package com.sort;

/**
 * 选择排序:
 * 简单选择排序,树形选择排序与堆排序
 * 
 */
public class SelecSortDemo {

/**
* --------------------------------------------
* 简单选择排序
* 原理:假设列表中有n个元素,从第一个元素开始,在第一个元素
* 与最后一个元素之间选择一个最小的元素与第一个元素交换,
* 然后从第二个元素开始,在第二个元素与最后一个元素之间选择
* 最小的元素与第二个元素交换,以此类推,最后列表有序。
*/
public static void simpleSelectSort(Object[] a){
int len = a.length;
for(int i = 0,j;i<len;i++){
j = selectMin(a, i);
if(i!=j) //等于就没有必要交换了
a[i] = a[j];
}
}
/**
* 简单选择排序的辅助方法
* 从指定位置i开始到最后位置选择出一个最小的元素
* 并且返回它的索引值
*/
private static int selectMin(Object[] a,int low){
int min = low; //假设第一个元素为最小值
for(int i = low+1;i<a.length;i++){
if(((Comparable)a[i]).compareTo(a[min])<0){
min = i;
}
}
return min;
}

/** 
     * --------------------------------------- 
     * 树形选择排序 :
     * 对于简单排序来说,主要是进行n-1趟元素的比较,每趟比较n-2次,
     * 每趟比较取出一个最小值(也可以是最大值),逐步使列表有序。
     * 但是第一趟的比较是可以为后续的比较提供信息的,使后续的比较次数大大减少,
     * 而后续的比较又可以为更后续的比较提供信息,这样就减少了比较的次数,减少了
     * 时间复杂度。
     * 
     * 实现原理:
     * 第一步,首先对n个记录进行两两比较,得到较小的n/2个数再依次比较,依次类推
     * 直到得到一个最小值,这是一个构造完全二叉树的过程,根节点即为最小元素,叶子节点为列表元素。
     * 构造的此树的存储结构可以用数组表示方法,数组长度为2n-1。填充此树,比如
     * 列表元素为:49    38     65    97   76    13    27   49
     * 构造的树为:                     13
     *                     38               13
     *                38       65       13       27
     *              19  38   65  97   76  13   27  49
     * 13为根结点位最小值,列表元素为叶子节点
     * 
     * 第二步,移走最小元素,此时可重新为数组a的第一个位置赋值为此最小值,
     * 之后如果找出次小值则可以为第二个位置赋值,......
     * 
     * 第三步,找出次小值,找出最小值在叶子节点的位置,从该节点开始,和其兄弟节点
     * 进行比较,修改从叶子节点到根节点的元素值,比较完毕后,根节点为次小值。
     * 第三步比较是利用了第一次比较提供的信息,因为第一步已经得到了两两比较的
     * 较小值,只要拿第一次与最小值比较的元素(即最小值的兄弟节点)与它们比较即可得最小值。
     * 即拿上述例子的76与27比较,然后27与38比较得到次小值27。
     * 重复第二和第三步,排序完成。
     * 
     * PS:这里把移出去的叶子节点都要重设为最大值,可对此方法进行稍微改动
     * 可传一个最大值进来,这里是整型所以用了Integer.MAX_VALUE
     */  
    public static void treeSelectSort(Object[] 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++] = 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;
      }
      }
      
       }
    }

/**
* ----------------------------------
* 堆排序
*    堆排序是在树形选择排序的基础上进一步进行优化
* 只需要一个额外的存储空间,且不需根据标志判断是不是最大值。
* 堆的定义:在1到n/2的元素中,有k(i)<=k(2i),k(i)<=k(2i+1)
* 或k(i)>=k(2i),k(i)>=k(2i+1)
* 简单来说:就是假如将此序列看成一棵完全二叉树,要使这个无序列表
* 变成堆,则小于等于n/2(最后一个非终端节点就是n/2)的某个节点i的左右子节点均大于此节点,
* 即堆的定义k(i)<=k(2i),k(i)<=k(2i+1)。

* 实现原理:
*    首先将序列看成一个树形结构,
* 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后以又用最后一个值替换根元素,
* 以此类推,则最终得到有序序列 
*/
public static void heapSort(Object[] a){  
        int len = a.length;  
        //构建堆  
        for(int i=(len-1)/2;i>=0;i--){  
            heapAdjust(a,i,len);  
        }  
          
        //输出堆顶元素并调整建新堆的过程  
        int count = len-1;  
        while(count > 0 ){  
            //交换树根与最后一个值  
            swap(a,0,count);  
            count -- ;  
            heapAdjust(a,0,count);  
        }  
    }  
      
    /** 
     * 调整某一个节点极其左右子节点的位置 ,并选择左右节点中的较大者
     * 继续向下调整
     */  
    private static void heapAdjust(Object[] a,int i,int len){  
    Object parent = a[i];
    for(int j = (i+1) * 2 - 1;j < len; j = (j+1) * 2 - 1){ //沿着左右节点中的较小者继续往下搜索
    if(j < len-1 && ((Comparable)a[j]).compareTo(a[j+1]) < 0 ){
    ++j; //如果左节点较大过度到右节点
    }
    if(((Comparable)parent).compareTo(a[j]) > 0) //左右节点均小于父节点则不必要继续向下搜索
    break;
    a[i] = a[j];
    i = j ;
    }
        a[i] = parent; //parent插入到正确的位置
        
    }

