算法之——堆排序(java)

启发于b站的一个视频,推荐大家去看看,讲的很清晰(av47196993  阿婆主:正月点灯笼)

完整的代码在本文末

一.堆是什么

堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆

二.完全二叉树

如果二叉树的深度为k,则除第k层外其余所有层节点的度都为2,且叶子节点从左到右依次存在 。只有这两种情况

 

我们用数组来存储树,假设父节点的下标为i,那么父节点的左子节点下标为2*i+1,右子节点下标为2*i+2,如下表格

父节点下标i
左子节点下标2*i+1
右子节点下标2*i+2

三.堆排序 

总思路:先把乱序数组排成堆的结构,根据大根堆的性质,最大元素为根节点。循坏建堆+取根,建堆+取根这样的操作...这样不断取到的根必然是有序的,最终完成排序

建堆思路:一个完全二叉必然有类似下图所示结构,我们用红色框把一个完全二叉分成若干个部分

从最后一个叶子节点的父节点开始,开始对父节点与它的两个子节点进行大小的比较(右子节点不存在就只比较父节点和左子节点就可以了),把最大元素与父节点元素交换位置。图中的框就是每次的操作单元。我们把图中的结构,从下到上,从有到左依次每个框里面执行这样的比较操作,那么最后就会得到一个堆

我这里把整个算法分成三个方法

①建堆(会调用②)

//把待数组建成一个堆结构
	public void buildHeap(int[] tree, int n) {
		int lastnode = n - 1;                //末节点为数组长度-1
		int parent = (lastnode - 1) / 2;     //根据完全二叉树性质得到父节点
		for (int i = parent; i >= 0; i--) {  //开始一直往前做heapify()
			heapify(tree, n, i);
		}
	}

②局部把最大值放堆顶(就是上面说到的,每个红框里,把父节点和它的左右子节点中,比较得出他们之间的最大值,并交换到在父节点位置)

//heapify的作用就是把每个最小部分的最大值放到堆顶
	public void heapify(int[] tree, int n, int nodeindex) {
		if (nodeindex >= n)                  //方法出口
			return;
		int leftson = 2 * nodeindex + 1;     //根据完全二叉性质得到左子节点
		int rightson = 2 * nodeindex + 2;    //根据完全二叉性质得到右子节点
		int maxindex = nodeindex;            //把开始节点下标设置为最大元素值下标
//从父节点和它的两个自节点中找到最大的,并把最大的下标给max下标
		if ((leftson < n) && (tree[leftson] > tree[maxindex]))
			maxindex = leftson;
		if ((rightson < n) && (tree[rightson] > tree[maxindex]))
			maxindex = rightson;
		if (maxindex != nodeindex) {
			swap(tree, maxindex, nodeindex);
			heapify(tree, n, maxindex);
		}

	}

③排序(会调用①,②)

public void heapSort(int[] tree, int n) {
		buildHeap(tree, n);//先把堆好
		//循环把最大的元素值(即堆顶元素)与数组末端的元素进行交换
		//因为循环过程中持续i--,每经过一次循环就相当于把数组长度减一,
		//也就达到了,把每次放到数组末端的最大值元素排除出后续操作的范围
		for (int i = n - 1; i >= 0; i--) {
			swap(tree, i, 0);
			heapify(tree, i, 0);
		}
	}

四.完整代码(java实现)

package test;

public class HeapSort {
	public static void main(String[] args) {
		int[] tree = { 25, 14, 97, 32, 31, 30, 75, 100, 84, 81, 26, 34 };
		for (int i : tree) {
			System.out.print(i + " ");
		}
		int n = tree.length;
		HeapSort heapSort = new HeapSort();
		heapSort.heapSort(tree, n);
		System.out.println("");
		for (int i : tree) {
			System.out.print(i + " ");
		}
	}
//把待数组建成一个堆结构
	public void buildHeap(int[] tree, int n) {
		int lastnode = n - 1;                //末节点为数组长度-1
		int parent = (lastnode - 1) / 2;     //根据完全二叉树性质得到父节点
		for (int i = parent; i >= 0; i--) {  //开始一直往前做heapify()
			heapify(tree, n, i);
		}
	}
//heapify的作用就是把每个最小部分的最大值放到堆顶
	public void heapify(int[] tree, int n, int nodeindex) {
		if (nodeindex >= n)                  //方法出口
			return;
		int leftson = 2 * nodeindex + 1;     //根据完全二叉性质得到左子节点
		int rightson = 2 * nodeindex + 2;    //根据完全二叉性质得到右子节点
		int maxindex = nodeindex;            //把开始节点下标设置为最大元素值下标
//从父节点和它的两个自节点中找到最大的,并把最大的下标给max下标
		if ((leftson < n) && (tree[leftson] > tree[maxindex]))
			maxindex = leftson;
		if ((rightson < n) && (tree[rightson] > tree[maxindex]))
			maxindex = rightson;
		if (maxindex != nodeindex) {
			swap(tree, maxindex, nodeindex);
			heapify(tree, n, maxindex);
		}

	}

	public void heapSort(int[] tree, int n) {
		buildHeap(tree, n);//先把堆好
		//循环把最大的元素值(即堆顶元素)与数组末端的元素进行交换
		//因为循环过程中持续i--,每经过一次循环就相当于把数组长度减一,
		//也就达到了,把每次放到数组末端的最大值元素排除出后续操作的范围
		for (int i = n - 1; i >= 0; i--) {
			swap(tree, i, 0);
			heapify(tree, i, 0);
		}
	}

	// 交换
	public void swap(int[] tree, int i, int j) {
		int tmp = tree[i];
		tree[i] = tree[j];
		tree[j] = tmp;
	}

}

 

执行结果图

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值