创建最大(小)堆以及堆排序

      以前在学数据结构的时候对于堆这块学的并不是很好,另加平时也没有用到过这一块的内容,所以早就把它忘到天涯海角去了。但是最近在面试的时候很多面试官都会闻到相关的内容,最多的就是关于堆排序的内容,当然包括了最大堆和最小堆。菜鸟一只,写下这篇博客也只是为了提醒我自己,以后搞忘的时候能够快速的记忆起来。当然也希望能够帮助到更多的和我一样的菜鸟级别的人对堆排序(现在我连怎么创建堆都不清楚)有个比较清楚的认识。大神们可以忽略,当然如果有错欢迎各位指出,万分感谢。

     关于堆的一些介绍我也就不在这里赘述了,(就算是写我也只能去复制粘贴的了,哈哈),这篇文章这篇文章可以推荐大家看一下。

    我在这里就大概的讲一下我实现堆排序的思路(这里就以最大堆排序为例了):

     1.首先需要初始化堆,将数组初始化为一个最大堆;

     2.因为堆排序是相当于把整个堆分成了有序区和无序区,刚开始全部都是无序区。当初始化最大堆以后将最大堆的堆顶元素(也就是第一个)与最后一个元素进行交换,这样被交换到最后的那个元素就是有序区了。当交换元素以后无序区就不再满足最大堆的条件,所以需要将无序区的所有元素重新初始化为最大堆(有序区的元素不在参与最大堆的构建)。然后重复以上的交换操作。在这个过程中,有序区逐渐增大,无序区逐渐减小。

     以上就是在堆排序中的简单思路;

    可能所有的博客都有这些内容,但是在一些细节上可能有所忽略,没有提及,毕竟大神们眼中的不是问题对我们来说就是个坑,容易掉进去。

   在初始化最大堆的时候,从最后一个非叶子结点开始,与字节点比较,创建以当前节点为根结点的最大堆(我的意思就是让这个节点与她的字节点比较大小,如果这个节点小于她的某一个子节点的话就与之交换)。依次向前的非叶子节点进行这样的操作。注意一点:当对前面的节点进行操作的时候可能会导致之前的最大堆不在满足条件,所以需要继续堆她们进行调整。这样就能完整地初始化这个最大堆了!md,我觉得我的语文真的不行了,完全表达不了真正的意思,希望大家不要看得更懵逼了!如早发现看不懂就尽快弃坑,免的让我这个菜鸟把你带坑里了。

下面我们用代码展示一下:

public class HeapSort{
	public static void main(String[] args) {
		int data[] = new int[]{3,2,4,5,9,7,8,1,6,17};
		HeapSort(data);
		System.out.println("排序后的数组:");
		print(data);
	}
	
	
	/**
	 * 这是堆排序的主要函数,
	 * 每次通过初始化堆以及
	 * 将堆顶元素与最后一个
	 * 元素进行交换
	 * @param data
	 */
	public static void HeapSort(int data[]){
		for (int i = 0; i < data.length; i++) {
			createMaxHeap(data, data.length - 1 - i);
			swap(data, 0, data.length - 1 - i);
			print(data);
			System.out.println();
		}
	}
	
	
	/**
	 * 其实只要把初始化堆的这个函数搞清楚
	 * 以后堆排序就十分的简单了
	 * @param data
	 * @param lastIndex
	 */
	public static void createMaxHeap(int data[],int lastIndex){
		/**传入的这个参数lastIndex就是无序区的最后一个元素的位置*/
		for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
			//用于保存当前节点的位置
			int k = i;
			//如果当前节点存在子节点
			while(k * 2 + 1 <= lastIndex ){
				//这个循环是保证将破坏后的最大堆恢复,
				//就是交换以后有些堆结构会被破坏掉需要重新初始化
				int biggerIndex = k * 2 + 1;
				//这里默认左子树上面的是较大的值
				if(biggerIndex < lastIndex){
					if(data[biggerIndex] < data[biggerIndex+1]){
						biggerIndex ++;
					}
				}
				//如果子树上面的值比父节点中的大,那么就会将之交换,并且以交换的字节点为根的最大堆就会有改变,需要进一步进行初始化,如果
				//如果子树上的值小于父节点的值就进行交换,并且将biggerIndex的值赋给k.否则的话退出while循环
				if (data[biggerIndex] > data[k]) {
					swap(data, biggerIndex, k);
					k = biggerIndex;
				}else{//如果子树上的值比父节点的小,那么就不用进行交换,并且以子节点为根结点的最大堆结构不会改变,可以直接退出
					break;
				}
			}
		}
	}
	public static  void print(int data[]){
		for (int i = 0; i < data.length; i++) {
			System.out.print(data[i]+"    ");
		}
	}

 	private static void swap(int[] data, int i, int j) {
 		if (i == j) {
			return;
		}
		data[i] = data[i] + data[j];
		data[j] = data[i] - data[j];
		data[i] = data[i] - data[j];
	}

}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值