选择排序—堆排序(Heap Sort)

什么是排序算法稳定性?

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的。

大根堆和小根堆

       堆的结构可以分为大根堆和小根堆,是一个完全二叉树,而堆排序是根据堆的这种数据结构设计的一种排序,下面先来看看什么是大根堆和小根堆
       性质:每个结点的值都大于其左孩子和右孩子结点的值,称之为大根堆;

                每个结点的值都小于其左孩子和右孩子结点的值,称之为小根堆。如下图

我们对上面的图中每个数都进行了标记,上面的结构映射成数组就变成了下面这个样子

 堆排序基本步骤

    1.首先将待排序的数组构造成一个大根堆,此时,整个数组的最大值就是堆结构的顶端

    2.将顶端的数与末尾的数交换,此时,末尾的数为最大值,剩余待排序数组个数为n-1

    3.将剩余的n-1个数再构造成大根堆,再将顶端数与n-1位置的数交换,如此反复执行,便能得到有序数组

如下图(小顶堆)所示:

代码如下:

public class MySort {
	
	public static void swap(int[] k, int a, int b) {
		int tem  = k[a];
		k[a] = k[b];
		k[b] =tem;
	}
    
    //堆调整算法 ,n为有效长度,k为当前节点
	public static void heapAdjust(int[] a, int n, int k) {
		int k1 = k*2 +1; //左右孩子的索引
		int k2 = k1 + 1; 
		
		//没有左右孩子,即叶子节点
		if(k1 >= n && k2 >= n) return;
		
		//只有左孩子
		if(k2 >= n) {
			if(a[k1] > a[k]) {
				swap(a, k, k1);
			}
		} else {  //左右孩子都有
			//如果本身满足大顶堆
			if(a[k] > a[k1] && a[k] > a[k2]) {
				return;
			} 
			
			//如果左孩子大,交换并调整k1
			if(a[k1] > a[k2]) {
				swap(a, k, k1);
				heapAdjust(a, n, k1);
			} else { //如果右孩子大,交换并调整k2
				swap(a, k, k2);
				heapAdjust(a, n, k2);
			}
			
		}
		
	}
	//heap排序(大顶堆 -- 升序排序)
	public static void heapSort(int[] a) {
		long start = System.currentTimeMillis();
		int n = a.length;
		//建堆
		for(int i = (n-2)/2; i>=0; i--) {
			heapAdjust(a, n, i);
		}
		
		//排序,交换堆顶和堆尾
		while(n > 0) {
			//System.out.print(a[0]+ " ");
			swap(a, 0, n-1);
			n--;
			heapAdjust(a, n, 0);
		}
		
		System.out.println("\nheapSort time: " + (System.currentTimeMillis()-start));
	}
 
    public static void main(String[] args) {
		int a[] = {3,4,7,1,10};
		int b[] = {3,2,1,4,5,7,6,9,8}; 
		heapSort(b);
		for(int i:b) {
			System.out.print(i+" ");
		}
	}

}

参考博客

https://blog.csdn.net/u012434102/article/details/45646235

https://blog.csdn.net/u010452388/article/details/81283998

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值