常用排序算法实现

本文深入探讨了排序算法的基础概念,包括插入排序、shell排序、冒泡排序、快速排序、选择排序、堆排序、归并排序等,并提供了C++代码实现。文章详细解释了每种算法的时间复杂度和工作原理,旨在帮助读者理解和掌握这些基本的排序技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.插入排序

   插入排序是最简单最直观的排序算法了,它的依据是:遍历到第N个元素的时候前面的N-1个元素已经是排序好的了,那么就查找前面的N-1个元素把这第N个元素放在合适的位置,如此下去直到遍历完序列的元素为止。
   算法的复杂度也是简单的,排序第一个需要1的复杂度,排序第二个需要2的复杂度,因此整个的复杂度就是
 1 + 2 + 3 + …… + N = O(N ^ 2)的复杂度。

  1. /* 
  2. *插入排序 
  3. */  
  4. void InsertSort(int *arr,int n)  
  5. {  
  6.     int j=0,temp;  
  7.     for(int i=1;i<n;i++)  
  8.     {  
  9.         int j=i;  
  10.         temp=arr[i];  
  11.         while(j>0)  
  12.         {  
  13.             if(temp<arr[j-1])//arr[i]<arr[i-1],则需将arr[i-1]右移一个位置  
  14.             {  
  15.                 arr[j]=arr[j-1];  
  16.                 j--;  
  17.             }else  
  18.                 break;  
  19.         }  
  20.         arr[j]=temp;//将数放于合适位置  
  21.         print(arr,n);  
  22.     }  
  23. }  

2、shell排序

  shell排序是对插入排序的一个改装,它每次排序把序列的元素按照某个增量分成几个子序列,对这几个子序列进行插入排序,然后不断缩小增量扩大每个子序列的元素数量,直到增量为一的时候子序列就和原先的待排列序列一样了,此时只需要做少量的比较和移动就可以完成对序列的排序了。

  1. /* 
  2. *shell排序 
  3. */  
  4. void ShellSort(int *arr,int n)  
  5. {  
  6.     int incre=n/3+1;  
  7.     bool tag=true;  
  8.     do  
  9.     {  
  10.         if(incre==1)  
  11.             tag=false;  
  12.         ShellSortWithIncre(arr,n,incre);  
  13.         incre=incre/3+1;  
  14.     }while(incre>=1&&tag);  
  15. }  
  16. /* 
  17. 根据增量,使用插入排序调整顺序 
  18. */  
  19. void ShellSortWithIncre(int *arr,int n,int incre)  
  20. {  
  21.     for(int i=incre;i<n;i++)  
  22.     {  
  23.         int j=i;  
  24.         int temp=arr[i];  
  25.         while(j-incre>=0)  
  26.         {  
  27.             if(temp<arr[j-incre])  
  28.             {  
  29.                 arr[j]=arr[j-incre];  
  30.                 j-=incre;  
  31.             }else  
  32.                 break;  
  33.         }  
  34.         arr[j]=temp;  
  35.     }  
  36. }  

3、冒泡排序

   冒泡排序算法的思想:很简单,每次遍历完序列都把最大(小)的元素放在最前面,然后再对剩下的序列从父前面的一个过程,每次遍历完之后待排序序列就少一个元素,当待排序序列减小为只有一个元素的时候排序就结束了。因此,复杂度在最坏的情况下是O(N ^ 2)

  1. /* 
  2. *冒泡排序 
  3. */  
  4. void BubbleSort(int *arr,int n)  
  5. {  
  6.     bool exchanged=true;  
  7.     for(int i=0;i<n;i++)  
  8.     {  
  9.         exchanged=false;  
  10.         for(int j=0;j<n-i-1;j++)  
  11.         {  
  12.             if(arr[j]>arr[j+1])  
  13.             {  
  14.                 std::swap(arr[j],arr[j+1]);  
  15.                 exchanged=true;  
  16.             }  
  17.         }  
  18.         if(!exchanged)  
  19.             return;  
  20.     }  
  21. }  

4、快速排序

