《算法笔记》9.7 堆

一.定义
大顶堆:根结点最大的完全二叉树;
小顶堆:根结点最小的完全二叉树;
(以下以大顶堆为例)
用数组的形式定义堆:

const int maxn = 100;
int n;
int heap[maxn];

二.基本操作
1.建堆:
a.向下调整:(将当前结点与它的左右孩子节点比较,按照大小关系交换,若交换则继续与孩子节点比较)

void downAdjust(int low, int high) { 
// low 是欲调整节点的数组下标,high 为堆最后一个元素 
	int i = low, j = i * 2; // i 为欲调整结点,j 为左孩子 
	while(j <= high) { //如果 i 的孩子结点存在 
		if(j + 1 <= high && heap[j + 1] > heap[j]) j = j + 1;
		if(heap[j] > heap[i]) {
			swap(heap[j], heap[i]);
			i = j;
			j = i * 2;
		}
		else break;
	}
}

b.建堆:(欲调整的结点从数组下标最大的非叶结点开始)
完全二叉树:1 ~ n/2:非叶子节点;n/2+1 及之后是叶子节点(共 n/2 个)

void createHeap() {
	for(int i = n / 2; i >= 1; i--) downAdjust(i, n);
}

2.删除堆顶元素:

void deleteTop() {
	heap[1] = heap[n--];
	downAdjust(1, n);
}

3.添加一个元素:
把想要添加的元素放在数组最后,然后进行向上调整;
a.向上调整:

void uoAdjust(int low, int high) {
	// low 一般设置为 1,high 表示欲调整结点的数组下标
	int i = high, j = i / 2;
	while(j >= low) {
		if(heap[j] < heap[i]) {
			swap(heap[j], heap[i]);
			i = j;
			j = i / 2;
		}
		else break;
	} 
}

b.添加元素:

void insert(int x) {
	heap[++n] = x;
	upAdjust(1, n);
}

4.堆排序
将堆顶元素与当前最后一个元素交换,然后进行排序(堆顶元素固定);

void heapSort() {
	createHeap();
	for(int i = n; i > 1; i--) {
		swap(heap[i], heap[1]);
		downAdjust(1, i - 1);
	}
}

三.题目
1.PAT A1098
思路:
先判断是不是 insertSort ,如果不是则一定是 heapSort;

注意:
1).判断两数组相等不能是 A == B;
2).如何输出下一个数组:先判断是否相等(flag = true),在主函数体又进行一遍后,如果相等(flag = true)则输出数组;
3).第一次排完序后记得把数组还原;

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 110;
int n;
int ori[maxn];
int tempori[maxn];
int changed[maxn];

bool isSame(int A[], int B[]) {
	for(int i = 1; i <= n; i++) {
		if(A[i] != B[i]) return false;
	}
	return true;
}

void showArray(int A[]) {
	for(int i = 1; i <= n; i++) {
		printf("%d", A[i]);
		if(i < n) printf(" ");
	}
	printf("\n");
}

void downAdjust(int low, int high) {
	int i = low, j = i * 2;
	while(j <= high) {
		if(j + 1 <= high && ori[j] < ori[j + 1]) j = j + 1;
		if(ori[j] > ori[i]) {
			swap(ori[j], ori[i]);
			i = j;
			j = i * 2;
		} 
		else break;
	}
}

void createHeap() {
	for(int i = n / 2; i >= 1; i--) downAdjust(i, n);
}

void heapSort() {
	createHeap();
	bool flag = false;
	for(int i = n; i > 1; i--) {
		if(i != n && isSame(ori, changed)) flag = true;
		swap(ori[1], ori[i]);
		downAdjust(1, i - 1);
		if(flag) {
			showArray(ori);
			return;
		}
	}
}

bool insertSort() {
	bool flag = false;
	for(int i = 2; i <= n; i ++) {
		if(i != 2 && isSame(ori, changed)) flag = true;
		sort(ori, ori + i + 1);
		if(flag == true) return true;
	}
	return false;
}

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) {
		scanf("%d", &ori[i]);
		tempori[i] = ori[i];
	}
	for(int i = 1; i <= n; i++) scanf("%d", &changed[i]);
	if(insertSort()) {
		printf("Insertion Sort\n");
		showArray(ori);
	}
	else {
		printf("Heap Sort\n");
		for(int i = 1; i <= n; i++) ori[i] = tempori[i];
		heapSort();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值