算法实验题8.1 黑箱子问题

★问题描述:
黑箱子是一个数据库,它能存放很多记录,每条记录包含一个整数,它有一个索引值index,它还能处理两种命令:
(1) append x: 将记录x添加到黑箱子中
(2) print: 将索引值加1,然后输出黑箱子里所有记录中第index小的记录,初始时刻黑箱子是空的并且索引值为0.设计实现黑箱子的算法
★实验任务:
对于给定的append运算和print运算组成的命令序列,计算print命令的输出序列
★数据输入:
第1行有1个正整数n(1<=n<=70000)表示命令数,接下来n行每行有一条命令
★结果输出:

将计算出的print运算的输出序列输出


输入示例

15
append 1
print
append 7
append 2
print
append 3
append 6
print
append 9
append 4
print
append 8
append 5
print
append 10


输出示例

1 2 3 4 5



和上次的神谕者。。呵呵呵呵。

神谕者的代码改改估计就可以了。数据结构与算法实验题 10.1 神谕者

不过也可以维护一个第k小的堆

代码等12月2号贴上。


一、最大最小堆

当操作为插入的时候,如果待插入的元素x 比最大堆的元素小,说明第k个最小值可能是最大堆的堆顶,把最大堆的堆顶删除移动到最小堆,那个x插入到最大堆。

当然一开始的时候直接插入最小堆。

然后查询的时候直接输出最小堆堆顶,然后把最小堆堆顶删除并转移到最大堆、

这样做保证最大堆堆顶<最小堆堆顶,所以最小堆堆顶一定是解


#include<cstdio>
const int MAXN=70000+1;
struct heap
{
	int min_tree[MAXN];
	int max_tree[MAXN];
	int min_cur_size;
	int max_cur_size;
	heap(){max_cur_size=min_cur_size=0;}
	void min_matain(int hole)
	{
		int child;
		int temp=min_tree[ hole ];

		for(;( hole <<1 ) <=min_cur_size ; hole=child)
		{
			child= (hole << 1);
			if(child != min_cur_size && min_tree[child + 1 ] < min_tree [child] )
				child++;

			if(min_tree[child] <temp)
				min_tree[hole]=min_tree[child];
			else
				 break;
		}
		min_tree[hole]=temp;
	}

	void max_matain(int hole)
	{
		int child;
		int temp=max_tree[ hole ];

		for(;( hole <<1 ) <=max_cur_size ; hole=child)
		{
			child= (hole << 1);
			if(child != max_cur_size && max_tree[child + 1 ] > max_tree [child] )
				child++;

			if(max_tree[child] >temp)
				max_tree[hole]=max_tree[child];
			else
				 break;
		}
		max_tree[hole]=temp;
	}

	int min_top()
	{
		return min_tree[ 1 ];
	}

	int max_top()
	{
		return max_tree[1];
	}

	void min_pop()
	{
		min_tree[1]=min_tree[min_cur_size--];
		min_matain(1);
	}

	void max_pop()
	{
		max_tree[1]=max_tree[max_cur_size--];
		max_matain(1);
	}

	void min_push(int x)
	{
		int hole=++min_cur_size;
		for(; hole >1 && x < min_tree [(hole >>1)];hole>>=1)
		{
			min_tree[hole] = min_tree [ hole >> 1];
		}
		
		min_tree[hole]=x;
	}

	void max_push(int x)
	{
		int hole=++max_cur_size;
		for(; hole >1 && x > max_tree [(hole >>1)];hole>>=1)
		{
			max_tree[hole] = max_tree [ hole >> 1];
		}
		
		max_tree[hole]=x;
	}
}q;


int main()
{
	 int n,i;  
    scanf("%d",&n);  
    int k=0,temp;  
    char cmd[20];  
    for(i=0;i<n;i++)
    {  
        scanf("%s",cmd);  
        if(cmd[0]=='a')   
        {  
            scanf("%d",&temp);  
			if(i==0)
			{
					q.min_push(temp);
					continue;
			}
			if(temp < q.max_top())
			{
					q.min_push(q.max_top());  
					q.max_pop();
					q.max_push(temp);
			}
			else
				q.min_push(temp);
			
        }  
        else  
        {  
            k++;  
			int kth=q.min_top();		
			q.min_pop();
			printf("%d ",kth);         
			q.max_push(kth);
        }  
    }  
    printf("\n");  
    return 0; 
}

        


二、SBT修改一下。

#include<cstdio>
const int MAXN=200000+10;
struct SBT
{
	int left[MAXN];   //left son
	int right[MAXN]; //right son
	int size[MAXN];   //the num of sons
	int value[MAXN];  //value
	int len;			//length
	int root;
	SBT(){ root=len=0; }

