【排序二】选择排序(选择排序&&堆排序)

本文详细介绍了选择排序和堆排序的原理与实现方法,包括排序的基本思想、时间复杂度、空间复杂度及代码实现等内容。

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

【排序一】插入排序



一、选择排序

1、基本思想

    顾名思义,选择排序就是每次选一个数据放到其应该出现的位置,以升序(降序)为例,首先选最小(最大)的数据放到正确位置,接着再选次小(次大)的数据放到合适的位置,以此类推,直到最大(最小)的数据被放入最后一个位置,排序就算完成。

总体算法分三步完成:选数据--->将所选数据放入合适位置--->缩小需要排序的范围

图解(以升序为例):



2、排序效果图:



3、时间复杂度&&空间复杂度

选择排序的比较次数O(n^2),比较次数与关键字的初始状态无关,总的比较次数:

N=(n-1)+(n-2)+...+1=n*(n-1)/2。 

交换次数O(n),最好情况是,已经有序,交换0次;最坏情况是,逆序,交换n-1次。

故此,选择排序的时间复杂度为O(N^2)

选择排序的空间复杂度为O(1)


4、实现代码

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #pragma once  
  2. #include <iostream>  
  3. #include <assert.h>  
  4. using namespace std;  
  5.   
  6. //选择排序:选一个数(最大或最小)-->将此数放在正确的位置上-->缩小范围  
  7. void PrintArray(const int* a,const size_t n)  
  8. {  
  9.     for (size_t i = 0; i < n; ++i)  
  10.     {  
  11.         cout<<a[i]<<" ";  
  12.     }  
  13.     cout<<endl;  
  14. }  
  15.   
  16. //C语言风格的选择排序  
  17. void SelectSort1(int* a,size_t n)  
  18. {  
  19.     assert(a);  
  20.     for (size_t i = 1; i < n; ++i)  
  21.     {  
  22.         int minIndex = i;//未排序区间最小数据的位置下标  
  23.         int start = i - 1;//未排序区间的第一个数据下标  
  24.   
  25.         //选出第二部分最小的数据  
  26.         for (size_t j = i+1; j < n-1; ++j)//用j = i+1来缩小未排序区间范围  
  27.         {  
  28.             if (a[j+1]<a[minIndex])  
  29.             {  
  30.                 swap(a[j+1],a[minIndex]);  
  31.             }  
  32.         }  
  33.         //第二部分最小的数据和第二部分第一个数据进行比较  
  34.         if (a[minIndex] < a[start])  
  35.         {  
  36.             swap(a[start],a[minIndex]);  
  37.         }  
  38.     }  
  39. }  
  40.   
  41. //C++风格的选择排序  
  42. void SelectSort2(int* a,size_t n)  
  43. {  
  44.     assert(a);  
  45.     int minIndex = 0;  
  46.     for (size_t i = 0; i < n - 1; ++i)  
  47.     {  
  48.         minIndex = i;      //未排序区间最小数据的位置下标  
  49.         size_t pos = i + 1;//未排序区间的第一个数据下标  
  50.   
  51.         while(pos < n)//选出未排序区间最小的数据  
  52.         {  
  53.             if (a[pos] < a[minIndex])  
  54.             {  
  55.                 minIndex = pos;  
  56.             }  
  57.             ++pos;  
  58.         }  
  59.         swap(a[i],a[minIndex]);//将所选数据放到正确位置  
  60.     }  
  61. }  
  62.   
  63. //选择排序的优化:每次既选出最大的数,也选出最小的数  
  64. void SelectSort3(int* a,size_t n)  
  65. {  
  66.     assert(a);  
  67.     int left = 0;//未排序区间的左下标  
  68.     int right = n - 1;//未排序区间的右下标  
  69.   
  70.     while (left < right)  
  71.     {  
  72.         int minIndex = left;//未排序区间最小数据的位置下标  
  73.         int maxIndex = right;//未排序区间最大数据的位置下标  
  74.   
  75.         //选出最大和最小数据的下标  
  76.         for (int i = left; i <= right; ++i)  
  77.         {  
  78.             if (a[i] < a[minIndex])  
  79.             {  
  80.                 minIndex = i;  
  81.             }  
  82.             if (a[i] > a[maxIndex])  
  83.             {  
  84.                 maxIndex = i;  
  85.             }  
  86.         }  
  87.         //修正:最大值在最小位置或最小值在最大位置  
  88.         swap(a[maxIndex],a[right]);//将最大数据放到区间最右侧  
  89.         if (minIndex == right)  
  90.         {  
  91.             minIndex = maxIndex;  
  92.         }  
  93.         swap(a[minIndex],a[left]);//将最小数据放在区间最左侧  
  94.   
  95.         left++;//缩小区间范围  
  96.         right--;//缩小区间范围  
  97.     }  
  98. }  
  99.   
  100. void TestSelectSort()  
  101. {  
  102.     int a[] = {9,5,4,2,3,6,8,7,1,0};  
  103.     size_t sz = sizeof(a)/sizeof(a[0]);  
  104.   
  105.     //SelectSort1(a,sz);  
  106.     //SelectSort2(a,sz);  
  107.     SelectSort3(a,sz);  
  108.     PrintArray(a,sz);  
  109. }  

