堆排序:
堆是一颗完全二叉树,如果父节点的值都大于子节点,就称之为大根堆,如果父节点的值都小于子节点,就称之为小根堆。一般使用数组来存储这个二叉树结构。
第i节点的左右孩子节点分别为2 ∗ i + 1和2 ∗ i + 2,它的父节点为(i - 1) / 2。由于是完全二叉树,假设节点的个数为size,则最后一个非叶子节点的编号为size / 2 - 1。
堆排序时,先建大根堆,显然队是无序的,将堆顶元素和最后一个元素交换,最后一个元素显然是最大的,去掉该元素,对剩余元素进行上述操作直到剩余最后一个元素。
public static void heapAdjust(int[] numbers, int i, int size) { // 堆调整
int leftChild = 2 * i + 1; // i的左孩子节点序号
int rightChild = 2 * i + 2; // i的右孩子节点序号
int max = i;
if (i < size / 2) { // 如果i不是叶子节点,就不用进行调整
if (leftChild < size && numbers[leftChild] > numbers[max])
max = leftChild;
if (rightChild < size && numbers[rightChild] > numbers[max])
max = rightChild;
if (max != i) { // i不是最大,则需要调整以max为父节点的子树,使其成为大根堆
swap(numbers, i, max); // 交换i和max,使得以max为父节点的子树成为大根堆
heapAdjust(numbers, max, size); // 交换之后,以max为父节点的子树可能不是大根堆,需要继续调整以max为父节点的子树
}
}
}
public static void buildMaxHeap(int[] numbers, int size) { // 建立大堆
for (int i = size / 2 - 1; i >= 0; i--) // 非叶子节点最大序号值为size / 2 - 1
heapAdjust(numbers, i, size);
}
public static void swap(int[] numbers, int i, int j) { // 交换数组两个节点的值
int temp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = temp;
}
public static void heapSort(int[] numbers, int size) {
buildMaxHeap(numbers, size);
for (int i = size - 1; i >= 0; i--) {
swap(numbers, 0, i); // 交换堆顶元素和最后一个元素,实现将剩余元素中的最大者放到最后面
heapAdjust(numbers, 0, i); // 调整之后以堆顶节点为父节点的子树可能不是大根堆,需要继续调整以堆顶节点为父节点的子树
}
}
最好时间复杂度:O(nlogn)
最坏时间复杂度:O(nlogn)
平均时间复杂度:O(nlogn)