堆排序及模拟堆代码模板

常用算法代码模板总结

目录

基础知识

堆排序代码

练习题目:模拟堆


基础知识

这里我们从数组下标1开始作为第一个数的存放位置,不从下标0开始(当然从下标0开始也是可以的),这样方便理解这个数的左右子节点的位置。

大根堆:父节点大于左右子节点。

小根堆:父节点小于左右子节点。

以下标1存放数对应的左右子节点位置:父节点下标x,左子节点下标2x,右子节点下标2x+1。

堆排序代码(升序降序看注释)

import java.util.Scanner;

public class Main {
	static int[] nums = new int[100010];
	static int n;

	// 小根堆构造:x的左节点下标2x,右节点下标2x+1
	public static void Down(int x) {// 重点是构造堆的过程
		int t = x;
		// 下面的代码默认是升序排序的,如果想降序排序,只需要修改if条件判断
		// 降序的思路也很简单,就是谁大放上面
		if (2 * x <= n && nums[2 * x] < nums[x]/* 降序nums[2 * x] > nums[x] */) {// 如果左节点存在且左节点小于父节点
			t = 2 * x;// 下标移动到左节点
		}
		if (2 * x + 1 <= n && nums[2 * x + 1] < nums[t]/* nums[2 * x + 1] > nums[t] */) {// 如果右节点存在且右节点小于父节点和左节点中较小的数
			t = 2 * x + 1;// 下标移动到右节点
		}
		if (t != x) {// t!=x说明父节点不是最小的,将子节点和父节点交换
			int temp = nums[t];
			nums[t] = nums[x];
			nums[x] = temp;
			Down(t);// 继续对这个节点进行移动
		}
	}

	public static void main(String args[]) {
		Scanner input = new Scanner(System.in);

		n = input.nextInt();// n表示需要排序的个数

		for (int i = 1; i <= n; i++) {// 接收数据
			nums[i] = input.nextInt();
		}

		for (int i = n; i > 0; i--)// 可以将i的初始值定为n/2
			Down(i);

		int count = n;
		int[] result = new int[n];// 记录结果

		for (int i = 1; i <= count; i++) {
			result[i - 1] = nums[1];
			nums[1] = nums[n--];// 每次输出完最小的那个数,然后更新根节点刷新最小的值
			Down(1);
		}
		for (int i = 0; i < count; i++) {
			System.out.print(result[i] + " ");
		}
	}
}

练习题目:模拟堆

堆排序及模拟堆代码模板_第1张图片

 

import java.util.Scanner;

public class Main {
	static int[] nums = new int[100010];// 存放数
	static int[] Index = new int[100010];// 记录插入顺序,Index[i]表示第i个插入的数在nums中的下标
	static int[] ToIndex = new int[100010];// 存放“记录插入顺序”的数的下标,ToIndex[i]表示在nums中下标为i的数在Index中对应的下标
	static int count = 0;// 记录实际存放数的个数

	public static void Swap(int a, int b) {
		int temp = nums[a];// 交换值
		nums[a] = nums[b];
		nums[b] = temp;

		temp = Index[ToIndex[a]];// 交换数对应的插入顺序
		Index[ToIndex[a]] = Index[ToIndex[b]];
		Index[ToIndex[b]] = temp;

		temp = ToIndex[a];// 交换反向找到插入顺序的数
		ToIndex[a] = ToIndex[b];
		ToIndex[b] = temp;
	}

	public static void Down(int x) {
		int t = x;
		if (2 * x <= count && nums[2 * x] < nums[t])
			t = 2 * x;
		if (2 * x + 1 <= count && nums[2 * x + 1] < nums[t])
			t = 2 * x + 1;
		if (t != x) {
			Swap(t, x);
			Down(t);
		}
	}

	public static void Up(int x) {
		while (x / 2 != 0 && nums[x] < nums[x / 2]) {// 如果x存在父节点且父节点大于当前节点
			Swap(x, x / 2);
			x = x / 2;// 跑到父节点的位置继续执行
		}
	}

	public static void main(String args[]) {
		Scanner input = new Scanner(System.in);
		int time = input.nextInt();
		int m = 0;
		for (int i = 0; i < time; i++) {
			String str = input.next();
			if (str.equals("I")) {
				int x = input.nextInt();
				count++;
				m++;
				Index[m] = count;// 存放这个数对应的插入顺序
				ToIndex[count] = m;// 存放反向查找到这个数对应的插入顺序的下标
				nums[count] = x;
				Up(count);
			}
			if (str.equals("PM")) {
				System.out.println(nums[1]);
			}
			if (str.equals("DM")) {
				Swap(1, count);// 将第一个数和最后一个数交换
				count--;// 数的总数减一
				Down(1);
			}
			if (str.equals("D")) {
				int k = input.nextInt();
				k = Index[k];// 获取第k个插入的数在nums中的下标
				Swap(k, count);// 和末尾元素交换
				count--;
				Up(k);
				Down(k);

			}
			if (str.equals("C")) {
				int k = input.nextInt();
				int x = input.nextInt();
				k = Index[k];
				nums[k] = x;// 更改值
				Up(k);
				Down(k);
			}
		}
	}
}

你可能感兴趣的:(数据结构与算法,java,排序算法,链表)