三、排序_06 &大顶堆小顶堆 &堆排序(笔记)

大顶堆小顶堆

public class A013_堆排序_大顶堆小顶堆 {

	public static void main(String[] args) {
		// int[] a = { 78, 56, 34, 43, 4, 1, 15, 2, 23 };
		int[] a = { 5, 6, 3, 2, 8, 1 };
		midOrder(a, 0);
		System.out.println();

		DoMinHeap(a);
		midOrder(a, 0);
		System.out.println();

		DoMaxHeap(a);
		midOrder(a, 0);
	}

	private static void DoMaxHeap(int[] a) {
		for (int i = a.length / 2 - 1; i >= 0; i--)
			MaxHeapFixDown(a, i);
	}

	public static void MaxHeapFixDown(int[] a, int parent) {
		int left = parent * 2 + 1;
		int right = parent * 2 + 2;
		if (left >= a.length)
			return;
		int max = left;
		if (right < a.length) {
			if (a[max] <= a[right])
				max = right;
		}
		if (a[parent] >= a[max]) {
			return;
		} else {
			int t = a[parent];
			a[parent] = a[max];
			a[max] = t;
			MaxHeapFixDown(a, max);
		}
	}

	public static void DoMinHeap(int[] a) {
		for (int i = a.length / 2 - 1; i >= 0; i--)
			MinHeapFixDown(a, i);
	}

	public static void MinHeapFixDown(int[] a, int parent) {
		int left = parent * 2 + 1;
		int right = parent * 2 + 2;
		if (left >= a.length)
			return;
		int min = left;
		if (right < a.length) {
			if (a[min] >= a[right])
				min = right;
		}
		if (a[parent] <= a[min]) {
			return;
		} else {
			int t = a[parent];
			a[parent] = a[min];
			a[min] = t;
			MinHeapFixDown(a, min);
		}
	}

	private static void midOrder(int[] arr, int i) {// 中
		if (i >= arr.length)
			return;
		midOrder(arr, i * 2 + 1);
		System.out.print(arr[i] + " ");
		midOrder(arr, i * 2 + 2);
	}
}

在这里插入图片描述
这是中序遍历生成的数组👆,第一行是初始的,第二行是小顶堆,第三行是大顶堆。
这里做了一个小顶堆,做了一个大顶堆,代码都差不多,可以通过max和min进行区分,这里就讲个小顶堆吧。
首先通过DoMinHeap方法,进行for循环,他是倒过来进行调整的,也就是非叶子结点的最后一个开始,进行调整,这里就是a.length / 2 - 1,数组长度除2,再-1就是了,然后把每一个数,都调用MinHeapFixDown方法:
进入方法后,先获取这个节点的左右节点坐标,如果左节点越界了,就说明是叶子节点直接return;这里用一个中间量min记录左节点的值,以方便接下来的代码,如果右节点的下标是正常的,那就说明有右节点,则进行判断,如果右节点,比左节点还要小,那么就把右节点的值,赋给min,就是min = right;
然后这个时候,就只有min这一个值了,然后开始将它与父节点进行判断,如果父节点是比min这个下标所在的节点还要小,那么就说明,这一个堆是个小顶堆,不用调整,else的话,就把min和parent两个下标所在的值进行交换,交换过后,还要进入递归,为什么呢?
因为交换过后,要判断,交换过后的,也就是min这个下标所在的堆,是不是小顶堆,如果不是的话,就递归再进行判断,如果越界的话,就直接在上面的出口,return了。

堆排序

import java.util.Arrays;

public class A013_堆排序_优化 {

	public static void main(String[] args) {
		int[] a = { 78, 56, 34, 43, 4, 1, 15, 2, 23 };
		// int[] a = { 5, 6, 3, 2, 8, 1, 9 };
		System.out.println(Arrays.toString(a));
		sortMin(a);
		System.out.println(Arrays.toString(a));
		sortMax(a);
		System.out.println(Arrays.toString(a));
	}

	private static void sortMin(int[] a) {
		DoMinHeap(a);
		for (int i = a.length - 1; i >= 0; i--) {
			int t = a[0];
			a[0] = a[i];
			a[i] = t;
			MinHeapFixDown(a, 0, i);
		}
	}

	public static void DoMinHeap(int[] a) {
		for (int i = a.length / 2; i >= 0; i--)
			MinHeapFixDown(a, i, a.length);
	}

	public static void MinHeapFixDown(int[] a, int parent, int n) {
		int left = parent * 2 + 1;
		int right = parent * 2 + 2;
		if (left >= n)
			return;
		int min = left;
		if (right < n) {
			if (a[min] >= a[right])
				min = right;
		}
		if (a[parent] <= a[min]) {
			return;
		}
		int t = a[parent];
		a[parent] = a[min];
		a[min] = t;
		MinHeapFixDown(a, min, n);
	}

	private static void sortMax(int[] a) {
		DoMaxHeap(a);
		for (int i = a.length - 1; i >= 0; i--) {
			int t = a[0];
			a[0] = a[i];
			a[i] = t;
			MaxHeapFixDown(a, 0, i);
		}
	}

	private static void DoMaxHeap(int[] a) {
		for (int i = a.length / 2 - 1; i >= 0; i--)
			MaxHeapFixDown(a, i, a.length - 1);
	}

	public static void MaxHeapFixDown(int[] a, int parent, int n) {
		int left = parent * 2 + 1;
		int right = parent * 2 + 2;
		if (left >= n)
			return;
		int max = left;
		if (right < n) {
			if (a[max] <= a[right])
				max = right;
		}
		if (a[parent] >= a[max]) {
			return;
		} else {
			int t = a[parent];
			a[parent] = a[max];
			a[max] = t;
			MaxHeapFixDown(a, max, n);
		}
	}
}

在这里插入图片描述
这里没用三种树的遍历方法,直接将数组从头到尾输出,第一行是初始的,第二行是小顶堆后的排序,第三行是大顶堆后的排序,可以看到小顶堆后的排序是降序,大顶堆反之。
上面讲了小顶对,我们这里讲大顶堆吧,首先调用的sortMax方法,进入该方法后,首先把乱序的数组通过调用DoMaxHeap,变成一个大顶堆,这和上面小顶堆的形成是一样的,就不多做赘述了,然后进入一个循环,由于现在数组是一个大顶堆,那么最大的那个数,就是在最头上,所以这时候,把数组的第一个元素,和数组的最后一个元素进行交换,然后将除了最后一个元素外的,前面的元素,用MaxHeapFixDown方法,再次进行大顶堆的生成,然后再回到for循环,还是用堆顶的元素,与i–,也就是数组的倒数第二个元素进行交换,以此类推,这样就会生成一个大元素在后,小元素在前的升序数组了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值