专题-经典排序算法

            经典排序算法

1.       冒泡排序

依次比较相邻两元素大小。如果按升序排列,较大元素放后面;如果按降序排列较小元素放后面。

    

void BubbleSort(int *arr, int n){
  if(arr==NULL)
    return;
  for(int i=0; i<n-1; i++){
    for(j=0; j<n-1-i; j++){
      if(arr[j]>arr[j+1]){  //升序排列
        int temp=arr[j];
        arr[j]=arr[j+1];
        arr[j+1]=temp;
      }
    }
  }
return;
}

时间复杂度分析:

最佳情况:O(n)原始数组按序排列

最差情况:O(n^2)原始数组逆序排列

2.       选择排序

和冒泡排序思路几乎一样,唯一区别不是交换相邻两元素而是找出当前未排序序列的最小(大)元素,与当前未排序序列第一个元素交换。  

      

void SelectionSort(int *arr, int n){
  if(arr==NULL)
    return;
  for(int i=n-1; i>=0; i--){
       int maxIndex=i;
    for(j=i; j>=0; j--){
      if(arr[j]>arr[maxIndex])  //升序排列
           maxIndex=j;
    }
    int temp=arr[i];
    arr[i]=arr[maxIndex];
    arr[maxIndex]=temp;
  }
  return;
}

 

时间复杂度分析:

       O(n^2)

3.       插入排序

  第一个元素默认是排序的,以后每选择一个元素插入排序中。

           

void InsertSort(int *arr, int n){
    if(arr==NULL)
        return;
    for(int i=0; i<n; i++){
       int curVal=arr[i];
       int preIndex=i-1;
       while(preIndex>=0&&curVal<arr[preIndex]){
           arr[preIndex+1]=arr[preIndex];
           preIndex--;
        }
        arr[preIndex+1]=curVal;
    }
    return;
}  

 

时间复杂度分析:

最佳情况:O(n)原始数组有序排列

最坏情况:O(n^2)原始数组逆序排列

4.       希尔排序(递减增量排序算法)

希尔排序是对插入排序的改进。插入排序对几乎已经拍好序的数据操作时,效率高,即可达到线性排序的效率;希尔排序是将待排序序列分割成若干子序列分别进行直接插入排序,待整个序列基本有序时,再对整体进行直接插入排序。

        

void ShellSort(int *arr, int n){
    if(arr==NULL)
        return;
    int gap=n;  //间隔
    while(true){  //每一步都是一个插入排序
       gap=gap/2;
       for(int i=0; i<gap; i++){
           for(int j=i+gap; j<n; j++){
               int temp=arr[j];
               int m;
               for(m=i-gap; m>=0 && arr[m]>temp; m=m-gap){
                   arr[m+gap]=arr[m];
               }
               arr[m+gap]=temp;
           }
    }
    if(gap==1)
       break;
    }
    return;
}                                    

时间复杂度分析:

       O(nlogn)

5.       快速排序

随机选择数组中的一个数,比选择的数字小的数字移到数组左边,比选择数字大的移到数组右边。

          

void swap(int *a, int* b){  //交换两个数字
       int temp;
       temp=*a;
       *a=*b;
       *b=temp;
       return;
}

void QuickSort(int data[], int start, int end){
       if(start>=end)
              return;
       int temp;
       //待排序的第最后一个元素作为基准元素
       int small=start-1;
       for(int index=start; index<end; index++){
           if(data[index]<data[end]){
               small++;
           if(small!=index)
              swap(data[small], data[index]);
        }
    }
    small++;
    swap(data[small], data[end]);
    QuickSort(data[], start, small-1);
    QuickSort(data[],small+1, end);
    return;
}    

时间复杂度分析:

最佳情况:O(nlogn)每次正好中分

最差情况:分为1个元素和其它元素两部分

6.       归并排序

包括分解和合并两部分

合并相邻有序子序列

