介绍学习完插入排序和交换排序,本篇博客来学习选择排序,选择排序的基本思想是:每趟从待排的记录中选出关键字最小的记录,顺序放在已经排好序子表的最后,直到全部记录排序完毕。由于选择排序每趟总是从无序区中选出全局最小或最大的关键字,所以适合于大量的记录中选择一部分排序记录。在这里,我们主要介绍选择排序里的直接选择排序和堆排序。
1.直接选择排序(简单选择排序)
基本思想
在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。
示例图
实现代码
//直接选择排序 void SelectSort(int a[],int len) { int k,j; for(int i=0;i<len-1;i++)//要进行len-1趟选择 { k=i; for(j=i+1;j<len;j++)//寻找最小,从未排序区间开始,即i+1 { if(a[k]>a[j]) { k=j; } } //i本身不是最小 if(k!=i) { int temp=a[k]; a[k]=a[i]; a[i]=temp; } } for(int i=0;i<len;i++) cout<<a[i]<<" "; }
效率分析
当初始表为正序时,记录移动次数为0,初始表为反序时,每趟均要进行交换操作,然而,无论记录的初始状态如何,都要进行相同次数的关键字对比,均为(n(n-1))/2,因此总的平均时间复杂度为O(n^2)。
直接选择排序算法只使用了几个辅助变量,与问题规模n无关,故辅助空间复杂度为O(1),是一个就地排序,另外,直接选择排序是一个不稳定的排序,可能会交换相等关键字的前后顺序。
2.堆排序
堆排序是一种树形的选择排序,是对直接选择排序的有效改进
堆的定义:
n个元素的序列{k1,k2,…,kn}当且仅当满足下列关系之一时,称之为堆。
情形1:ki <= k2i 且ki <= k2i+1 (最小化堆或小顶堆)
情形2:ki >= k2i 且ki >= k2i+1(最大化堆或大顶堆)
堆是一种完全二叉树或者近似完全二叉树,所以效率极高。
例如:
(a)大顶堆序列:(96, 83,27,38,11,09)----根结点大于孩子结点
(b) 小顶堆序列:(12,36,24,85,47,30,53,91)----根结点小于孩子结点
堆排序的思想
利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。
其基本思想为(大顶堆):
1)将初始待排序关键字序列(R0,R2....Rn-1)构建成大顶堆,此堆为初始的无序区;
2)将堆顶元素R[0]与最后一个元素R[n-1]交换,此时得到新的无序区(R0,R2,......Rn-2)和新的有序区(Rn-1),且满足R[1,2...n-2]<=R[n-1];
3)由于交换后新的堆顶R[0]可能违反堆的性质,因此需要对当前无序区(R0,R2,......Rn-2)调整为新堆,然后再次将R[0]与无序区最 后一个元素交换,得到新的无序区(R0,R2....Rn-3)和新的有序区(Rn-2,Rn-1)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
例如:
给定一个整形数组a[]={16,7,3,20,17,8},对其进行堆排序,我们使用大顶堆。
首先根据该数组元素构建一个完全二叉树,得到
然后需要构造初始堆,则从最后一个非叶节点开始调整,调整过程如下:
最后得到初始堆
把20和3交换位置(堆顶的元素和最后一个元素)
交换之后可能造成被交换的孩子节点不满足堆的性质,因此每次交换之后要重新对被交换的孩子节点进行调整。此时放到最后的20不在进行堆排序。初始化堆得到
把17和3交换位置(堆顶的元素和最后一个元素,红色的20不参与)得
以此类推,最后得到
这样整个区间便已经有序了。由排序过程可见,若想得到升序,则建立大顶堆,若想得到降序,则建立小顶堆。 从上述过程可知,堆排序其实也是一种选择排序,是一种树形选择排序。
实现代码
调整建立初始堆函数为:
//堆排序--初始化堆函数 //完全二叉树若根节点n为从0开始,则左孩子为2n+1,右孩子为2n+2。 void init(int a[],int start,int end)//对a[low....high]进行初始化 { int temp = a[start]; for(int i = 2*start + 1; i<=end; i*=2) { //因为假设根结点的序号为0而不是1,所以i结点左孩子和右孩子分别为2i+1和2i+2 if(i<end &&a[i]<a[i+1])//左右孩子的比较 { i++;//i为较大的记录的下标 } if(temp > a[i])//左右孩子中获胜者与父亲的比较 { break; } //将孩子结点上位,则以孩子结点的位置进行下一轮的筛选 a[start]= a[i]; start = i; } a[start]= temp; //插入最开始不和谐的元素 }
堆排序代码
void HeapSort(int a[],int len) { //先建立大顶堆 for(int i=len/2; i>=0; --i) { init(a,i,len); } //进行排序 for(int i=len-1; i>0; --i) { //最后一个元素和第一元素进行交换 int temp=a[i]; a[i] = a[0]; a[0] = temp; //然后将剩下的无序元素继续调整为大顶堆 init(a,0,i-1); } //输出结果 for(int i=0;i<len;i++) cout<<a[i]<<" "; }
效率分析
堆排序的时间主要由建立初始堆和反复重建初始堆着两部分时间构成。堆排序最坏的时间复杂度为O(nlog2(n)),堆排序为不稳定排序,可能改变相等元素的前后位置,由于初始化堆需要比较次数较多,所以堆排序不适合记录较少的排序。
附上源码地址:https://github.com/longpo/algorithm/tree/master/SelectSort
相关推荐
堆排序详细图解(通俗易懂)+排序算法----堆排序(超详细)堆排序详细图解(通俗易懂)+排序算法----堆排序(超详细)堆排序详细图解(通俗易懂)+排序算法----堆排序(超详细)堆排序详细图解(通俗易懂)+排序算法...
常用的排序算法--堆排序,通过创建堆的方法进行排序
经典排序算法 - 堆排序Heap sort序 经典排序算法 - 地精排序Gnome Sort 经典排序算法 - 奇偶排序Odd-even sort 经典排序算法 - 梳排序Comb sort 经典排序算法 - 耐心排序Patience Sorting 经典排序算法 - 珠...
选择排序算法也是一种简单的排序算法,它的工作原理是通过选择最小或最大元素,并将其与第一个元素交换,以达到排序的目的。选择排序算法的时间复杂度也为O(n^2),因此它也适合小规模的数据排序。 3.插入排序算法 ...
堆排序是一种基于比较的排序算法,它通过构建一个大顶堆或小顶堆来实现排序。在计算机科学中,堆通常被理解为一种特殊的树形数据结构,满足堆的性质:父节点的值总是大于或等于(对于大顶堆)或小于或等于(对于小...
堆排序是一种树形选择排序算法,它的基本思想是将待排序的数组构建成一个大根堆(或小根堆),然后将堆顶元素与堆底元素交换位置,再将剩余元素重新构建成堆,重复执行交换和重构堆的操作,直到整个数组有序。堆排序...
7. **堆排序**:堆排序利用了数据结构“堆”的特性,可以看作是优先队列的一种应用。时间复杂度为O(n log n),原地排序,空间效率高。 8. **计数排序、桶排序、基数排序**:这些是线性时间复杂度的非比较型排序算法...
本文将对快速排序、归并排序、堆排序等常见排序算法进行比较和分析,探讨它们的优缺点和适用场景。 首先, let's 看一下这些排序算法的时间复杂度和空间复杂度: | 排序算法 | 平均情况 | 最好情况 | 最坏情况 | ...
Java代码-排序-直接插入排序、希尔排序、直接选择排序、冒泡排序、堆排序、快速排序、归并排序中部分排序以及算法-贪心法,大家可以将源码下载下来进行学习,附带着注释和解释,有不理解的可以找博主一起探讨,共同...
本文将深入探讨标题和描述中提到的一些基本排序算法,包括选择排序、冒泡排序、插入排序、希尔排序、堆排序、快速排序以及归并排序,并结合C++编程语言进行讲解。 1. **选择排序(Selection Sort)** - 选择排序是一...
- 选择排序:如简单选择排序和堆排序。 2. 非基于比较的排序算法:这类算法不依赖于元素间的比较,而是利用其他特性进行排序。例如,计数排序要求数据范围较小,基数排序要求数据可分解为多个属性。 【基于比较...
堆排序的源程序--编译、运行成功的。 其基本算法思想参照《算法导论》。 有点编译器需去掉-system("pause");
实现以下常用的内部排序算法并进行性能比较:"直接插入排序"," 折半插入排序"," 2—路插入排序"," 表插入排序"," 希尔排序"," 起泡排序"," 快速排序"," 简单选择排序"," 树形选择排序"," 堆排序"," 归并排序"," 链式...
此文件为数据结构中的九种排序算法,包含一些排序方法的过程,其九种排序包括:直接插入排序,折半插入排序,希尔排序,冒泡排序,快速排序,选择排序,堆排序,归并排序,基数排序!
- **堆排序**:利用堆这种数据结构所设计的一种排序算法,可以看作是一种选择排序的优化。 3. ** 动态展示** 源码中的动态展示部分,通过对每一步操作进行绘制,让学习者能够观察到: - 冒泡排序中的气泡如何...
该资源提供了Java中实现堆排序的全面指南。文档中涵盖了堆排序的基本概念,包括如何对数组进行排序以及如何在Java中实现堆排序。此外,文档还包括一个逐步指南,介绍了如何在Java中实现堆排序,包括详细的代码示例和...
在这个"JavaScript-使用javascript开发的排序算法-sorting.zip"压缩包中,很可能是包含了各种常见的排序算法实现,比如冒泡排序、插入排序、选择排序、快速排序、归并排序以及堆排序等。 1. **冒泡排序**:冒泡排序...
七大排序算法如下: 交换排序:快速排序quicksort,冒泡排序bubblesort...选择排序:直接选择排序selectionsort,堆排序maxheapsort 插入排序:直接插入排序insertsort,希尔排序shellsort 合并排序:归并排序mergesort
C语言实现常见排序算法。编译环境:VS2010。 包括: 冒泡排序 快速排序 直接插入排序 Shell排序 直接选择排序 堆排序 归并排序(递归和非递归两种) 桶式排序 基数排序:顺序和静态队列两种方法 索引排序(采用简单...
本资源提供了七大经典排序算法的实现程序,包括快速排序、冒泡排序、选择排序、归并排序、插入排序、希尔排序和堆排序。下面将逐一详细介绍这些排序算法及其原理。 1. 快速排序:由C.A.R. Hoare提出,是一种采用...