运行结果:



二、堆排序

1、堆介绍

数据结构是一种数组对象,它可以被视为一棵完全二叉树结构

堆结构的二叉树存储是:
(最)大堆:每个父节点的都大于孩子节点
(最)小堆:每个父节点的都小于孩子节点

如图所示:



2、堆排序的基本思想

      堆积排序(Heapsort)是指利用这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

1)将初始待排序关键字序列(R1,R2....Rn) 构建 大顶堆 ,此堆为初始的无序区;
2) 将堆顶元素R[1]与最后一个元素R[n]交换 ,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n]; 
3)由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1) 调整 新堆 ,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

图解(假设为升序):



3、堆排序效果图



4、时间复杂度&&空间复杂度

   假设一棵完全二叉树有N个节点,则它的的高度为lgN,堆排序中的比较次数为2*lgN,交换次数为N次,

堆排序的时间复杂度为O(N*lgN)

由于占用了有限个空间,所以堆排序的空间复杂度为O(1)


5、代码实现

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #pragma once  
  2. #include <iostream>  
  3. #include <assert.h>  
  4. using namespace std;  
  5.   
  6. //选择排序:选一个数(最大或最小)-->将此数放在正确的位置上-->缩小范围  
  7. void PrintArray(const int* a,const size_t n)  
  8. {  
  9.     for (size_t i = 0; i < n; ++i)  
  10.     {  
  11.         cout<<a[i]<<" ";  
  12.     }  
  13.     cout<<endl;  
  14. }  
  15. void TestSelectSort()  
  16. {  
  17.     int a[] = {9,5,4,2,3,6,8,7,1,0};  
  18.     size_t sz = sizeof(a)/sizeof(a[0]);  
  19.   
  20.     //SelectSort1(a,sz);  
  21.     //SelectSort2(a,sz);  
  22.     SelectSort3(a,sz);  
  23.     PrintArray(a,sz);  
  24. }  
  25.   
  26. //堆调整:将堆的末端子结点作调整,使得子结点永远小于父结点  
  27. void AdjustDown(int* a,size_t n,size_t pos)  
  28. {  
  29.     size_t parent = pos;//父节点的下标  
  30.     size_t child = parent*2 + 1;//左孩子的下标  
  31.     while(child < n)  
  32.     {  
  33.         //选左右孩子中较大的  
  34.         if ((child+1 < n) && (a[child] < a[child+1]))  
  35.         {  
  36.             ++child;  
  37.         }  
  38.         if (a[child] > a[parent])//如果孩子节点大于父节点的值,则交换  
  39.         {  
  40.             swap(a[child],a[parent]);  
  41.   
  42.             //向下更新父节点和孩子节点  
  43.             parent = child;  
  44.             child = parent*2 + 1;  
  45.         }  
  46.         else  
  47.         {  
  48.             break;  
  49.         }  
  50.     }  
  51. }  
  52. //默认升序,所以应该建大堆  
  53. void HeapSort(int* a,size_t n)  
  54. {  
  55.     assert(a);  
  56.     //从最后一个非叶子节点开始向下调整  
  57.     for (int i = (n-2)>>1; i >= 0; --i)  
  58.     {  
  59.         AdjustDown(a,n,i);//创建最大堆:将堆所有数据重新排序  
  60.     }  
  61.   
  62.     //缩小范围  
  63.     for (int i = n-1; i > 0; --i)  
  64.     {  
  65.         swap(a[0],a[i]);//堆排序:移除位在第一个数据的根结点  
  66.         AdjustDown(a,i,0);//并做最大堆调整的递归运算  
  67.     }  
  68. }  
  69.   
  70. void TestHeapSort()  
  71. {  
  72.     int a[] = {9,5,4,2,3,6,8,7,1,0};  
  73.     size_t sz = sizeof(a)/sizeof(a[0]);  
  74.   
  75.     HeapSort(a,sz);  
  76.     PrintArray(a,sz);  
  77. }  

运行结果:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值