(此图转载自博客:https://www.cnblogs.com/linjiaxin/p/7615196.html

void MergeSortCore(int *data, int* copy, int start, int end){
    if(start==end){
        copy[start]=data[start];
        return;
    }
    int length=(start+end)/2;
    MergeSortCore(copy, data, start, start+length);  //分解
    MergeSortCore(copy, data, start+length+1, end);
    int i=start+length;
    int j=end;
    int indexCopy=end;
    while(i>=start&& j>=start+length+1){  //合并
       if(data[i]>data[j])
              copy[indexCopy--]=data[i--];
       else
              copy[indexCopy--]=data[j--];
    }
    for(; i>=start; --i)
       copy[indexCopy--]=data[i];
    for(; j>=start; --j)
       copy[indexCopy--]=data[j];
    return;
}

void MergeSort(int *data, int length){
    if(data==NULL|| length<0)
        return;
    int* copy=new int[length];
    for(int i=0; i<length; i++)
        copy[i]=data[i];
    MergeSortCore(data, copy, 0, length-1);
    delete[] copy;
    return;
}

时间复杂度分析:

       O(nlogn)

7.       堆排序:

堆排序,就是以堆的方式去排序,什么是堆呢?满足对任意一个父节点不大(小)于其子节点的完全二叉树。大根堆用于升序排列,小根堆用于将序排列。

步骤:

       将原始数组构建成大(小)根堆;

将堆顶元素和最后一个元素进行交换,得到新的无序数组区域和新的有序数组区域;

重新调整无序数组区域为大(小)根堆,将堆顶元素和最后一个元素进行交换,直到排列完

       (对原理讲解的很不错的博客:https://blog.csdn.net/u013384984/article/details/79496052

void swap(int &a, int &b){
    int temp=a;
    a=b;
    b=temp;
}

void AdjustHeap(int arr[], int nodeIndex, int n){
    int leftChild=2*nodeIndex+1;
    int rightChild=2*nodeIndex+2;
    int maxIndex=nodeIndex;
    if(leftChild<n && arr[maxIndex]<arr[leftChild])
        maxIndex=leftChild;
    if(rightChild<n && arr[maxIndex]<arr[rightChild])
        maxIndex=rightChild;
    if(maxIndex!=nodeIndex){
        swap(arr[maxIndex], arr[nodeIndex]);
        adjustHeap(arr, maxIndex, n);
    }
}

//大根堆,升序排列
void HeapSort(int arr[], int n){
    if(n==1)  //直到无序区的元素个数为1
        return;
    //最后一个非叶子节点编号为n/2-1,从0开始计数
    for(int i=n/2-1; i>=0; i--)
        AdjustHeap(arr, i, n);  //调整为大根堆
    swap(arr[0], nums[n-1]);  //将堆顶与最后一个元素交换
    HeapSort(arr, n-1);  //排序数组减一
}                    

时间复杂度分析:

       O(nlogn)

8.       桶排序(基数排序)

找出最大的数

将所有待比较的数统一为同样的位数长度,较短前面补0

从最低位开始,依次进行一次排序

int maxBit(int data[], int n){
    int maxData=data[0];
    for(int i=1; i<n; i++){
        if(maxData<data[i])
            maxData=data[i];
    }
    int maxn=0;
    while(maxData!=0){
        maxData/=10;
        maxn++;
    }
    return maxn;
}

void BucketSort(int data[], int n){
    int maxn=maxBit(data, n);  //最大位数
    int temp=new int[n];  //临时存储
    int *count=new int[10];  //10个桶0-9
    int i,j,k;
    int radix=1;
    for(i=1; i<=maxn; i++){  //进行maxn次排序
        for(j=0; j<10; j++)//每次排序前初始化为0
            count[j]=0;
        for(j=0; j<n; j++){  //桶统计
            k=(data[j]/radix)%10;
            count[k]++;
        }
        for(j=1; j<10; j++)
            count[i]+=count[i-1];  //将temp中的位置依次分配给各个桶
        for(j=n-1; j>=0; j--){  //先占据后面的位置所以从后往前放。
            k=(data[j]/radix)%10;
            temp[count[k]-1]=data[j];  //放入到分配的桶
            count[k]--;  //依次前移放入
        }
        for(j=0; j<n; j++)  //一次排序结果
            data[j]=temp[j];
        radix=radix*10;  //调整桶基数
    }
    delete []temp;
    delete []count;
}   

时间复杂度分析

O(p(n+b)),其中n是待排元素个数,b是桶个数,p是排序的次数

posted @ 2019-07-24 16:37  行走的算法  阅读(218)  评论(0编辑  收藏  举报