算法之選擇排序法

選擇排序法(Selection Sort)

一,概念

自行總結:從越來越小的選擇區間中選擇一個最小(大)的值,和選擇區間最前面的值交換位置,直到排序完成

二,圖示

在這裏插入圖片描述

三,C++實現

main.cpp

#include <iostream>

using namespace std;

void selectionSort(int arr[], int n){
    // 一層循環,縮小尋找最小值的區間範圍
    for(int i = 0; i < n; i ++){
        // 二層循環,尋找[i, n)區間裏的最小值的index
        int minIndex = i;
        for( int j = i + 1; j < n; j ++ ){
            if( arr[j] < arr[minIndex])
                minIndex = j;
        }
        // 二層循環完畢,區間最小值和區間第一交換位置,放到區間最前面
        // swap函數,進行交換
        swap(arr[i], arr[minIndex]);
    }
}

int main() {

    int a[10] = {10,9,8,7,6,5,4,3,2,1};
    selectionSort(a, 10);
    for ( int i = 0; i < 10; i ++ )
        cout<<a[i]<<" ";
    cout<<endl;

    return 0;
}

注:對於c++實現,整數,浮點和字符串數組可通過寫泛型參數實現,而集合數組則需要寫類實現(以後再研究代碼吧)

四,js實現

function selectionSort(arr, n){
    // 一層循環,縮小尋找最小值的區間範圍
	for(let i = 0; i < n; i++){
	    // 二層循環,尋找[i, n)區間裏的最小值的index
	    let minIndex = i;
	    for(let j = i+1; j < n; j++){
	        if(arr[j]<arr[minIndex]){
	        	minIndex = j;
	        }
	    }
	    // 二層循環完畢,區間最小值和區間第一交換位置,放到區間最前面
	    // es6解構賦值,進行交換
	    [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
	}
	return arr;
}
selectionSort([10,9,8,7,6,5,4,3,2,1],10);

selectionSort([10,9,8,7,6,5,4,3,2,1],10);
(10) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
selectionSort([5.5,4.5,3.5,2.5,1.1],5);
(5) [1.1, 2.5, 3.5, 4.5, 5.5]
selectionSort([‘d’,‘a’,‘f’,‘c’,‘b’],5);
(5) [“a”, “b”, “c”, “d”, “f”]

注:對於js實現,整數,浮點和字符串數組都可通用,而集合數組則取具體屬性比較便可用

五,C++實現(擴展)

1,浮點和字符串數組

浮點和字符串數組可通過寫泛型參數實現

#include <iostream>
#include <string>
using namespace std;
// 定義泛型
template<typename T>
void selectionSort(T arr[], int n){

    for(int i = 0 ; i < n ; i ++){

        int minIndex = i;
        for( int j = i + 1 ; j < n ; j ++ )
            if( arr[j] < arr[minIndex] )
                minIndex = j;

        swap( arr[i] , arr[minIndex] );
    }
}
int main() {
//    整型數組
//    int a[10] = {10,9,8,7,6,5,4,3,2,1};
//  浮點型數組
//    float a[10] = {10.1,9.9,8.8,7.8,6.6,5.5,4.4,3.3,2.2,1.1};
//  字符串數組
    string a[10] = {"a","c","f","e","g","h","i","b","l","p"};
    selectionSort(a, 10);
    for ( int i = 0; i < 10; i ++ )
        cout<<a[i]<<" ";
    cout<<endl;

    return 0;
}

2,集合數組

添加集合的類,對操作符(小於號)進行重載(也就是重新定義),去設置比較集合中的屬性值

Student.h


#ifndef UNTITLED_STUDENT_H
#define UNTITLED_STUDENT_H

#include <iostream>
#include <string>

using namespace std;


struct Student{

    string name;
    int score;

    // 小於號運算符的重載
    bool operator<(const Student &otherStudent){
        return score < otherStudent.score;
    }

    friend ostream& operator<<(ostream &os, const Student &student){

        os<<"Student: "<<student.name<<" "<<student.score<<endl;
        return os;
    }
};

#endif //UNTITLED_STUDENT_H

main.cpp

#include <iostream>
#include <string>
#include "Student.h"

using namespace std;
// 定義泛型
template<typename T>
void selectionSort(T arr[], int n){

    for(int i = 0 ; i < n ; i ++){

        int minIndex = i;
        for( int j = i + 1 ; j < n ; j ++ )
            if( arr[j] < arr[minIndex] )
                minIndex = j;

        swap( arr[i] , arr[minIndex] );
    }
}
int main() {
    Student a[4] = {{"D", 98}, {"C", 100}, {"B", 95}, {"A", 95}};
    selectionSort(a, 4);
    for ( int i = 0; i < 4; i ++ )
        cout<<a[i]<<" ";
    cout<<endl;

    return 0;
}

3,集合數組(多層比較)

如果分數相同的情況下,再比較名字的大小,則對小於號的重載變爲三目運算符

Student.h


#ifndef UNTITLED_STUDENT_H
#define UNTITLED_STUDENT_H

#include <iostream>
#include <string>

using namespace std;


struct Student{

    string name;
    int score;

    // 小於號運算符的重載
    // 分數不等,小於號比的是分數
    // 分數相等,小於號比名字
    // 注意:這裏的排序順序(升序或降序)完全可以自定義了
    bool operator<(const Student &otherStudent){
        return score != otherStudent.score ?
               score < otherStudent.score : name < otherStudent.name;
//        return score < otherStudent.score;
    }

    friend ostream& operator<<(ostream &os, const Student &student){

        os<<"Student: "<<student.name<<" "<<student.score<<endl;
        return os;
    }
};

#endif //UNTITLED_STUDENT_H

4,統計排序時間

創建統計時間所必要的工具參數

  • 打印
  • 生成隨機數數組
  • 驗證是否排序
  • 計算排序時間

SortTestHelper.h


#ifndef INC_03_SELECTION_SORT_DETECT_PERFORMANCE_SORTTESTHELPER_H
#define INC_03_SELECTION_SORT_DETECT_PERFORMANCE_SORTTESTHELPER_H

#include <iostream>
#include <ctime>
#include <cassert>
#include <string>

using namespace std;


namespace SortTestHelper {

    // 生成有n個元素的隨機數組,每個元素的隨機範圍爲[rangeL, rangeR]
    int *generateRandomArray(int n, int rangeL, int rangeR) {

        assert(rangeL <= rangeR);

        int *arr = new int[n];

        srand(time(NULL));
        for (int i = 0; i < n; i++)
            arr[i] = rand() % (rangeR - rangeL + 1) + rangeL;
        return arr;
    }
    // 打印數組
    template<typename T>
    void printArray(T arr[], int n) {

        for (int i = 0; i < n; i++)
            cout << arr[i] << " ";
        cout << endl;

        return;
    }
    // 判斷是否打印成功
    template<typename T>
    bool isSorted(T arr[], int n) {

        for (int i = 0; i < n - 1; i++)
            if (arr[i] > arr[i + 1])
                return false;

        return true;
    }
    // 計算排序時間
    template<typename T>
    void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) {

        clock_t startTime = clock();
        sort(arr, n);
        clock_t endTime = clock();

        assert(isSorted(arr, n));
        cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl;

        return;
    }

};
#endif //INC_03_SELECTION_SORT_DETECT_PERFORMANCE_SORTTESTHELPER_H

