java实现堆排序

本文详细介绍如何使用Java实现堆排序算法,包括构建大根堆、调整堆结构和完成排序的全过程。通过具体代码示例,展示堆排序的工作原理及其实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
	}
}

控制台:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值