	void right_rotate(int &t)
	{
		int k=left[t];
		left[t]=right[k];
		right[k]=t;
		size[k]=size[t];
		size[t]=size[ left[t] ] + size[ right[t] ] +1;
		t=k;
	}

	void left_rotate(int &t)
	{
		int k=right[t];
		right[t]=left[k];
		left[k]=t;
		size[k]=size[t];
		size[t]=size[left[t]]+size[right[t]]+1;
		t=k;
	}

	void insert(int &t,int v)
	{
		if(!t)
		{
			t=++len;  
			value[t]=v;  
			size[t]=1;  
			left[t]=right[t]=0;
			return; 
		}
		size[t]++;

		if(v < value[t])
			insert(left[t],v);
		else
			insert(right[t],v);

		matain(t);
	}

	void matain(int &t)
	{
		if(size[ left[ left[t] ] ] > size[ right[t] ] )
		{
			right_rotate(t);
			matain(right[t]);
			matain(t);
		}
		else if( size[ right[ left[t] ] ]>size[ right[t] ] )
		{
			left_rotate(left[t]);
			right_rotate(t);
			matain(left[t]);
			matain(right[t]);
			matain(t);
		}
		else if(size[ right[ right[t] ] ]>size[ left[t] ])
		{
			left_rotate(t);
			matain(left[t]);
			matain(t);
		}
		else if(size[ left[ right[t] ] ]>size[ left[t] ])
		{
			right_rotate(right[t]);
			left_rotate(t);
			matain(left[t]);
			matain(right[t]);
			matain(t);
		}
	}

	int select(int t,int k)
	{
		if(k==size[left[t]]+1)
			return value[t];
		if(k<=size[left[t]])
			return select(left[t],k);
		else
			return select(right[t],k-size[left[t]]-1);
	}
}sbt;

int main()
{
	int n,i;
	scanf("%d",&n);
	int k=0,temp;
	char cmd[20];
	while(n--)
	{
		scanf("%s",cmd);
		if(cmd[0]=='a')	
		{
			scanf("%d",&temp);
			sbt.insert(sbt.root,temp);
		}
		else
		{
			k++;
			printf("%d ",sbt.select(sbt.root,k));			
		}
	}
	printf("\n");
	return 0;
}


三、划分树修改。。

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXM=20;
const int MAXN=70000+10;
int data[MAXM][MAXN], num[MAXM][MAXN], sorted[MAXN];

struct node
{
	int kind;	//kind=0 代表插入 kind=1则为查询
}p[MAXN];

void Build(int depth, int L, int R) {
	if (L == R)
		return;
	int same, mid, i, left, right;
	mid = (L + R) >> 1;
	same = mid - L + 1;
	left = L;
	right = mid + 1;
	for (i = L; i <= R; i++) {
		if (data[depth][i] < sorted[mid])
			same--;
	}
	//same用来标记和中间值val_mid 相等的,且分到左孩子的数的个数。
	for (i = L; i <= R; i++) {
		if (data[depth][i] < sorted[mid])
			data[depth + 1][left++] = data[depth][i];
		else if (data[depth][i] == sorted[mid] && same) {
			data[depth + 1][left++] = data[depth][i];
			same--;
		} else
			data[depth + 1][right++] = data[depth][i];
		num[depth][i] = num[depth][L - 1] + left - L;      
		//num记录元素所在区间的当前位置之前进入左孩子的个数
	}
	Build(depth + 1, L, mid);
	Build(depth + 1, mid + 1, R);
}

int findk(int L, int R, int x, int y, int k,int depth) {
	if (L == R)
		return data[depth][L];

	int mid, left, temp;
	mid = (L + R) >> 1;
	left = num[depth][y] - num[depth][x - 1];
	temp = num[depth][x - 1] - num[depth][L - 1];
	if (left >= k)
		return findk( L, mid, L + temp, L + temp + left - 1, k,depth + 1);
	else {
		k -= left;
		temp = x - L - temp;
		left = y - x + 1 - left;
		return findk( mid + 1, R, mid + temp + 1, mid + temp + left, k,depth + 1);
	}
}

int main() {

	int n,i;
	int len=0,temp;
	scanf("%d", &n);
	char cmd[20];
	for(i=0;i<n;i++)
	{
		scanf("%s",cmd);
		if(cmd[0]=='a')
		{
			scanf("%d",&temp);
			p[i].kind=0;	
			len++;
			sorted[len] = data[0][len] = temp;
		}
		else if(cmd[0]=='p')
		{
			p[i].kind=1;
		}
	}

	sort(sorted + 1, sorted + len + 1);
	Build(0, 1, len);
	
	int cnt=0;			//统计当前元素个数
	int k=0;
	for(i=0;i<n;i++)
	{
		if(p[i].kind==0)
			cnt++;
		else 		
		{
			k++;
			printf("%d ",findk(1,len,1,cnt,k,0));	
		}
	}
	printf("\n");
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值