算法导论随笔(二)

2021-03-07 02:30

阅读:349

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

算法导论随笔(二)

手动建堆


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

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

  • 基本操作:维持某节点的堆性质
void heapify(int o) //维护i号节点的堆性质
{
    while (1)
    {
        int ls = o 

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

  • 修改某节点的值
void modify(int o, int v) //内部函数,将mh[o]改为v
{
    if ((v  1 && (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 
#include 
#include 
#include 
#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 && (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  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


评论


亲,登录后才可以留言!