/**
* 交换数组中两元素的值
*/
private static void swap(Object[] a,int i,int j){
Object temp = null;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
    
    //just for test
    public static void main(String[] args) {
    Integer[] data = {49,38,65,97,76,13,27,49};
SelecSortDemo.treeSelectSort(data);
for(Integer d:data){
System.out.println(d);
}

}

转自:http://zhouyunan2010.iteye.com/blog/1217462

}

java中的排序算法——简单选择排序,树形选择排序与堆排序(一)相关推荐

  1. Java 与排序算法(2):选择排序

    一.选择排序 选择排序(Selection Sort)是一种简单的排序算法,其基本思想是在待排序序列中选择最小(或最大)的元素,将其与序列的第一个元素交换位置,然后在剩余的元素中继续选择最小(或最大) ...

  2. python 按条件选择行和列数据_小白学数据结构-排序算法Python(冒泡、选择、快速、希尔等等)...

    排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们通常所说的排序算法往往指的是内部排序算法,即数据 ...

  3. 八大排序算法-简单排序(3种)

    八大排序算法-简单排序 javascript-选择排序 jacascript-冒泡排序 jacascript-插入排序 javascript-选择排序 算法思想:简单选择排序是最简单直观的一种算法,基 ...

  4. JavaScript 几种排序算法实现(冒泡、选择、插入、归并、快速排序)

    1. 冒泡 // 冒泡 - 每次循环, 将两两中偏大的元素移动到右边 for (let i = 0; i < arr.length - 1; i++) {for (let j = i; j &l ...

  5. 【排序算法】python 十大经典排序算法(全网最详)

    排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存.常见的内部排序算法有:插入排序.希尔排序.选 ...

  6. 数据结构排序系列详解之六 树形选择排序

    这篇博客接着来说说选择类排序之一的排序:树形选择排序 在简单选择排序中,每次的比较都没有用到上次比较的结果,所以比较操作的时间复杂度是O(N^2),想要降低比较的次数,则需要把比较过程中的大小关系保存 ...

  7. 九大排序算法告诉你什么是内部排序和外部排序

    概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们通常所说的排序算法往往指的是内部排序算法, ...

  8. Java中的经典算法之冒泡排序(Bubble Sort)

    Java中的经典算法之冒泡排序(Bubble Sort) 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一趟:首先比较第1个和第2 ...

  9. 排序算法竟能如此美丽?排序算法可视化大全!

    文章目录 首荐:VisuAlgo 各算法对比 最炫酷的 比较聪明的 最古老的 开源的Javascript程序 我的方法(伪):折线可视化 开源Python脚本 舞蹈可视化 内存状态可视化 首荐:Vis ...

  10. 排序算法的稳定性 (什么样的排序是不稳定的)

    有两个6,a[0]和a[3].排序结果就有两种可能: 如果排序结束后,a[0]可以保证一定在a[3]前头,也就是他们原有的顺序不变,那这种排序算法就是稳定的.(比如常见的冒泡排序.基数排序.插入排序. ...

最新文章

  1. mysql管理用户数据库_MySQL 数据库管理(一)(用户与受权)
  2. python线下培训-线下培训价值一万八的某达PYTHON培训视频
  3. [watevrCTF 2019]Repyc [NPUCTF2020]BasicASM
  4. SQL Server代理(4/12):配置数据库邮件
  5. tensorflow2 目标检测_一文了解YOLO-v4目标检测
  6. 常见职位的英文简称_想进外企?英文简历少不了,看这里,教你英文简历的形式和技巧...
  7. 【iCore4 双核心板_ARM】例程三十三:SD_IAP_ARM实验——更新升级STM32
  8. LIO-SAM探秘第三章之代码解析(二) --- featureExtraction.cpp
  9. Python黑帽子-实现netcat基本功能(改进版)
  10. 【转】智能家居 系统安装及HA系统介绍
  11. uniapp---app端上传证件(身份证/银行卡)照片后转base64发送给后台功能实现
  12. Linux软件漏洞修复指南
  13. 怎么将计算机设置为光盘引导模式,怎么设置uefi引导系统
  14. “千山之首 大果榛品”2022年辽阳大果榛子地理标志标识推介会开幕
  15. 【学习总结】数学-欧几里德定理
  16. 解决申请开发者office E5中无法发送手机验证码,reCaptcha加载失败
  17. mysql查询学校开设总课程数_MYSQL数据库课程设计
  18. JS如何区分微信浏览器、QQ浏览器和QQ内置浏览器,解决 ios 无法判断是否为qq浏览器环境的问题。
  19. noip2013 总结
  20. ubuntu 如何在终端下切换到指定的文件夹或盘根目录

热门文章

  1. 走向.NET架构设计—第三章—分层设计,初涉架构
  2. 摄像机丢失信号及偏色的检测思路
  3. JQuery-UI组件化开发
  4. AMD Cpu 性能分析
  5. codeforces Round#429 (Div2)
  6. MongoDB学习之路(三)
  7. 1.1 开始起步,配置ruby on rails运行环境
  8. android布局之LinearLayout 转
  9. 汇编语言——基础知识
  10. 全网最全数据分析师干货-python篇