最大堆的操作及堆排序

什么是堆

优先队列:取出的元素的顺序是按照元素的优先权(关键字)大小,而不是元素进入队列的顺序

优先队列的完全二叉树表示最大堆的操作及堆排序_第1张图片

堆的特性

结构性:用数组表示的完全二叉树
有序性:任一结点的关键字是其子树所以结点的最大值或最小值

最大堆的操作及堆排序_第2张图片

最大堆的插入

将新增的结点放到堆最后的位置,然后与其父结点进行比较,比父节点大的,位置互换,然后继续往上比较,直到根结点。

最大堆的删除

将堆顶的元素删除,然后将最后的元素值放到根结点处。调整堆 变成最大堆

最大堆的建立

  • 1 通过插入操作,将N个元素一个个相继插入到一个初始为空的堆中去,其时间复杂度最大时为O(NlogN);
  • 2.在线性时间下建立最大堆
    ①将N个元素按输入顺序存入,先满足完全二叉树的结构特性;
    ②调整各节点位置,以满足最大堆的有序特性。

堆排序

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

算法复杂度

最佳情况:T(n) = O(nlogn) 最差情况:T(n) = O(nlogn) 平均情况:T(n) = O(nlogn)

算法描述

  • 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆。
  • 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
  • 由于交换后新的堆顶会违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

代码

public class Heapsort {

	public void buildmaxheap(int[] a) { // 建立最大堆
		for (int i = a.length / 2 - 1; i >= 0; i--) // i=a.length/2-1,指向完全二叉树中最后面的父节点,
													// 然后一个个往前调整直到根结点
			adjustHeap(a, i, a.length);

	}

	public void adjustHeap(int[] a, int k, int len) { // k是指需要调整的结点,与它的子结点进行比较互换,下滤
		int tmp = a[k];
		for (int i = 2 * k + 1; i < len - 1; i = i * 2 + 1) {

			if (a[i] < a[i + 1]) // 比较k下面孩子结点的大小,大的与父节点比较
				i++;
			if (a[i] < tmp) // 父节点大,不需要调整
				break;
			else {
				a[k] = a[i]; // 将大的子节点与父节点互换,原来父结点继续与原来子节点的子节点比较,直到边界
				k = i; // K指向新的需要比较的父节点位置,便于找到其子节点进行比较
			}
		}
		a[k] = tmp; // 最后找到正确位置,将一开始父节点的值放到正确位置

	}

	public int[] HeapSort(int[] a) {
		int len = a.length;
		if (len < 1)
			return a;
		buildmaxheap(a); // 将数组a建立成最大堆
		while (len > 0) { // 将堆顶与最大堆最后位置互换,调整最大堆,一直循环,直到堆顶
			int i = a[0];
			int j = a[len - 1];
			a[0] = j;
			a[len - 1] = i;
			len--;
			adjustHeap(a, 0, len);
		}
		return a;

	}

	public int deleteMax(int[] a) { // 刪除最大堆堆顶,并返回删除的值
		int k = a[0];
		a[0] = a[a.length - 1];
		a[a.length - 1] = -9999;
		adjustHeap(a, 0, a.length - 1); // 调整二叉树成 最大堆
		return k;
	}

	public int[] inser(int[] a, int data) { // 最大堆a中插入元素data,假设a中最后一个位置空

		a[a.length - 1] = data;
		int k = a.length - 1;
		int parent = (k - 1) / 2;
		while (parent >= 0 && data > a[parent]) {  //插入的结点一直向上比较
			a[k] = a[parent];
			k = parent;
			if (parent != 0)
				parent = (parent - 1) / 2;
			else
				break;
		}
		a[k] = data;
		return a;

	}

其中堆的插入删除的操作,并没有判断堆的大小,是否为空的条件,而且默认堆的数组是够大的。插入操作时,插入到了堆的最后一个位置,假设是0到length-2是原来的堆。删除操作时,将最后的位置设为-9999,代表为空。

你可能感兴趣的:(数据结构与算法)