业务逻辑:初始化数组 创建堆 堆序列化 堆数组排序
1.数据结构
堆(英语:heap)是计算机科学中一类特殊的数据结构的统称。
堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:
1.堆中某个节点的值总是不大于或不小于其父节点的值;
2.堆总是一棵完全二叉树。
常见的堆有二叉堆、斐波那契堆等。
堆的定义:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。
(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4…n/2)
堆是一颗完全二叉树,在这棵树中,所有父节点都满足大于等于其子节点的堆叫大根堆,所有父节点都满足小于等于其子节点的堆叫小根堆。
当一个无序数组,创建成一个堆时,可能会违背一个堆的性质,所以需要将节点与节点的进行交换。在节点与节点交换时,从最后一个非叶子节点开始:比较自己左右子节点,循环到叶子节点比较结束;然后找到索引减一找到节点,进行循环操作
2.业务代码
public class HeapSort<T extends Integer> {
/**
* 获取左孩子节点
*
* @param i 索引
* @return 节点
*/
public int left(int i) {
return (i + 1) * 2 - 1;
}
/**
* 获取右孩子
*
* @param i 索引
* @return 节点
*/
public int right(int i) {
return (i + 1) * 2;
}
/**
* 获取父节点
*
* @param i 索引
* @return 节点
*/
public int parent(int i) {
// 当i为根节点
if (i == 0) {
return -1;
}
return (i - 1) / 2;
}
/**
* 大根堆
*
* @param a 数组
* @param i 索引
* @param heapLength 堆长度
*/
public void bigHeapify(T[] a, int i, int heapLength) {
int l = left(i);
int r = right(i);
int largest = -1;
/**
* 下面两个if条件句用来找到三个元素的最大元素的位置largest;
* l < heapLength 说明l在数组内,i非叶子节点;
*/
if (l < heapLength && a[i].compareTo(a[l]) < 0) {
largest = l;
} else {
largest = i;
}
// r < heapLength 说明r在数组内
if (r < heapLength && a[largest].compareTo(a[r]) < 0) {
largest = r;
}
// 如果i处元素不是最大的,就把i处的元素与最大处的原交换,交换会使元素下降
if (i != largest) {
T temp = a[i];
a[i] = a[largest];
a[largest] = temp;
// 交换元素后,以a[i]为根的树就可能不在满足大根堆性质,于是递归调用该方法
bigHeapify(a, largest, heapLength);
}
}
/**
* 大根堆
*
* @param a 数组
* @param i 索引
* @param heapLength 堆长度
*/
public void smallHeapify(T[] a, int i, int heapLength) {
int l = left(i);
int r = right(i);
int least = -1;
/**
* 下面两个if条件句用来找到三个元素的最小元素的位置largest;
* l < heapLength 说明l在数组内,i非叶子节点;
*/
if (l < heapLength && a[i].compareTo(a[l]) > 0) {
least = l;
} else {
least = i;
}
// r < heapLength 说明r在数组内
if (r < heapLength && a[least].compareTo(a[r]) > 0) {
least = r;
}
// 如果i处元素不是最大的,就把i处的元素与最大处的原交换,交换会使元素下降
if (i != least) {
T temp = a[i];
a[i] = a[least];
a[least] = temp;
// 交换元素后,以a[i]为根的树就可能不在满足大根堆性质,于是递归调用该方法
smallHeapify(a, least, heapLength);
}
}
/**
* 创建一个完成的堆序列
*
* @param a 数组
* @param heapLength 数组长度
*/
public void buildHeap(T[] a, int heapLength) {
// 从后往前看,lengthParent-1 出的元素是第一个有孩子节点的节点
int lengthParent = parent(heapLength - 1);
// 最初,parent(length)之后的所有元素都是叶子结点;
// 因为大于length/2处元素的孩子节点如果存在,那么
// 它们的数组下标值必定大于length,这与事实不符;
// 在数组中,孩子元素必定在父亲元素的后面,从后往前
// 对元素调用bigHeapify,保证了元素的孩子都是大根堆
for (int i = lengthParent; i >= 0; i--) {
bigHeapify(a, i, heapLength);
}
}
public static void main(String[] args) {
// 初始化一个无序数组
Integer[] ints = new Integer[]{9, 24, 2, 7, 26, 6, 3, 16, 8};
HeapSort<Integer> heapSort = new HeapSort<>();
// 调用堆创建方法,将无序数组生成为堆数组
heapSort.buildHeap(ints, ints.length);
// 打印输出堆数组
System.out.println("堆数组序列:" + Arrays.asList(ints));
int len = ints.length - 1;
// 递归排序堆数组
while (len > 0) {
swap(ints, 0, len);
len--;
heapSort.bigHeapify(ints, 0, len);
}
// 打印输出排序数组
System.out.println("排序数组序列:" + Arrays.asList(ints));
}
}
3.算法总结
数组堆排序是一种非线性时间比较类选择型排序
平均时间复杂度为O(),最好的情况为O(),最坏的情况O(),空间复杂度为O(1),排序方式为In-place,是一种不稳定的排序算法
4.笔记总结
(1)初始化普通无序数组
(2)将无序数组转化成堆性质(大堆根,小堆根)数组
无序数组需要转化成堆性质数组,需要进行堆节点交换操作:
在进行堆节点交换时,从最后一个非叶子(一个树枝的最后一个节点成为叶子节点,没有叶子节点的节点称之为非叶子节点)节点a进行开始,与左b右c子节点进行比对大小,将三个节点中最大的节点交换到父节点a位置,如果b节点数据是三个节点中数据最大,则将a,b节点数据交换,然后再将交换之后的b节点数据进行与自己的左右子节点进行比对交换操作,依次循环,直到没有所处位置比左右子节点数据都大时结束;然后将原节点a的索引减一,进行循环比对交换。直到该堆符合相关性质为止。
(3)将堆性质数组进行(按大、小)进行排序
获得堆性质数组之后,将数组最后一个位置数据与第一个进行交换,然后将原数组刚刚交换到最后一个位置的数据排除,将剩下的数组数据进行堆性质数据。堆序列化后,再进行数组第一个位置与倒数第二个进行交换,然后排序倒数第二个数组位置数据,依次循环往复。
(4)得到一个有序的数组
————————————————
对堆数据结构有疑惑的,点击原文链接
原文链接:https://blog.csdn.net/u013728021/article/details/84034420