算法導論隨筆(二)

算法導論隨筆(二)

手動建堆


  • 做爲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

ios

  • 經典題,求出序列前奇數個數的中位數,可使用平衡樹來作,不過更簡單的是用兩個優先隊列。大根堆存前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;
}
相關文章
相關標籤/搜索