堆,优先队列,二叉搜索树,平衡二叉树与并查集: 加工并存储数据的数据结构

加工并存储数据的数据结构

    • 堆的时间复杂度:
    • 堆的实现
    • 标准库优先队列
    • 需要用到优先队列的题目
        • Expedition(POJ 2431)
        • Fence Repair
    • 二叉搜索树
        • 性质
        • 二叉搜索树的复杂度
        • 二叉搜索树的实现:
        • 标准库中的二叉搜索树
    • 平衡二叉树
    • 并查集
        • 并查集例题:

能够高效的利用二叉树解决 类似于优先队列操作的问题的数据结构叫 堆

优先队列:

  1. 只能从队尾插入元素,从队首删除元素。
  2. 但是它有一个特性,就是队列中最大的元素总是位于队首,所以出队时,并非按照先进先出的原则进行,而是将当前队列中最大的元素出队。
  3. 这点类似于给队列里的元素进行了由大到小的顺序排序。元素的比较规则默认按元素值由大到小排序,可以重载“<”操作符来重新定义比较规则。

堆:

   1
/     \
2     4 
/ \    / \
7  8  5
  • 推最重要的性质是儿子的值一定不小于父亲的值,除此之外,数的节点从上到下,从左至右的顺序紧凑排列的。
  • 插入一个数值:首先在堆的末尾插入数值,然后不断向上提升直到没有大小颠倒为止。
  • 取出一个最小的数值(并且删除):首先把堆的最后一个节点的数值复制到根节点上,并且删除最后一个节点。然后不断向下交换直到没有大小颠倒为止,在向下交换的过程中,如果有两个儿子,选择数值较小的儿子进行交换。

堆的时间复杂度:

堆的两种操作所花的时间都与数的深度成正比,如果一共有n个元素,每个操作进行都能在 O(logn)的时间内完成。

堆的实现

vector<int> heap;
void push(int x){
   
	heap.push_back(x);
	int i=heap.size();
	while(i > 0){
   
		int p=(i-1)/2;
		if(heap.at(p) >= x) break;
		heap.at(i) = heap.at(p);
		i = p;
	}
	heap.at(i)=x;
}
int pop(){
   
	//最小值
	if(heap.size()==0)  return -1;
	int ret = heap.at(0);
	int x = heap.back();
	heap.erase(heap.cend()-1);
	int i=0;
	while(i*2+1 < heap.size()){
   
      int l=i*2+1,r=l+1;
      if(r<heap.size() && heap.at(r) < heap.at(l)) l=r;
      //如果没有大小颠倒则退出
      if(x <= heap.at(l)) break;

      //把儿子的数值提升上来
      heap.at(i) = heap.at(l);
      i = l;
	}
	heap.at(i) = x;
	return  ret;
}

标准库优先队列

C++中,STL里的 priority_queue就是优先队列 ,但是取出数值时得到的是最大值。

int main()
{
   
	//声明并执行默认初始化
	priority_queue<int> pque;

	//插入元素
	pque.push(3);
	pque.push(5);
	pque.push(1);
	while(!pque.empty()){
   
		cout<<pque.top()<<ends;
		pque.pop();
	}
	return 0;

}

堆,优先队列,二叉搜索树,平衡二叉树与并查集: 加工并存储数据的数据结构_第1张图片

需要用到优先队列的题目

Expedition(POJ 2431)

描述:你需要驾驶一辆卡车行驶 L 单位距离。 最开始时, 卡车上有 P 单位 的汽油。 卡车每开 1 单位距离需要消耗 1 单位的汽油 。 如果在途中车上的汽油耗尽 , 卡车就无法继续前行, 因而无法到达终点。 在途中一共有 N个加油站。 第 i 个加油站在距离起点 Ai单位距离的地方,最多可以给卡车加 Bi单位汽油,假设卡车的燃料箱的容量是无限大的 , 无论加多少油都没问题 。 那么请问卡车能否到达终点? 如果可以,最少需要加多少次油?如果可以到达终点,输出最少的加油次数,否则输出 -1.。

限制条件:

  • 1 <= N <= 10000
  • 1 <= L <= 1000000, 1<= P <=1000000
  • 1 <= Ai < L , 1 <= Bi <=100

题解:由于加油站的数量N很大,必须想一个高效的算法。
思路:”我们在达到加油站时,就获得了一次在之后的任何时候加 Bi单位油的权力 “,这样的思路,我们将现有的油耗尽,添加已经经历过的加油站所能加的油量,存入优先队列,以从大到小的顺序,保证加油最小次数。

代码:


int Solve(int N,int L,int P,const vector<int> &A,const vector<int> &B){
   
	// 1.遍历全部途中的加油站,如果当前存放油量大于其位置,就添加该加油站点能加的油存入优先队列中
	// 2.油空了   @1:如果优先队列也是空的,则无法到达终点  @2:否则取出加油。
	
	
	int res = 0;
	priority_queue<int> pque;
	for (int i = 0; i !=N; ++i) {
   
		if(P < A.at(i) ){
   
			if(pque.size() 

你可能感兴趣的:(程序设计(算法与数据结构篇),算法,二叉树,队列,树堆,数据结构)