快速排序的算法思想: 选定一个枢纽元素,对待排序序列进行分割,分割之后的序列一个部分小于枢纽元素,一个部分大于枢纽元素,再对这两个分割好的子序列进行上述的过程。

  1. /* 
  2. 快速排序 
  3. */  
  4. void QuickSort(int *arr,int start,int end)  
  5. {  
  6.     int low=start,high=end-1;  
  7.     int pivot;  
  8.     if(low<high)  
  9.     {  
  10.         pivot=Partition(arr,low,high);  
  11.         //print(arr,end-start+1);  
  12.         QuickSort(arr,low,pivot);  
  13.         QuickSort(arr,pivot+1,end);  
  14.     }  
  15. }  
  16. /* 
  17. 根据pivot将数组分为两部分,左边小于pivot,右边大于pivot 
  18. */  
  19. int Partition(int *arr,int start,int end)  
  20. {  
  21.     int pivot=getMediumNum(arr,start,end);  
  22.     std::swap(arr[start],arr[pivot]);  
  23.     int pivotNum=arr[start];  
  24.     //std::cout<<"pivot is "<<pivotNum<<std::endl;  
  25.     while(start<end)  
  26.     {  
  27.         while(start<end&&pivotNum<arr[end])  
  28.             --end;  
  29.         if(start<end)  
  30.             arr[start++]=arr[end];  
  31.         while(start<end&&arr[start]<=pivotNum)  
  32.             ++start;  
  33.         if(start<end)  
  34.             arr[end--]=arr[start];  
  35.     }  
  36.     arr[start]=pivotNum;  
  37.     return start;  
  38. }  
  39. /* 
  40. 取头,中,尾三数的中值 
  41. */  
  42. int getMediumNum(int *arr,int start,int end)  
  43. {  
  44.     int medium=(start+end)/2;  
  45.     if(arr[start]<arr[medium])  
  46.     {  
  47.         if(arr[medium]<arr[end])  
  48.             return medium;  
  49.         else  
  50.             if(arr[start]>arr[end])  
  51.                 return start;  
  52.             else  
  53.                 return end;  
  54.     }else  
  55.     {  
  56.         if(arr[medium]>arr[end])  
  57.             return medium;  
  58.         else  
  59.             if(arr[start]>arr[end])  
  60.                 return end;  
  61.             else  
  62.                 return start;  
  63.     }  
  64. }  

另一个分割方法:

  1. int Partition(int *arr,int start,int end)  
  2. {  
  3.     int x = arr[end];  
  4.     int i = start - 1;  
  5.     for(int j=start;j<end;j++)  
  6.     {  
  7.         if(arr[j]<=x)  
  8.         {  
  9.             ++i;  
  10.             swap(arr[i],arr[j]);  
  11.         }  
  12.     }  
  13.     swap(arr[i+1],arr[end]);  
  14.     return i+1;  
  15. }  

5、选择排序

  每次选择最小的数,放入该数对应的位置。

  1. /* 
  2. 选择排序 
  3. */  
  4. void SelectSort(int *arr,int n)  
  5. {  
  6.     for(int i=0;i<n;i++)  
  7.     {  
  8.         int min=i;  
  9.         for(int j=i;j<n;j++)  
  10.         {  
  11.             if(arr[j]<arr[min])  
  12.                 min=j;  
  13.         }  
  14.         if(min!=i)  
  15.             std::swap(arr[i],arr[min]);  
  16.     }  
  17. }  

6、堆排序

堆的定义:
  n个关键字序列Kl,K2,…,Kn称为堆,当且仅当该序列满足如下性质(简称为堆性质):
  (1) ki≤K2i且ki≤K2i+1 或(2)Ki≥K2i且ki≥K2i+1(1≤i≤)
  若将此序列所存储的向量R[1……n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。
  堆的这个性质使得可以迅速定位在一个序列之中的最小(大)的元素。
  堆排序算法的过程如下:1)得到当前序列的最小(大)的元素
  (2)把这个元素和最后一个元素进行交换,这样当前的最小(大)的元素就放在了序列的最后,而原先的最后一个元素放到了序列的最前面
  (3)的交换可能会破坏堆序列的性质(注意此时的序列是除去已经放在最后面的元素),因此需要对序列进行调整,使之满足于上面堆的性质。重复上面的过程,直到序列调整完毕为止。

  1. /* 
  2. *堆排序 
  3. */  
  4. void HeapSort(int *arr,int n)  
  5. {  
  6.     BuildMaxHeap(arr,n);  
  7.     //std::cout<<"构建的大顶堆为:";  
  8.     //print(arr,n);  
  9.     for(int i=n-1;i>0;i--)  
  10.     {  
  11.         std::swap(arr[i],arr[0]);  
  12.         HeapAdjust(arr,0,i);  
  13.     }  
  14. }  
  15. /* 
  16. 构建大顶堆 
  17. */  
  18. void BuildMaxHeap(int *arr,int n)  
  19. {  
  20.     for(int i=n/2-1;i>=0;i--)  
  21.     {  
  22.         HeapAdjust(arr,i,n);  
  23.     }  
  24. }  
  25. /* 
  26. *调整大顶堆 
  27. */  
  28. void HeapAdjust(int *arr,int start,int n)  
  29. {  
  30.     int rightChild=(start+1)*2;  
  31.     while(rightChild<n)//左右节点都存在  
  32.     {  
  33.         if(arr[rightChild]<arr[rightChild-1])  
  34.             --rightChild;  
  35.         if(arr[start]<arr[rightChild])  
  36.         {  
  37.             std::swap(arr[start],arr[rightChild]);  
  38.             start=rightChild;  
  39.             rightChild=(start+1)*2;  
  40.         }else  
  41.             break;  
  42.     }  
  43.     if(rightChild==n)//只有左节点,没有右节点  
  44.     {  
  45.         if(arr[start]<arr[rightChild-1])  
  46.             std::swap(arr[start],arr[rightChild-1]);  
  47.     }  
  48. }  

7、归并排序

归并排序的算法思想:把待排序序列分成相同大小的两个部分,依次对这两部分进行归并排序,完毕之后再按照顺序进行合并

  1. /* 
  2. 自底向上归并排序 
  3. */  
  4. void MergeSort(int *arr,int n)  
  5. {  
  6.     for(int i=1;i<n;i*=2)  
  7.     {  
  8.         MergePass(arr,i,n);  
  9.         std::cout<<i<<"路归并后的结果:"<<std::endl;  
  10.         print(arr,n);  
  11.     }  
  12. }  
  13.   
  14. /* 
  15. 功能:将两个有序数组归并到一起 
  16. */  
  17. void Merge(int *arr,int start,int mid,int end)  
  18. {  
  19.     int length=end-start;  
  20.     int i=start,j=mid,p=0;  
  21.     int *arr2=new int[length];  
  22.     while(i<mid&&j<end)  
  23.     {  
  24.         if(arr[i]<arr[j])  
  25.         {  
  26.             arr2[p++]=arr[i];  
  27.             ++i;  
  28.         }else  
  29.         {  
  30.             arr2[p++]=arr[j];  
  31.             ++j;  
  32.         }  
  33.     }  
  34.     while(i<mid)  
  35.         arr2[p++]=arr[i++];  
  36.     while(j<end)  
  37.         arr2[p++]=arr[j++];  
  38.     p=0;  
  39.     for(i=start;i<end;i++,p++)  
  40.     {  
  41.         arr[i]=arr2[p];  
  42.     }  
  43.     delete[] arr2;  
  44. }  
  45. /* 
  46. 根据间隔,进行归并 
  47. */  
  48. void MergePass(int *arr,int interval,int n)  
  49. {  
  50.     int i=0;  
  51.     for(;i+2*interval<n;i+=2*interval)  
  52.     {  
  53.         Merge(arr,i,i+interval,i+2*interval);  
  54.     }  
  55.     if(i+interval<n)  
  56.         Merge(arr,i,i+interval,n);  
  57. }  
  58. /* 
  59. 自顶向下二路归并算法 
  60. */  
  61. void MergeSortDC(int *arr,int start,int end)  
  62. {  
  63.     int low=start,high=end;  
  64.     int mid;  
  65.     if(low<high-1)  
  66.     {  
  67.         mid=(low+high)/2;  
  68.         MergeSortDC(arr,start,mid);  
  69.         MergeSortDC(arr,mid,end);  
  70.         Merge(arr,start,mid,end);  
  71.     }  
  72.   
  73. }  

8、基数排序

  1. //基数排序  
  2. void RadixSort(int *arr,int n)  
  3. {  
  4.     bool isContinue=true;  
  5.     vector<int> ivec[10];  
  6.     int remainder=0,baseNum=1,p=0;  
  7.     while(isContinue)  
  8.     {  
  9.         isContinue=false;  
  10.         for(int i=0;i<n;i++)  
  11.         {  
  12.             remainder=(arr[i]/baseNum)%10;  
  13.             if(remainder)  
  14.                 isContinue=true;  
  15.             ivec[remainder].push_back(arr[i]);  
  16.         }  
  17.         p=0;  
  18.         for(int i=0;i<10;i++)  
  19.         {  
  20.             int size=ivec[i].size();  
  21.             for(int j=0;j<size;j++)  
  22.             {  
  23.                 arr[p++]=ivec[i][j];  
  24.             }  
  25.             ivec[i].clear();  
  26.         }  
  27.         baseNum*=10;  
  28.     }  
  29. }  http://blog.youkuaiyun.com/lanyan822/article/details/7864123

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值