数据结构+算法-堆排序

2019 精帖
0 3393

堆排序(英语:Heapsort)是指利用这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。


以最小堆为例

下沉操作

对于一个非叶子节点的下沉操作指的是:如果父节点大于子节点的任何一个节点,那么父节点就要和子节点中的最小的节点交换。

QQ截图20190512120608.png

代码描述

	/**
	 * 下沉操作,构造小顶堆
	 * @param heap 元素数组
	 * @param k 当前元素下标
	 * @param n 数组长度
	 */
    public void sink(int[] heap,int k,int n) {
        while (k<<1 <= n) {
            int j = k<<1;
            /**
             * 判断左子树大还是右子树大,(当然了,对于小顶堆来说,j指向较小的那个元素)
             */
            if (j < n && compare(heap,j, j+1))
                     j++;
            /**
             * 判断父节点是否大于最小的子节点,如果如果是则交换,不是则返回
             */
            if (!compare(heap,k, j))
                     break;
            exchange(heap,k, j);
            k = j;
        }
    }


排序过程

排序的第一步是对整个无序数组进行整理使其满足二叉堆的性质,这样才能对其进行排序(对于非叶子节点所有的父节点均大于其子节点)。

然后对整个堆进行排序,过程描述如下:

    对于小顶堆来说,根节点就是堆中最小的元素,把根节点(数组第一个元素)与数组最后一个元素交换,此时堆元素的长度-1

    交换以后的数组可能不满足堆的性质,则以根节点开始进行下沉操作,直到数组满足堆得性质。

    然后继续交换第一个节点与最后一个节点,如此反复,直到数组中只有一个节点,排序结束

代码描述

/**
	 * 排序
	 * 首先对一个无序的数组进行下沉操作,以至于满足堆的性质,(所有的父节点均大于其子节点)
	 * 然后对整个堆进行排序
	 * @param heap
	 */
	public void sort(int[] heap) {
	    int n = heap.length-1;
	    /**
	     * 第一个for循环用户构造一个满足堆特点的二叉堆
	     * 对所有的非叶子节点执行下沉操作
	     */
	    for (int k = n>>1; k >= 1; k--)
	        sink(heap, k, n);
	    /**
	     * 对二叉堆进行堆排序
	     * 对于小顶堆来说,根节点就是堆中最小的元素,把根节点(数组第一个元素)与数组最后一个元素交换,此时堆元素的长度-1
	     * 交换以后的数组可能不满足堆的性质,则以根节点开始进行下沉操作,直到数组满足堆得性质。
	     * 然后继续交换第一个节点与最后一个节点,如此反复,直到数组中只有一个节点,排序结束
	     */
	    while (n > 1) {
	    	exchange(heap, 1, n--);
	        sink(heap, 1, n);
	    }
	}


完整代码:

package club.test;

import org.junit.Test;
/**
 * 堆排序(小顶堆为例)
 * @author jiajia
 *
 */
public class TestMain8 {
	@Test
	public void test() {
		int[] a=new int[] {0,2,8,5,3,6};
		sort(a);
		for(int i=0;i<a.length;i++) {
			System.out.print(a[i]+" ");
		}
	}
	/**
	 * 排序
	 * 首先对一个无序的数组进行下沉操作,以至于满足堆的性质,(所有的父节点均大于其子节点)
	 * 然后对整个堆进行排序
	 * @param heap
	 */
	public void sort(int[] heap) {
	    int n = heap.length-1;
	    /**
	     * 第一个for循环用户构造一个满足堆特点的二叉堆
	     * 对所有的非叶子节点执行下沉操作
	     */
	    for (int k = n>>1; k >= 1; k--)
	        sink(heap, k, n);
	    /**
	     * 对二叉堆进行堆排序
	     * 对于小顶堆来说,根节点就是堆中最小的元素,把根节点(数组第一个元素)与数组最后一个元素交换,此时堆元素的长度-1
	     * 交换以后的数组可能不满足堆的性质,则以根节点开始进行下沉操作,直到数组满足堆得性质。
	     * 然后继续交换第一个节点与最后一个节点,如此反复,直到数组中只有一个节点,排序结束
	     */
	    while (n > 1) {
	    	exchange(heap, 1, n--);
	        sink(heap, 1, n);
	    }
	}
	/**
	 * 交换元素
	 * @param heap
	 * @param i
	 * @param j
	 */
	public void exchange(int[] heap,int i,int j) {
        heap[i]=heap[i]+heap[j];
        heap[j]=heap[i]-heap[j];
        heap[i]=heap[i]-heap[j];
	}
	/**
	 * 比较
	 * @param heap
	 * @param i
	 * @param j
	 * @return
	 */
	public boolean compare(int[] heap,int i,int j) {
        return heap[i]>heap[j]?true:false;
    }
	/**
	 * 下沉操作,构造小顶堆
	 * @param heap 元素数组
	 * @param k 当前元素下标
	 * @param n 数组长度
	 */
	public void sink(int[] heap,int k,int n) {
        while (k<<1 <= n) {
            int j = k<<1;
            /**
             * 判断左子树大还是右子树大,(当然了,对于小顶堆来说,j指向较小的那个元素)
             */
            if (j < n && compare(heap,j, j+1))
                     j++;
            /**
             * 判断父节点是否大于最小的子节点,如果如果是则交换,不是则返回
             */
            if (!compare(heap,k, j))
                     break;
            exchange(heap,k, j);
            k = j;
        }
    }
}


留言(0)
加载更多
猜你喜欢
  • blog -判断一棵二叉树是否为另一颗二叉树的子树

    题目:判断下方两棵二叉树右方的二叉树是否为左方二叉树的子树 例1: | |
  • blog -图的着色问题

    -图的着色问题问题描述: 图的m-着色判定问题——给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色,是否有一种着色使G中任意相邻的2个顶点着不同颜色?个人感觉图的着色问题类似与八皇后
  • ofc 为什么要学习

    为什么要学习
  • blog 使用双向循环链表解决 约瑟夫环问题-

    约瑟夫环问题描述         有m个人,围成一个环,编号为 1、2、3、、、m,从第一个人开始循环报(从1开始),假设到n的那个人出局,然后从下一个人继续(从1开始),到n出列,以
  • blog -快速

    快速流程--来自百度百科 首先设定一个分界值,通过该分界值将组分成左右两部分。  将大于或等于分界值的集中到组右边,小于分界值的集中到组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素
  • blog 十种理解(前五)

    十种理解(前五)1.冒泡冒泡是一种简单的。它重复地走访过要列,一次比较两个元素,如果它们的顺错误就把它们交换过来。描述:比较相邻的元素。如果第一个比第二个大,就交换它们两个;对每一对相邻元素作同样的工作
  • blog -快速

    百科:快速(Quicksort)是对冒泡的一种改进。 快速由C. A. R. Hoare在1960年提出。它的基本思想是:通过一趟将要分割成独立的两部分,其中一部分的所有都比另外一部分的所有
  • blog -反转链表-递归

    反转链表 有一个单向链表t如下: t = 1->2->3->4->5->6->7->8->9 写一个方反转链表t如下: 1<-2<-3<-4<-5<
  • blog --完全二叉树的权值

    试题描述:思路: 用组表示完全二叉树,用先遍历的方式遍历每一层的节点,用一个组储存每一层的和,因为规模小于100000所以用一个容量为17的组即可。计完每一层的和,再比较层最小之和最大的那一层。代码:packa
  • blog 最小生成树Kruskal-

    最小生成树和其应用         什么是最小生成树:一个有 n 个点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个点,并且有保持图连通的最少的边。最小生成树可以用krus