C++ 数据结构-堆

堆--一种可被视为完全二叉树的结构,实现有多种方法





(一)  C++ STL - 优先队列实现

1.首先写好队列头文件

#include


2.定义一个int型、值小的数优先级高(先出队列)的队列-----小根堆

*最后的'' 与‘>’间注意留空格

priority_queue, greater > a;
大根堆的定义:
priority_queue > a;
//priority_queue, less > a;


3.操作:

往堆中加一个元素:

a.push(x);
弹出堆顶元素:

a.pop();
访问堆顶元素:

a.top();
堆的大小:a.size()

判断堆是否为空:a.empty();


4.一个经典的栗子:合并果子

题目描述

在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。

每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。

因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。

例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。

输入格式:

输入包括两行,第一行是一个整数n(1<=n<=10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1<=ai<=20000)是第i种果子的数目。

输出格式:

输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于2^31。

输入样例:
3 
1 2 9 
输出样例:
15










 我的代码:


#include 
#include 
using namespace std;

priority_queue, greater > a;
int n, t, ans, x, y;

int main() {
	cin >> n;
	for(int i=1; i<=n; i++) {
		cin >> t;
		a.push(t);
	}
	for(int i=1; i<=n-1; i++) {     // n个果子 合并n-1次  
		x = a.top();
		a.pop();
		y = a.top();
		a.pop();	        //合并两堆成为新的一堆 
		a.push(x+y);
		ans += x+y;
	}
	cout << ans << endl;
	return 0;
}

(二)自定义结构体-数组实现

在写堆之前,首先要了解堆的性质:

设(从1存储的)数组heap,元素个数为heap_size; 


- heap[1]表示堆顶;

- 如果一个有中间结点是i,那么它的左孩子的下标就是2*i,右孩子的下标就是2*i+1,父亲是2*i

- 如果一个结点i,1 <= i <= heap_size/2  那么它有孩子;  heap_size/2 < i <= heap_size 则结点i为叶子结点


小根堆:heap[i/2] <= heap[i];

大根堆:heap[i/2] >=heap[i];


下面以小根堆讨论:

put()函数:在最后一个位置加入元素,循环与父结点比较,若小于父结点则互换,直到大于等于父结点或到了根结点

get()函数:取走堆顶端元素,将最后一个元素覆盖根,循环与孩子比较,与左右(二或一个)孩子中较小的互换,直到小于等于孩子或到了叶子结点



合并果子用这种方法

代码(觉得不够简洁):

#include 
#include        //INT_MAX
using namespace std;

struct Heap {
	int heap_size;
	int a[10001];
	bool empty(void) const {
		if(heap_size == 0) return true;
		return false;
	}
	void put(int x) {
		int index = ++ heap_size;
		a[index] = x;
		while(true) {
			if(index == 1) break;
			if(a[index] < a[index/2]) {
				swap(a[index], a[index/2]);
				index /= 2;
			} else break;
		}
	}
	int get(void) {
		int rtn = top();
		int index = heap_size --;
		a[1] = a[index];
		a[index] = 0;
		index = 1;
		while(index * 2 <= heap_size) {
			int tmpx = a[2*index], tmpy = INT_MAX;
			if(2*index+1 <= heap_size) tmpy = a[2*index+1];
			if(tmpx < tmpy) {
				if(a[index] > a[index*2]) {
					swap(a[index], a[index*2]);
					index *= 2;
				} else if(a[index] > tmpy) {
					swap(a[index], a[index*2+1]);
					index = index * 2 + 1;
				} else break;

			} else {
				if(a[index] > a[index*2+1]) {
					swap(a[index], a[index*2+1]);
					index = 2*index + 1;
				} else if(a[index] > tmpx) {
					swap(a[index], a[index*2]);
					index *= 2;
				} else break;
			}
		}
		return rtn;
	}
};

Heap a;
int n, t;
int ans;

int main() {
	cin >> n;
	for(int i=1; i<=n; i++) {
		cin >> t;
		a.put(t);
	}
	for(int i=1; i<=n-1; i++) {
		int x, y;
		x = a.get();
		y = a.get();
		a.put(x+y);
		ans += x+y;
	}
	cout << ans << endl;
	return 0;
}


2018年2月重构代码-小根堆:

#include 
#include 
using namespace std;

struct Heap{ //小根堆 
	int a[100010];
	int size, end;
	Heap() {size = 0; fill(a+1, a+100000, 1e9);}
	int top() {
		return a[1];
	}
	void down(int x) {
		int l=x*2, r = x*2+1;
		if(a[l] < a[x] || a[r] < a[x]) {
			if(a[l] < a[r]) {
				swap(a[l], a[x]);
				down(l);
			}else {
				swap(a[r], a[x]);
				down(r);
			}
		}
	}
	void up(int K) {
		while(K > 1 && a[K] < a[K>>1]) {
			swap(a[K], a[K>>1]);
			K >>= 1;
		}
	}
	int insert(int v) {
		a[++size] = v;
		up(size);
	}
	int pop() {
		a[1] = a[size];
		a[size] = 1e9;
		down(1);
	}
}; 

int main() {
	Heap h;
	int n, tmp;
	cin >> n;
	for(int i=n; i; i--) {
		cin >> tmp;
		h.insert(tmp);
	} 
	for(int i=1; i<=n; i++) {
		cout << h.top() << ' ';
		h.pop();
	}
	return 0;
}


重构×3

struct PriorityQueue { //小根堆
	int A[100010];
	int size;
	bool empty() {
		return !size;
	}
	void push(int x) {
		int i = ++size;
		while(i>>1) {
			if(x >= A[i>>1]) break;
			A[i] = A[i>>1];
			i >>= 1;
		}
		A[i] = x;
	}
	int top() {
		if(empty()) return -1e9;
		return A[1];
	}
	int pop() {
		int res = A[1], x = A[size--];
		int i = 1;
		while((i<<1) <= size) {
			int miv = i<<1;
			if((i<<1|1) <= size && A[miv] > A[i<<1|1])
				miv = i<<1|1;
			if(A[miv] >= x) break;
			A[i] = A[miv];
			i = miv;
		}
		A[i] = x;
		return res;
	}
} heap;


(%二叉堆-Binary_Heap%!)

你可能感兴趣的:(C++ 数据结构-堆)