`
zhouYunan2010
  • 浏览: 207515 次
  • 性别: Icon_minigender_1
  • 来自: 湖南
社区版块
存档分类

选择排序(树形排序,堆排序)

阅读更多
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);
		}
	}
}

分享到:
评论

相关推荐

    数据结构排序算法汇总包-直接插入排序 折半插入排序 2—路插入排序 表插入排序 希尔排序 起泡排序 快速排序 简单选择排序 树形选择排序 堆排序 归并排序链式基数排序

    实现以下常用的内部排序算法并进行性能比较:"直接插入排序"," 折半插入排序"," 2—路插入排序"," 表插入排序"," 希尔排序"," 起泡排序"," 快速排序"," 简单选择排序"," 树形选择排序"," 堆排序"," 归并排序"," 链式...

    树形选择排序算法源代码

    在源代码文件`sort.cpp`中,你应该能看到如何用C++实现树形选择排序的详细过程,包括定义堆结构、构建堆、交换元素和调整堆的函数等。 总的来说,树形选择排序通过引入小顶堆的概念,提高了选择排序的效率,尤其在...

    几种经典排序算法,包括快速排序、冒泡排序、选择排序和堆排序

    堆是一种特殊的树形数据结构,每个父节点的值都大于或等于其子节点的值。堆排序的过程包括构建大顶堆、交换堆顶元素与最后一个元素并调整堆、缩小堆范围,重复这个过程直到只剩下一个元素。堆排序的时间复杂度在最好...

    堆排序算法源代码

    堆排序的核心思想是利用树形数据结构——堆(Heap)来完成排序。堆是一个近似完全二叉树的结构,同时满足大顶堆(父节点的值大于或等于其子节点的值)或小顶堆(父节点的值小于或等于其子节点的值)的性质。在堆排序...

    冒泡排序,选择排序,插入排序,希尔排序,堆排序,归并排序,快速排序源码实现

    5. **堆排序**:堆排序是一种树形选择排序,它的基本思想是建立一个大顶堆或小顶堆,然后将堆顶元素与末尾元素交换,调整剩余元素重新成堆,如此反复进行。源码实现主要包括建堆、交换堆顶与末尾元素、调整堆的过程...

    插入排序、选择排序、希尔排序、堆排序、冒泡、双向冒泡、快速排序、归并排序、递归的归并排序、基数排序

    4. 堆排序:堆排序是一种树形选择排序,通过构建最大堆或最小堆来实现排序。它的平均和最坏情况时间复杂度均为O(n log n)。 5. 冒泡排序:冒泡排序是最基础的排序算法之一,通过不断交换相邻的逆序元素,使得大元素...

    霍夫曼树和堆排序

    堆是一种特定的树形数据结构,满足堆的性质:在一个最大堆中,每个父节点的值都大于或等于其子节点的值;在最小堆中,每个父节点的值都小于或等于其子节点的值。在C++中,我们可以用数组来实现堆,因为数组天然支持...

    基数排序、堆排序、希尔排序、直接插入排序

    堆是一种特殊的树形数据结构,其每个父节点的值都大于或等于其子节点的值。在`堆排序Heap_sort.cpp`中,你可以学习到如何维护堆的性质并进行相应的调整,如 sift-up 和 sift-down 操作,以实现排序。 希尔排序,又...

    C++堆排序,包括建堆,上调,下调,排序,树形输出

    树形输出是将堆结构以图形化的方式展示出来,这有助于理解和调试堆排序的过程。通常使用二维数组来模拟树的结构,通过打印节点的值和它们之间的连接,可以直观地看到每个元素在堆中的位置。 总结一下,堆排序算法...

    插入排序冒泡排序堆排序基数排序选择排序快速排序源码

    堆排序是一种树形选择排序,利用完全二叉树的特性来调整数组。分为建堆和调整堆两部分,最后将堆顶元素与末尾元素互换,然后重新调整堆。Java实现如下: ```java public class HeapSort { public static void sort...

    基于选择排序方法的类模板设计与实现C++课程设计.doc

    选择排序是排序法中很经典的算法,选择排序法可以分为简单选择排序、树形选择排序和堆排序。简单选择排序是选择排序的基础,而树形选择排序和堆排序是简单选择排序的改进。 类模板设计 为了实现基于选择排序方法的...

    数据结构堆排序

    堆是一种特殊的树形数据结构,每个节点都有一个值,并且满足以下性质:对于任何非叶节点,其值都大于或等于(最大堆)或小于或等于(最小堆)它的子节点的值。在最大堆中,根节点是所有节点中最大的;在最小堆中,根...

    MFC 堆排序 树控件 数据结构

    在“duipaixu1”这个文件中,可能包含了实现上述功能的源代码示例,包括堆排序的算法实现、MFC树控件的使用方法,以及如何将排序过程用树形结构呈现。通过分析和学习这个文件,开发者能够加深对MFC、堆排序以及数据...

    数据结构课程设计 实验报告——堆排序

    堆排序是一种基于树形选择的排序算法,其核心在于利用完全二叉树的性质进行元素的选择与排序。在排序过程中,将待排序的数据集合视为一颗完全二叉树的顺序存储结构,并通过维护该完全二叉树的堆属性来进行排序。 ##...

    堆排序算法实例

    在计算机科学中,堆是一个可以被看作是一棵树形结构的数据集合,其中每个父节点的值都大于或等于其子节点的值(大顶堆)或小于或等于其子节点的值(小顶堆)。堆排序算法利用了这个特性来有效地对数据进行排序。 ...

    堆排序 c语言 演示

    ### 堆排序C语言实现解析 #### 一、堆排序简介 堆排序是一种基于比较的排序算法,它利用了二叉堆的数据结构特性来进行排序。堆分为两种:最大堆和最小堆。最大堆指的是父节点总是大于或等于其子节点的堆;而最小堆...

    多线程排序---希尔排序、快速排序、堆排序

    堆排序是由Napoleon Goldstein在1960年代初提出来的,它是一种树形选择排序,利用了完全二叉树的特性。堆可以看作一个近似完全平衡的二叉树,分为最大堆和最小堆,最大堆的父节点总是大于或等于其子节点,最小堆反之...

    java 实现二叉排序树 堆

    在实际应用中,二叉排序树常用于快速查找和排序,而堆则常用于实现优先级队列、求解最大/最小元素问题,如堆排序算法。结合二叉排序树和堆的概念,可以设计出更高效的数据结构和算法,例如二叉堆(一种同时满足二叉...

    数组堆操作,包括堆排序、堆插入、堆删除等

    堆是一种特殊的树形数据结构,每个节点都有一个值,并且满足堆的性质:对于最大堆,父节点的值总是大于或等于其子节点的值;对于最小堆,父节点的值总是小于或等于其子节点的值。这种数据结构常用于优先队列的实现,...

    堆排序代码

    堆排序是一种基于比较的排序算法,它利用了堆这种特殊的树形结构来进行排序。在计算机科学中,堆通常指的是一种完全二叉树结构,其每个节点的值都大于等于(最大堆)或小于等于(最小堆)其子节点的值。 #### 二、...

Global site tag (gtag.js) - Google Analytics