【排序二】选择排序(选择排序&&堆排序)
2017-03-01 20:27
239 查看
【排序一】插入排序
一、选择排序
1、基本思想
顾名思义,选择排序就是每次选一个数据放到其应该出现的位置,以升序(降序)为例,首先选最小(最大)的数据放到正确位置,接着再选次小(次大)的数据放到合适的位置,以此类推,直到最大(最小)的数据被放入最后一个位置,排序就算完成。
总体算法分三步完成:选数据--->将所选数据放入合适位置--->缩小需要排序的范围
图解(以升序为例):
![](https://img-blog.csdn.net/20170301163820558?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc25vd181Mjg4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
2、排序效果图:
![](https://img-blog.csdn.net/20170301163859636?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc25vd181Mjg4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
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、实现代码
运行结果:
![](https://img-blog.csdn.net/20170301170511583?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc25vd181Mjg4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
二、堆排序
1、堆介绍
堆数据结构是一种数组对象,它可以被视为一棵完全二叉树结构。
堆结构的二叉树存储是:
(最)大堆:每个父节点的都大于孩子节点。
(最)小堆:每个父节点的都小于孩子节点。
如图所示:
![](https://img-blog.csdn.net/20170301193011439?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc25vd181Mjg4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
2、堆排序的基本思想
堆积排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
1)将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无序区;
2)将堆顶元素R[1]与最后一个元素R
交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R
;
3)由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
图解(假设为升序):
![](https://img-blog.csdn.net/20170301200744428?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc25vd181Mjg4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
3、堆排序效果图
![](https://img-blog.csdn.net/20170301200853492?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc25vd181Mjg4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
4、时间复杂度&&空间复杂度
假设一棵完全二叉树有N个节点,则它的的高度为lgN,堆排序中的比较次数为2*lgN,交换次数为N次,
故堆排序的时间复杂度为O(N*lgN)。
由于占用了有限个空间,所以堆排序的空间复杂度为O(1)。
5、代码实现
运行结果:
一、选择排序
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、实现代码
#pragma once #include <iostream> #include <assert.h> using namespace std; //选择排序:选一个数(最大或最小)-->将此数放在正确的位置上-->缩小范围 void PrintArray(const int* a,const size_t n) { for (size_t i = 0; i < n; ++i) { cout<<a[i]<<" "; } cout<<endl; } //C语言风格的选择排序 void SelectSort1(int* a,size_t n) { assert(a); for (size_t i = 1; i < n; ++i) { int minIndex = i;//未排序区间最小数据的位置下标 int start = i - 1;//未排序区间的第一个数据下标 //选出第二部分最小的数据 for (size_t j = i+1; j < n-1; ++j)//用j = i+1来缩小未排序区间范围 { if (a[j+1]<a[minIndex]) { swap(a[j+1],a[minIndex]); } } //第二部分最小的数据和第二部分第一个数据进行比较 if (a[minIndex] < a[start]) { swap(a[start],a[minIndex]); } } } //C++风格的选择排序 void SelectSort2(int* a,size_t n) { assert(a); int minIndex = 0; for (size_t i = 0; i < n - 1; ++i) { minIndex = i; //未排序区间最小数据的位置下标 size_t pos = i + 1;//未排序区间的第一个数据下标 while(pos < n)//选出未排序区间最小的数据 { if (a[pos] < a[minIndex]) { minIndex = pos; } ++pos; } swap(a[i],a[minIndex]);//将所选数据放到正确位置 } } //选择排序的优化:每次既选出最大的数,也选出最小的数 void SelectSort3(int* a,size_t n) { assert(a); int left = 0;//未排序区间的左下标 int right = n - 1;//未排序区间的右下标 while (left < right) { int minIndex = left;//未排序区间最小数据的位置下标 int maxIndex = right;//未排序区间最大数据的位置下标 //选出最大和最小数据的下标 for (int i = left; i <= right; ++i) { if (a[i] < a[minIndex]) { minIndex = i; } if (a[i] > a[maxIndex]) { maxIndex = i; } } //修正:最大值在最小位置或最小值在最大位置 swap(a[maxIndex],a[right]);//将最大数据放到区间最右侧 if (minIndex == right) { minIndex = maxIndex; } swap(a[minIndex],a[left]);//将最小数据放在区间最左侧 left++;//缩小区间范围 right--;//缩小区间范围 } } void TestSelectSort() { int a[] = {9,5,4,2,3,6,8,7,1,0}; size_t sz = sizeof(a)/sizeof(a[0]); //SelectSort1(a,sz); //SelectSort2(a,sz); SelectSort3(a,sz); PrintArray(a,sz); }
运行结果:
二、堆排序
1、堆介绍
堆数据结构是一种数组对象,它可以被视为一棵完全二叉树结构。
堆结构的二叉树存储是:
(最)大堆:每个父节点的都大于孩子节点。
(最)小堆:每个父节点的都小于孩子节点。
如图所示:
2、堆排序的基本思想
堆积排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
1)将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无序区;
2)将堆顶元素R[1]与最后一个元素R
交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R
;
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、代码实现
#pragma once #include <iostream> #include <assert.h> using namespace std; //选择排序:选一个数(最大或最小)-->将此数放在正确的位置上-->缩小范围 void PrintArray(const int* a,const size_t n) { for (size_t i = 0; i < n; ++i) { cout<<a[i]<<" "; } cout<<endl; } void TestSelectSort() { int a[] = {9,5,4,2,3,6,8,7,1,0}; size_t sz = sizeof(a)/sizeof(a[0]); //SelectSort1(a,sz); //SelectSort2(a,sz); SelectSort3(a,sz); PrintArray(a,sz); } //堆调整:将堆的末端子结点作调整,使得子结点永远小于父结点 void AdjustDown(int* a,size_t n,size_t pos) { size_t parent = pos;//父节点的下标 size_t child = parent*2 + 1;//左孩子的下标 while(child < n) { //选左右孩子中较大的 if ((child+1 < n) && (a[child] < a[child+1])) { ++child; } if (a[child] > a[parent])//如果孩子节点大于父节点的值,则交换 { swap(a[child],a[parent]); //向下更新父节点和孩子节点 parent = child; child = parent*2 + 1; } else { break; } } } //默认升序,所以应该建大堆 void HeapSort(int* a,size_t n) { assert(a); //从最后一个非叶子节点开始向下调整 for (int i = (n-2)>>1; i >= 0; --i) { AdjustDown(a,n,i);//创建最大堆:将堆所有数据重新排序 } //缩小范围 for (int i = n-1; i > 0; --i) { swap(a[0],a[i]);//堆排序:移除位在第一个数据的根结点 AdjustDown(a,i,0);//并做最大堆调整的递归运算 } } void TestHeapSort() { int a[] = {9,5,4,2,3,6,8,7,1,0}; size_t sz = sizeof(a)/sizeof(a[0]); HeapSort(a,sz); PrintArray(a,sz); }
运行结果:
相关文章推荐
- 【排序二】选择排序(选择排序&&堆排序)
- 算法分析-选择排序(直接选择排序 & 堆排序)
- 排序-->选择排序(选择排序&&堆排序)
- 数据结构&算法实践—【排序|选择排序】堆排序
- 选择排序之堆排序
- 内排序(插入排序、冒泡排序、选择排序、shell排序、快速排序、归并排序、堆排序)
- (12)选择排序之三 堆排序
- 快速排序、希尔排序、插入排序、选择排序、归并排序、堆排序总结
- 选择排序(三)--堆排序
- 选择排序之----堆排序
- c语言各种常见排序(直接插入排序、折半插入排序、冒泡排序、选择排序、堆排序)
- 数据结构&算法实践—【排序|选择排序】选择排序
- 插入排序、冒泡排序、选择排序、Shell排序、快速排序、归并排序、堆排序
- 数据结构&算法实践—【排序|选择排序】选择排序
- 程序员必知的8大排序(二)-------简单选择排序,堆排序(java实现)
- 数据结构学习笔记 --- 排序(选择排序、堆排序)
- 常用排序算法之选择排序 ( 直接选择排序、堆排序 )
- C语言实现 排序源程序(包括直接插入、希尔、冒泡、快速、简单选择、堆排序)
- 插入排序、冒泡排序、选择排序、快速排序、堆排序、归并排序算法比较
- 程序员必知的8大排序(二)-------简单选择排序,堆排序(java实现)