【数据结构】--【排序】--堆排序详解

 * 堆排序和简单选择排序都是选择排序
 * 堆排序:将数组看成完全二叉树的结构,根据数组的顺序下标建立抽象的二叉树(需要理解);有大根堆和小根堆;
 * 插入实现的思想:每次插入的都是叶子节点,插入的时候根据数组的下标作为依据进行判断:插入元素的父节点(i-1)/2的值是否大于等于插入的节点,如果是不做处理,
 *        否则,将两者数据进行互换,同时索引指针指向父节点,在进行验证,while循环条件为 arr[(index-1)/2]<arr[index]
 * 弹出实现思想:首先将第一个元素与数组的最后一个元素互换位置,这样就打破了堆排序的结果,然后对从上到下进行重新验证同时限制数组的长度n-1(每次弹出一个,-1),
 *         如果插入元素小于子节点(首先得出最大的子节点),互换位置,然后修改指针,在进行下面子节点的验证,while循环条件left不能越界
 * 时间复杂度O(n*logn)
 * 空间复杂度 O(1)
 * 稳定性:不稳定算法

public class HeapSorting {
	public static void heapSort(int[] arr){
		if(arr==null||arr.length<2){
			return;
		}
		heapSort(arr,0,arr.length-1);
	}

	/**
	 * 
	 * @param arr
	 * @param l 数组起点
	 * @param j 数组长度
	 */
	private static void heapSort(int[] arr, int l, int j) {

		for(int i=0;i<arr.length;i++){
//			逐步形成大根堆
			heapInsert(arr,i);
		}
//			交换拍好的大根堆和最后的一个值
			swap(arr,0,j--);
//			交换之后,不再是大根堆形式,进行下一步排序
			while(j>0){
				heapSortdown(arr,0,j);
//				System.out.println("谁动了我的奶酪"+j);
//				System.out.println(arr[j]);
				swap(arr,0,j--);
				System.out.println("谁动了我的奶酪"+j);
			}
	}
/**
 * 弹出大根堆,重新向下排序,
 * @param arr 待排序数组+末尾排好序的数
 * @param size 待排序数组的长度
 */
	private static void heapSortdown(int[] arr,int index, int size) {
//		小心越界
		int left = index*2+1;
		while(left<size){
//			先判断两个子孩子谁大,获取最大的节点;注意下面代码中<=中的等号必须有,可以考虑一下数组为{1,3,2}时候的场景
			int largest = left+1<=size && arr[left]>arr[left+1]?left:left+1;
//			如果新放入的值大于子节点的最大值,说明有序。返回

			largest = arr[largest] > arr[index] ? largest : index;
			if (largest == index) {
//				return和break效果都是一样的
				return;
			}
//			否则交换父节点和最大的子节点
			swap(arr,index,largest);
//			将索引值下标改为最大下标
			index=largest;
//			修改子节点的下标
			left=index*2+1;
		}
//      错误做法;
/*		int left=(index-1)/2;;
		int largest = arr[left]>arr[left+1]?left:left+1;
		while(arr[index]<arr[largest]){
			swap(arr,arr[index],arr[largest]);
			index=left;
			left=(index-1)/2;
		}*/
	}

	private static void heapInsert(int[] arr, int index) {
//		正确插入验证:循环条件:父节点的值是否大于子值
		while(arr[(index-1)/2]<arr[index]){
//			如果大于交换
			swap(arr,(index-1)/2,index);
//			修改索引下标,进行向上验证
			index=(index-1)/2;
		}
//	     错误之处,如果i=8,arr[i]=4;(i-1)/2=3,arr[3]=5;这个循环就成了死循环。
		/*		while(index>0){
					int fuValue = (index-1)/2;
					if(arr[fuValue]<arr[index]){
						System.out.println(arr[fuValue]+"  "+arr[index]);
						swap(arr,fuValue,index);
						index=fuValue;
					}
				}*/
	}
//	交换两个数的值
	public static void swap(int[] arr,int i,int minValue){
		int temp =arr[i];
		arr[i] =arr[minValue];
		arr[minValue]=temp;
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] arr = {1,3,5,7,9,2,4,6,8};
		heapSort(arr);
		for (int i : arr) {
			System.out.println(i);
		}
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值