码迷,mamicode.com
首页 > 编程语言 > 详细

算法导论随笔(二)

时间:2021-01-15 12:10:01      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:lse   def   优先   https   bre   小根堆   收获   大根堆   scan   

算法导论随笔(二)

手动建堆


  • 作为stl选手,对于手写堆接触较少,不过熟悉建堆的过程还是有不少收获的。

  • 堆的载体:一个长度为n的数组

  • 基本操作:维持某节点的堆性质
void heapify(int o) //维护i号节点的堆性质
{
    while (1)
    {
        int ls = o << 1;
        int rs = o << 1 | 1;
        int mx = mh[o];
        int mi = o;
        if (ls <= n1 && (mh[ls] < mx) ^ fl)
        {
            mx = mh[ls];
            mi = ls;
        }
        if (rs <= n1 && (mh[rs] < mx) ^ fl)
        {
            mx = mh[rs];
            mi = rs;
        }
        if (mi != o)
        {
            sw(mh[o], mh[mi]);
            o = mi;
        }
        else
        {
            break;
        }
    }
}

  • 建堆:
for (int i = (n1 >> 1); i >= 1; --i)
{
    heapify(i);
}

  • 修改某节点的值
void modify(int o, int v) //内部函数,将mh[o]改为v
{
    if ((v < mh[o]) ^ fl)
    {
        mh[o] = v;
        while (o > 1 && (mh[o] < mh[o >> 1]) ^ fl)
        {
            sw(mh[o], mh[o >> 1]);
            o >>= 1;
        }
    }
    else
    {
        mh[o] = v;
        heapify(o);
    }
}

应用:手写优先队列 luogu1168

  • 经典题,求出序列前奇数个数的中位数,可以使用平衡树来做,不过更简单的是用两个优先队列。大根堆存前k / 2 + 1小的数,小根堆存剩下的k / 2个数,每次输出大根堆顶就可以。

应用代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define INF 2147483647

using namespace std;

int aa[100005], n;

void sw(int& a, int& b)
{
	int t = a;
	a = b;
	b = t;
}

struct minh
{
	int mh[100005];
	bool fl = false; //默认小根堆
	int n1 = 0;

	void set(int f)  //设置大小根堆
	{
		bool r = f ^ fl;
		fl = f;
		if (r)		//如果变化则更新堆
		{
			for (int i = (n1 >> 1); i >= 1; --i)
			{
				heapify(i);
			}
		}
	}

	void heapify(int o) //维护i号节点的堆性质
	{
		while (1)
		{
			int ls = o << 1;
			int rs = o << 1 | 1;
			int mx = mh[o];
			int mi = o;
			if (ls <= n1 && (mh[ls] < mx) ^ fl)
			{
				mx = mh[ls];
				mi = ls;
			}
			if (rs <= n1 && (mh[rs] < mx) ^ fl)
			{
				mx = mh[rs];
				mi = rs;
			}
			if (mi != o)
			{
				sw(mh[o], mh[mi]);
				o = mi;
			}
			else
			{
				break;
			}
		}
	}

	void modify(int o, int v) //内部函数,将mh[o]改为v
	{
		if ((v < mh[o]) ^ fl)
		{
			mh[o] = v;
			while (o > 1 && (mh[o] < mh[o >> 1]) ^ fl)
			{
				sw(mh[o], mh[o >> 1]);
				o >>= 1;
			}
		}
		else
		{
			mh[o] = v;
			heapify(o);
		}
	}

	int top()		//查询
	{
		return mh[1];
	}

	void push(int v)  //插入
	{
		mh[++n1] = fl ? -INF : INF;
		modify(n1, v);
	}

	int pop()	//带返回值的pop
	{
		int v = -INF;
		if (n1)
		{
			v = mh[1];
			mh[1] = mh[n1--];
			heapify(1);
		}
		return v;
	}

	int size()  //堆大小
	{
		return n1;
	}

} q1, q2;

int main()
{
	q1.n1 = q2.n1 = 0;
	q1.set(0); 
	q2.set(1);
	
	scanf("%d", &n);

	int xx;
	scanf("%d", &xx);
	printf("%d\n", xx);
	q2.push(xx);
	for (int i = 2; i <= n; ++i)
	{
		scanf("%d", &xx);
		if (q1.size() == q2.size())
		{
			int tmp = q1.top();
			if (tmp < xx)
			{
				q2.push(tmp);
				q1.pop();
				q1.push(xx);
			}
			else
			{
				q2.push(xx);
			}
			printf("%d\n", q2.top());
		}
		else
		{
			int tmp = q2.top();
			if (tmp > xx)
			{
				q1.push(tmp);
				q2.pop();
				q2.push(xx);
			}
			else
			{
				q1.push(xx);
			}
		}
	}
	return 0;
}

算法导论随笔(二)

标签:lse   def   优先   https   bre   小根堆   收获   大根堆   scan   

原文地址:https://www.cnblogs.com/int-me-X/p/14280006.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!