java实现堆排序
需要用到两个子函数,函数1是实现将一个数组变为一个大根堆,函数2是为了将一个打乱了的数组重新调整为大根堆。
每次对于大根堆中,第一个位置就是整个数组的最大值,所以我们可以将大根堆的第一个位置值取出来,和最后一个值进行交换,然后就找出了最大值,接下来,我们就在第1~len-1个数中继续进行相同的操作。
上边两个函数都用到了一个自定义的交换数组中数值的函数swap。
首先是交换函数swap
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
函数1是实现添加一个数到一个大根堆最后边,然后从新整理为一个大根堆
// 插入结点,按照大根堆结构插入
public static void heapInsert(int[] arr, int index) {
while (arr[index] > arr[(index - 1) / 2]) {// 子大于父,就交换
swap(arr, index, (index - 1) / 2);
// 下边往父节点移动
index = (index - 1) / 2;
}
}
函数2是为了将一个打乱了的数组重新调整为大根堆(堆顶被打乱了)
// 下边来一个堆调整的函数,heapLen就是堆的长度
public static void heapify(int index, int heapLen, int[] arr) {
int left = index * 2 + 1;
while (left < heapLen) {
// 首先找到当前结点的子结点中较大的一个
int maxIndex = (arr[(left)] < arr[left + 1]) && left + 1 < heapLen ? left + 1 : left;
// 如果当前值大于maxIndex位置值,就交换
if (arr[index] < arr[maxIndex]) {
swap(arr, index, maxIndex);
} else {
break;
}
// 然后是结点同时向下边移动
index = maxIndex;// 只是针对修改的一部分进行继续向下
left = index * 2 + 1;
}
}
完整代码如下:
package TestSort;
public class HeapSort {
public static void main(String[] args) {
int[] arr = { 1, 2, 5, 3, 6 };
System.out.println("原始数组: ");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
System.out.println("排序后的数组: ");
heapSort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
public static void heapSort(int[] arr) {
int len = arr.length;
// 首先使用一个for循环来将这个数组调整为一个大根堆
for (int i = 0; i < len; i++) {
heapInsert(arr, i);
}
// 通过上边形成了大根堆,然后就是调整,把第一个和最后一个交换,就把最大值放入到了我们数组的最后一个位置。
while (len > 0) {
swap(arr, 0, --len);
heapify(0, len, arr);
}
}
// 插入结点,按照大根堆结构插入
public static void heapInsert(int[] arr, int index) {
while (arr[index] > arr[(index - 1) / 2]) {// 子大于父,就交换
swap(arr, index, (index - 1) / 2);
// 下边往父节点移动
index = (index - 1) / 2;
}
}
// 下边来一个堆调整的函数,heapLen就是堆的长度
public static void heapify(int index, int heapLen, int[] arr) {
int left = index * 2 + 1;
while (left < heapLen) {// 函数最后的跳转方式就是每次跳转到左节点,所以要存在左结点才可以继续;注意,这里不能有等号,因为left是下标,下标能对于那个长度
// 首先找到当前结点的子结点中较大的一个
int maxIndex = 0;
if (left + 1 < heapLen) {// 如果有右节点
// 同时有左结点和右结点就选取大的
maxIndex = (arr[(left)] < arr[left + 1]) ? left + 1 : left;
} else {// 如果没有右结点
maxIndex = left;
}
// 如果当前值大于maxIndex位置值,就交换
if (arr[index] < arr[maxIndex]) {
swap(arr, index, maxIndex);
} else {
break;
}
// 然后是结点同时向下边移动
index = maxIndex;// 只是针对修改的一部分进行继续向下
left = index * 2 + 1;// 每次调转到左结点位置
}
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
控制台打印:
下边也是和上边差不多的堆排序,只是有细微差别,是后期自己重新写了一遍,添加了部分注释:
package sort;
public class HeapSort {
public static void main(String[] args) {
int[] arr = { 1, 2, 5, 3, 6 };
heapSort(arr, 0, arr.length - 1);
for (int i = 0; i < arr.length; i++) {
System.out.print(" " + arr[i] + " ");
}
}
public static void heapSort(int[] arr, int start, int end) {
// 首先将数组变为大根堆
for (int i = 0; i < arr.length; i++) {
heapInsert(arr, i);
}
// 然后把大根堆的堆顶放到大根堆最后一个位置,同时堆的长度减一
int heapLen = arr.length;// 堆的初始长度
while (heapLen > 0) {
swap(arr, 0, --heapLen);
// 然后调整
heapify(arr, heapLen);
}
}
// 加入一个数到数组最后一个位置(原来的数组已经是大根堆),处理之后,还是大根堆
public static void heapInsert(int[] arr, int index) {
// 从当前位置也就是index开始和父结点比对,如果父节点大于该结点,就交换,同时当前结点往父节点移动
// int fatherIndex = (index - 1) / 2;
while ((index - 1) / 2 >= 0 && arr[index] > arr[(index - 1) / 2]) {
swap(arr, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
// 下边是如果有一个数据变化了,也就是堆顶数据变化了,怎么调节这个数组,成为一个大根堆
public static void heapify(int[] arr, int heapLen) {
int index = 0;// 父节点的下标
// 让父节点和子结点中较大的一个比较,如果父节点较小,就交换
while ((index * 2 + 1) < heapLen) {
int maxChild;
if ((index * 2 + 2) >= heapLen) {
maxChild = index * 2 + 1;
} else {
maxChild = arr[index * 2 + 1] > arr[index * 2 + 2] ? (index * 2 + 1) : (index * 2 + 2);
}
if (arr[index] < arr[maxChild]) {
swap(arr, index, maxChild);
}
// else {//没得这个else也可以,但是如果添加了else,就可以少走很多步骤,降低复杂度的常数项
// break;
// }
// 然后移动,当前结点和子结点都往下移动
index = maxChild;
}
}
private static void swap(int[] arr, int index1, int index2) {
int temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
}
控制台: