3.1 经典排序的实现以及时空复杂度分析

常用几种排序及其时间复杂度

  • 冒泡排序:O(n^2),一趟最大的数在数组的最后
int* bubbleSort(int* A, int n) {
    // write code here
    int i,j;
    for(i=0;i<n-1;i++){
        for(j=0;j<n-i-1;j++){
            if(A[j]>A[j+1]){
               int temp=A[j];
                A[j]=A[j+1];
                A[j+1]=temp;
            }  
        }
    }
    return A;
}
  • 选择排序:O(n^2),选出最大的从前往后放置
int* selectionSort(int* A, int n) {
    int min;
    int i,j;
    for(i=0;i<n-1;i++){
        min=i;
        for(j=i;j<n;j++){
            if(A[j]<A[min])
                min=j;
        }
        int temp=A[i];
        A[i]=A[min];
        A[min]=temp;
    }
    return A;
}
  • 插入排序:O(n^2),当前位置的数与它前面的数进行比较
int* insertionSort(int* A, int n) {
    // write code here
    int i,j;
    for(i=1;i<n;i++){
        int temp=A[i];
        for(j=i-1;j>=0;j--){
            if(A[j]>temp)
                A[j+1]=A[j];
            else
                break;
        }
        A[j+1]=temp;
     }
    return A;
}
  • 归并排序:O(N*logN),相邻有序区间合并
class MergeSort {
public:
    int* mergeSort(int* A, int n) {
        // write code here
        merging(A,0,n-1);
        return A;
    }
    void merging(int* A,int start,int end){
        if(start<end){
            int middle=start+(end-start)/2;
            merging(A,start,middle);
            merging(A,middle+1,end);
            merge(A,start,middle,end);
        }else
            return;
    }
    void merge(int* A,int start,int middle,int end){
        int left=start;
        int right=middle+1;
        int* B=new int[end-start+1];
        int count=0;
        while(left<=middle&&right<=end){
            if(A[left]<A[right])
                B[count++]=A[left++];
            else
                B[count++]=A[right++];
        }
        while(left<=middle)
            B[count++]=A[left++];
        while(right<=end)
            B[count++]=A[right++];
        memcpy(A+start,B,sizeof(int)*(end-start+1));
        delete[] B;
    }
};
  • 快速排序:O(N*logN)
class QuickSort {
public:
    int* quickSort(int* A, int n) {
        // write code here
        quicksorting(A,0,n-1);
        return A;
    }
    void quicksorting(int* A,int start,int end){
        if(start<end){
        int pivot=partition(A,start,end);
        quicksorting(A,start,pivot-1);
        quicksorting(A,pivot+1,end);
        }else
            return ;
    }
   int partition(int* A,int start,int end){
        int low=start;
        int high=end;
        int p=A[start];
       while(low<high){
           while(A[high]>p&&low<high){
               high--;
           }
           if(low<high)
               A[low++]=A[high];
           while(A[low]<p&&low<high){
               low++;
           }
           if(low<high)
               A[high--]=A[low];
       }
       A[low]=p;
       return low;
   }
};
  • 堆排序:O(N*logN),大根堆,堆顶元素与最后一个元素交换,再调整为大根堆
class HeapSort {
public:
    int* heapSort(int* A, int n) {
        // write code here
        int i=(n-1-1)/2;
        for(;i>=0;i--){
            updown(A,i,n);
        }
        for(i=0;i<n-1;i++){
            int temp=A[0];
            A[0]=A[n-i-1];
            A[n-i-1]=temp;
            updown(A,0,n-i-1);
        }
        return A;
    }
    void updown(int* A,int start,int n){
        int max;
        while(start<n){
            max=2*start+1;
            if(max>=n)
                break;
            if(2*start+2<n&&A[2*start+2]>A[max])
                max=2*start+2;
            if(A[start]<A[max]){
                int temp=A[max];
                A[max]=A[start];
                A[start]=temp;
                start=max;
            }else
                break;
        }
    }
};
  • 希尔排序:O(N*logN),插入的改良,插入步长不为1,是可以调整的,如步长为3,2,1
