选择类排序的基本思想是每一趟在n-i+1(i=1,2,...,n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。本篇在介绍简单选择排序的基础上,给出了其改进算法--树形选择排序和堆排序。

1.简单选择排序

算法思想:第一趟简单选择排序时,从第一个记录开始,通过N-1次关键字的比较,从n个记录中选出关键字最小的记录,并和第一个记录进行交换。第二趟简单选择排序时,从第二个记录开始,通过n-2次关键字的比较,从n-1个记录中选出关键字最小的记录,并和第二个记录表进行交换。......第i趟简单选择排序时,从第i个记录开始,通过n-i次关键字的比较,从n-i+1个记录中选出关键字最小的记录,并和第i个记录进行交换。如此反复,经过n-1趟简单选择排序,将n-1个记录排到位,剩下一个最小记录直接在最后,所以共需进行n-1趟简单选择排序。

 private static void SelectSort(int[] a) {int k=0,temp;for (int i = 0; i < a.length-1; i++) {k=i;for (int j = i+1; j < a.length; j++) {if(a[j]<a[k]) k=j;}if(k!=i){temp=a[i];a[i]=a[k];a[k]=temp;}}}

算法分析:i=1时需要进行n-1此比较,i=2时需进行n-2次比较,依次总需要n-1+n-2+..+1=n(n-1)/2,即进行比较操作的时间复杂度为O(n^2),空间复杂度为O(1),不稳定

2.树形选择排序

算法思想:树形选择排序也称作锦标赛排序。基本思想是先把待排序的n个记录的关键字两两比较,取出较小者,然后再在[n/2]个较小者中,采用同样的方法进行比较,选出每两个中的较小者,如此反复,直至选出最小关键字记录为止。这个过程可以用一棵满二叉树来表示,不满时用关键字为∞的节点填满,选择的最小关键字记录就是这棵树的根节点。在输出最小关键字之后,为选出次小关键字,将最小关键字记录所对应的叶子结点的关键字值置为∞,然后从该叶节点开始和其兄弟结点的关键字比较,修改从该叶结点到根结点路径上各结点的值,则根结点的值即为次小关键字。重复进行上述过程,直到所有的记录全部输出为止,如图所示给出了选取最小及次小关键字的过程。

                                                   

(a)选出最小关键字                                                                            (b)选出次小关键字

  private static void treeSelectSort(int[] a){ int len = a.length;int treeSize = 2 * len - 1;  //完全二叉树的节点数int low = 0;         Object[] tree = new Object[treeSize];    //临时的树存储空间//由后向前填充此树,索引从0开始        for(int i = len-1,j=0 ;i >= 0; --i,j++){//填充叶子节点             tree[treeSize-1-j] = a[i];         }                  for(int i = treeSize-1;i>0;i-=2){//填充非终端节点            tree[(i-1)/2] = ((Comparable)tree[i-1]).compareTo(tree[i]) < 0 ? tree[i-1]:tree[i];}                  //不断移走最小节点       int minIndex;         while(low < len){             Object min = tree[0];    //最小值             a[low++] = (int) min;             minIndex = treeSize-1;//找到最小值的索引             while(((Comparable)tree[minIndex]).compareTo(min)!=0){minIndex--;             }             tree[minIndex] = Integer.MAX_VALUE;  //设置一个最大值标志             //找到其兄弟节点             while(minIndex > 0){      //如果其还有父节点                 if(minIndex % 2 == 0){   //如果是右节点                     tree[(minIndex-1)/2] = ((Comparable)tree[minIndex-1]).compareTo(tree[minIndex])                          < 0 ? tree[minIndex-1]:tree[minIndex];                     minIndex = (minIndex-1)/2;                 }else{                   //如果是左节点                     tree[minIndex/2] = ((Comparable)tree[minIndex]).compareTo(tree[minIndex+1])                          < 0 ? tree[minIndex]:tree[minIndex+1];minIndex = minIndex/2;                 }             }                      }      }

算法分析:假设排序所用满二叉树的深度为h,在树形选择排序中,除了最小关键字,被选出的其他较小关键字都是走了一条有叶子结点到根结点的比较的过程且均需比较h-1次。可证明含有n个叶子结点的完全二叉树的深度h=log2n+1,因此在树形选择排序中,每选出一个较小关键字需要进行log2n次比较,所以其时间复杂度O(nlog2n) 空间复杂度O(n) 稳定

3.堆排序

威洛母斯对树形选择排序进一步的改进方法,堆排序,用以弥补树形选择排序占用空间多的缺憾。采用堆排序时,只需要一个记录大小的辅助空间。堆排序是在排序过程中,将向量中存储的数据看成一棵完全二叉树,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择关键字最小的记录,即待排序记录仍采用向量数组方式存储,并非采用树的存储结构,而仅仅是采用完全二叉树的顺序结构的特征进行分析而已。

算法思想:在待排序的记录的关键字存放在数组a[1,...,n]之中,将a看成一棵完全二叉树的顺序表示,每个结点表示一个记录,第一个记录a[0]作为二叉树的根,以下各记录a[1]~a[n-1]依次逐层从左到右顺序排列,任意结点a[i]的左孩子是a[2i],右孩子是a[2i+1],双亲是a[i/2]。对这棵完全二叉树进行调整建堆。

堆定义:称各结点的关键字值满足条件:a[i]>=a[2i]切a[i]>a[2i+1]的完全二叉树为大根堆。反之就是根结点小于孩子结点对应的堆称为小根堆。例如

98                                                      14

77               35                                48               35

62    55     14     35                        62    55       98     35

48                                                 77

(a).大根堆                                     (b).小根堆

实现原理: 

1.首先将序列看成一个树形结构,

构建堆的过程:找到最后一个非终端节点n/2,与它的左右子节点比较,

比较结果使此父节点为这三个节点的最小值。再找n/2-1这个节点,

与其左右子节点比较,得到最小值,以此类推....,最后根节点即为最小值

49  38   65   97   76   13   27   49

初始树为:

49

38              65

97      76      13       27

49

构造堆后的树为

13

38              27

49    76       65       49

97

交换数据的顺序为:97<——>49, 13<--->65,38不用换,49<-->13,13<-->27

2.输出堆顶元素并调整建新堆的过程

输出堆顶最小值后,假设以最后一个值替代之,由于其左右子树的堆结构并没有被破坏

只需要自上而下进行调整。比如把上图的13输出后以97替代,然后可以把97与27交换,

然后97又与49交换,此时最小值为根元素27,输出27后以又用最后一个值替换根元素,

以此类推,则最终得到有序序列

  private static void HeapSort(int[] a) {crt_heap(a);int temp;for (int i = a.length-1; i >=1; i--) {temp=a[0];a[0]=a[i];a[i]=temp;sift(a,0,i-1);//使a[0,..,i-1]变成堆}}//重建堆private static void sift(int[] a, int k, int m) {int t,x,i,j;t=a[k];//暂存根记录a[k]x=a[k];i=k;j=2*i;boolean finished=false;while(j<=m&&!finished){//若存在右子树,且右子树根的关键字大,则沿右分支筛选if(j<m&&a[j]<a[j+1]) j=j+1;if(x>=a[j]) finished=true;//筛选完毕else{//继续筛选a[i]=a[j];i=j;j=2*i;}}a[i]=t;//a[k]填入到恰当的位置}//建立初堆private static void crt_heap(int[] a) {int n=a.length-1;for(int i=n/2;i>=0;--i){//从第[n/2]个记录开始进行筛选建堆sift(a,i,n);}}

算法分析:在每次循环时,左、右子树先比较一次,然后左、右子树较大者再与被筛元素比较一次,所以对深度为H的堆,筛选算法中的关键比较次数至多为2(h-1)次。时间复杂度O(nlog2n)  空间复杂度O(1)   不稳定

排序算法--选择篇(简单选择,树形选择,堆排序)相关推荐

  1. 【简单排序算法】:简单选择排序、直接插入排序和冒泡排序

    [简单排序算法]:简单选择排序.直接插入排序和冒泡排序 简单选择排序: 原理:设所排序序列的记录个数为n.i取1,2,-,n-1,每次从所有n-i+1个记录(Ri,Ri+1,-,Rn)中找出最小的记录 ...

  2. 【排序算法】图解简单选择排序(图解堪比Debug显示每次循环结果)

    [排序算法]图解简单选择排序(图解堪比Debug分析每次循环结果) 写在前面: 本文主要介绍简单选择排序算法,通过图片一步步解释每一趟每一次的后移.代码通过C#实现,并输出每一次交换的情况和比较次数, ...

  3. 排序算法:冒泡排序、插入排序、选择排序、希尔排序

    相关博客: 排序算法:冒泡排序.插入排序.选择排序.希尔排序 排序算法:归并排序.快速排序 排序算法:桶排序.计数排序.基数排序 排序算法:堆排序 十大排序算法小结 一.冒泡排序: 1.算法原理: 冒 ...

  4. JS 排序算法详解(冒泡排序,选择排序,插入排序,希尔排序,快速排序)

    JS 排序算法详解(冒泡排序,选择排序,插入排序,希尔排序,快速排序) 一. 大O表示法 在进行排序算法之前,我们得先掌握一种对算法效率的表示方法,大O表示法. 我们使用大O表示法来表示算法的时间复杂 ...

  5. 经典排序算法(一) —— Selection Sort 选择排序

    经典排序算法(一) -- Selection Sort 选择排序 文章目录 经典排序算法(一) -- Selection Sort 选择排序 简介 排序过程 实现 复杂度 简介 选择排序是一种简单直观 ...

  6. 【Java】八个常用的排序算法:插入排序、冒泡排序、选择排序、希尔排序 、快速排序、归并排序、堆排序和LST基数排序

    这篇文章主要介绍了Java如何实现八个常用的排序算法:插入排序.冒泡排序.选择排序.希尔排序 .快速排序.归并排序.堆排序和LST基数排序,需要的朋友可以参考下 本文实现了八个常用的排序算法:插入排序 ...

  7. java排序算法(插入排序,冒泡排序,选择排序)

    java排序算法(插入排序,冒泡排序,选择排序) 先了解原理,然后自己跟着敲一下,加深印象 CMD编译命令:javac -encoding utf-8 SortList.java && ...

  8. java语言冒泡排序法_Java实现八个常用的排序算法:插入排序、冒泡排序、选择排序、希尔排序等...

    本文实现了八个常用的排序算法:插入排序.冒泡排序.选择排序.希尔排序 .快速排序.归并排序.堆排序和LST基数排序 首先是EightAlgorithms.java文件,代码如下: import jav ...

  9. 排序算法入门之简单选择排序

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 在学了冒 ...

  10. python选择排序算法图解_简单选择排序算法(C语言详解版)

    该算法的实现思想为:对于具有 n 个记录的无序表遍历 n-1 次,第 i 次从无序表中第 i 个记录开始,找出后序关键字中最小的记录,然后放置在第 i 的位置上. 例如对无序表{56,12,80,91 ...

最新文章

  1. 编译 | 5G时代的游戏世界:一年后的AR与VR将会发生的几个变化
  2. 在C#中使用SerialPort类实现串口通信
  3. 012 分析技能冷却二叉树
  4. VTK:提取可见细胞用法实战
  5. 2007-3-31第五天CCNA课
  6. 转:怎样开始学习php代码审计?
  7. DQL 学习-- DQL 基本元素
  8. android demo示例代码,Android Service demo例子使用详解(示例代码)
  9. 迪米特法则(Law Of Demeter)
  10. 219.存在重复元素II
  11. 系统名称:联想ThinkpadOEM Win7SP1简体中文旗舰版原版光盘镜像64位
  12. 中国IT产业未来在哪里
  13. SpringBoot的使用01
  14. 二阶常系数齐次线性微分方程通解的求取
  15. 《产品游戏化》电子书下载(epub+mobi+pdf) Netflix、迪士尼、微软巨头在使用的产品策略
  16. 6个简历模板免费下载网站,资源超多,质量超高!
  17. VScode提升效率技巧教程
  18. 在EXCEL中如何给一列数据加上双引号
  19. Git与GitHub说明分析
  20. 悲观|乐观锁、自旋|互斥锁、公平|非公平锁

热门文章

  1. 【Python计量】异方差性的检验
  2. 联想用u盘重装系统步骤_用u盘给联想笔记本装系统
  3. 天龙八部手游服务器维护公告,-天龙八部手游-详情页-官方网站-天龙八部官方唯一正版3DMMORPG武侠手游...
  4. zencart模板修改的地方
  5. 老徐小程序之小程序怎么选?
  6. centos 6.9部署svn服务器和客户端(客户端含windows、linux版本)
  7. 软件测试入门知识,Linux系统基础教程——带你玩转Linux(五)
  8. c++builder:Project Project1.exe raised exception class EAccessViolation with message 'Access violati
  9. 如何入门Python之Python基础教程详解
  10. 怎么用真机测试android,andriod studio如何使用真机测试 andriod studio真机测试教程