main.cpp

#include <iostream>
#include "SortTestHelper.h"

using namespace std;

template<typename T>
void selectionSort(T arr[], int n){

    for(int i = 0 ; i < n ; i ++){

        int minIndex = i;
        for( int j = i + 1 ; j < n ; j ++ )
            if( arr[j] < arr[minIndex] )
                minIndex = j;

        swap( arr[i] , arr[minIndex] );
    }
}

int main() {
    //  從測試可以看出數據變大十倍,執行時間變大百倍,時間複雜度度n方
    //  Selection Sort : 0.130219 s
    //  int n = 10000;
    //  Selection Sort : 11.44 s
    int n = 100000;
    int *arr = SortTestHelper::generateRandomArray(n,0,n);
    SortTestHelper::testSort("Selection Sort", selectionSort, arr, n);
    delete[] arr;

    return 0;
}

注意:數組數量級增加10倍,排序時間增加100倍,時間複雜度n方

六,js實現(擴展)

1,集合數組(多層比較)

如果分數相同的情況下,再比較名字的大小,則比較判斷的地方也變爲三目運算符

function selectionSort(arr, n){
	for(let i = 0; i < n; i++){
	    let minIndex = i;
	    for(let j = i+1; j < n; j++){
	        if(arr[j].age != arr[minIndex].age ?
               arr[j].age < arr[minIndex].age : 
               arr[j].name < arr[minIndex].name){
	        	minIndex = j;
	        }
	    }
	    [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
	}
	return arr;
}

selectionSort([{name:'b',age:2},{name:'a',age:1},{name:'e',age:3},{name:'c',age:3}],4);

2,統計排序時間

// 生成隨機數組
function getRandom(n){
    let arr = [];
    for (let i = 0; i < n; i++){
    	arr[i] = Math.floor(Math.random() * n);
    }
    return arr;
}
// 選擇排序
function selectionSort(arr, n){
    // 一層循環,縮小尋找最小值的區間範圍
	for(let i = 0; i < n; i++){
	    // 二層循環,尋找[i, n)區間裏的最小值的index
	    let minIndex = i;
	    for(let j = i+1; j < n; j++){
	        if(arr[j]<arr[minIndex]){
	        	minIndex = j;
	        }
	    }
	    // 二層循環完畢,區間最小值和區間第一交換位置,放到區間最前面
	    // es6解構賦值,進行交換
	    [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
	}
	return arr;
}
// 統計排序執行時間
console.time("sort");
selectionSort(getRandom(10000),10000);
console.timeEnd("sort");

發佈了134 篇原創文章 · 獲贊 165 · 訪問量 139萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章