class ShellSort {
public:
    int* shellSort(int* A, int n) {
        // write code here
        int shell=n/2;
        while(shell>=1){
        shellSort1(A,shell,n);
            shell=shell/2;
        }
        return A;
    }
    void shellSort1(int* A,int shell,int n){
        for(int i=0;i<n;i++){
            int j=i-shell;//shell为增量,直接插入排序的时候为1
            int temp=i;
            int current=A[i];
            while(j>=0){
                if(current<A[j]){
                    A[temp]=A[j];
                    j=j-shell;
                    temp=temp-shell; 
                }else{
                    break;
                }
            }
          A[temp]=current;
        }
        }
};

思想来自于桶排序的两种排序

  • 计数排序:O(n),例如员工按照身高排序,根据厘米数
class CountingSort {
public:
    int* countingSort(int* A, int n) {
        // write code here
         int max=A[0];
        for(int i=0;i<n;i++){
           if(A[i]>max)
               max=A[i];
        }
        int* B=new int[max+1];//实际上有max+1个数据,因为还有一个0
        int* C=new int[n];//C中存放的是排好序的数据
        //int B[max+1];
        for(int k=0;k<max+1;k++)
        {
            B[k]=0;
        }//代表max+1个桶
        int index;//代表第index个桶,第index个桶里面存放的是值为index的数据的个数
        for(int j=0;j<n;j++){
            index=A[j];
            B[index]=B[index]+1;
        }
        for(int m=1;m<max+1;m++){
            B[m]=B[m]+B[m-1];//这样B中的值代表m所处排好序的序列中的位置

        }
        //借助于另一个数组可以降低时间复杂度
        int pos,value;
        for(int p=n-1;p>=0;p--){
            value=A[p];
            pos=B[value]-1;
            C[pos]=value;
            B[value]--;
        }
       // for(int r=0;r<n;r++){
           // A[r]=C[r];
        //}
        memcpy(A,C,n*sizeof(int));
        delete C;
        delete B;
        return A;
    }
};
  • 基数排序:O(n),按照个位数大小进桶,然后依次十位数等进桶等
class RadixSort
{ //基数排序
public:
  int*
  radixSort (int* A, int n)
  {
    // write code here
    int** B = new int*[10];
    for (int w = 0; w < 10; w++)
      {
    B[w] = new int[n + 1];
    B[w][0] = 0;
      } //B相当于桶,一共10个桶,代表0-9个数字
    int value, index;
    bool flag = false;
    int count = 1;
    while (!flag )
      {
    flag = true;
    for (int i = 0; i < n; i++)
      {
        value = A[i] / count % 10; //value是数据个位上的数
        if (value != 0)
          flag = false;
        B[value][0]++;
        index = B[value][0];
        B[value][index] = A[i];
      }
    if (flag == 1)
      break;
     int y = 0;
    for (int m = 0; m <= 9; m++)
      {
        for (int ii = 1; ii <= B[m][0]; ii++)
          {
        A[y] = B[m][ii];
        y = y + 1;
          }
        B[m][0] = 0;  //记得每次都要B清零,只需要将每个桶的总数量清零就可以,不必将桶中所有的数据都清除
      }
    count = 10 * count;
      }
    for (int z = 0; z < 10; z++)
      {
    if (B[z] != NULL)
      {
        delete[] B[z];
      }
      }
    if (B != NULL)
      {
    delete[] B;
      }
    return A;
  }
};

空间复杂度分析

  • O(1):插入排序、选择排序、冒泡排序、堆排序、希尔排序

  • O(logN) ~ O(N):快速排序

  • O(N):归并排序

  • O(M):M为选择桶的数量,计数排序、基数排序

稳定性分析

  • 稳定的排序算法:冒泡排序、插入排序、归并排序、计数排序、基数排序、桶排序

  • 不稳定的排序算法:选择排序、快速排序、希尔排序、堆排序

results matching ""

    No results matching ""