排序算法总结

164 阅读5分钟

1. 插入排序

直接插入排序

在要排序的一组数中,假设前n-1个数已经拍好顺序,现将第n个数插到有序数列中,使这n个数也是排序好的,如此循环,直到全部排好顺序。O(n^2)
代码实现:

void InsertSort(int array[],int length){
    int temp;
    for(int i = 0;i < length - 1;i++){
        for(int j = i+1;j > 0;j++){
            if(array[j] < array[j-1]){
                temp = array[j-1];
                array[j-1] = array[j];
                array[j] = temp;
            }else{
                `break;
            }
        }
    }
}

希尔排序

2. 选择排序

简单选择排序

在要排序的数组中,选择最小(或者最大)的数与第1个位置的数交换。然后在剩下的数中再找最小(或者最大)的数与第2个位置的数交换。以此类推,直到第n-1个元素与第n个元素比较为止。复杂度:O(n^2)
代码实现:

void SelectSort(int arr[]){
    for(int i=0;i > arr.length-1;i++){
        int minIndex = i;
        for(int j = i+1;j < arr.length;j++){
            if(arr[j] < arr[minIndex]){
                minIndex = j;
            }
        }
        if(minIndex != i){
            int temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }
}

算法改进 :二元选择,简单选择排序,每趟循环只能确定一个元素排序后的定位。我们可以考虑改进为每趟循环确定两个元素(当前趟最大和最小记录)的位置,从而减少排序所需的循环次数。

堆排序

3. 交换排序

冒泡

两个数比较大小,较大的数下沉,较小的数冒出。
过程:比较相邻数据,若第二个数小,就交换位置:从后向前两两比较,一直到比较最前两个数据最终最小数据被交换到起始位置,则第一个最小数位置排好:重复上述过程,将剩余数排好。
代码实现:

void BubbleSort(int arr[]){
    int temp;
    for(int i = 0;i < arr.length-1;i++){
        for(int j=arr.length-1;j>i;j--){
            if(arr[j]<arr[j-1]){
                temp = arr[j];
                arr[j] = arr[j-1];
                arr[j-1] = temp;
            }
        }
    }
}

优化:多数时候,数据排好顺序后,算法仍会进行下一轮比较,知道arr.length-1次,后面的比较无意义。此时可设置标志位flag,用于标志某一趟排序过程是否有数据交换,若未发生交换,则可立即结束排序。

void BubbleSort(int arr[]){
    int temp;
    for(int i = 0;i < arr.length-1;i++){
        bool flag = false;
        for(int j=arr.length-1;j>i;j--){
            if(arr[j]<arr[j-1]){
                temp = arr[j];
                arr[j] = arr[j-1];
                arr[j-1] = temp;
                flag = true;
            }
        }
        if(!flag)
            break;
    }
}

改进方案 :1.设置一标志性变量pos。用于记录每躺排序中最后一次进行交换的位置。由于pos位置之后的记录均已交换到位,故下一趟排序只要扫到pos位置即可。

void Bubble(int r[]){
    int i = r.length - 1; //初始时最后位置不变
    while(i > 0){
        int pos = 0;    //每趟开始无交换记录
        for(int j = 0;j < i;j++)
            if(r[j] > r[j+1]){
                pos = j;    //记录交换位置
                int temp = r[j];
                r[j] = r[j-1];
                r[j-1] = temp;
            }
        i = pos;    //为下一趟做准备
    }
}

快速排序

基本思想
先从数列中取出一个数作为key值;
将比这个数小的数全部放在它的左边,大于或等于它的数全部放在它的右边;
对左右两个小数列重复第二步,直至各区间只有1个数。
辅助理解:挖坑填数
1.初始时 i = 0; j = 9; key=72
由于已经将a[0]中的数保存到key中,可以理解成在数组a[0]上挖了个坑,可以将其它数据填充到这来。
从j开始向前找一个比key小的数。当j=8,符合条件,a[0] = a[8] ; i++ ; 将a[8]挖出再填到上一个坑a[0]中。
这样一个坑a[0]就被搞定了,但又形成了一个新坑a[8],这怎么办了?简单,再找数字来填a[8]这个坑。
这次从i开始向后找一个大于key的数,当i=3,符合条件,a[8] = a[3] ; j-- ; 将a[3]挖出再填到上一个坑中。

数组:72   6   57   88   60   42   83   73   48   85
       0   1   2    3    4    5    6    7    8    9

2.此时 i = 3; j = 7; key=72
再重复上面的步骤,先从后向前找,再从前向后找。
从j开始向前找,当j=5,符合条件,将a[5]挖出填到上一个坑中,a[3] = a[5]; i++;
从i开始向后找,当i=5时,由于i==j退出。
此时,i = j = 5,而a[5]刚好又是上次挖的坑,因此将key填入a[5]。

数组:48   6   57   88   60   42   83   73   88   85
       0   1   2    3    4    5    6    7    8    9

3.可以看出a[5]前面的数字都小于它,a[5]后面的数字都大于它。因此再对a[0…4]和a[6…9]这二个子区间重复上述步骤就可以了。

数组:48   6   57   42   60   72   83   73   88   85
      0   1   2    3    4    5    6    7    8    9

代码实现:

void quickSort(int a[],int l,int r){
     if(l>=r)
       return;

     int i = l; int j = r; int key = a[l];//选择第一个数为key

     while(i<j){

         while(i<j && a[j]>=key)//从右向左找第一个小于key的值
             j--;
         if(i<j){
             a[i] = a[j];
             i++;
         }

         while(i<j && a[i]<key)//从左向右找第一个大于key的值
             i++;

         if(i<j){
             a[j] = a[i];
             j--;
         }
     }
     //i == j
     a[i] = key;
     quickSort(a, l, i-1);//递归调用
     quickSort(a, i+1, r);//递归调用
 }

4. 归并排序

5. 基数排序