Treap:查找第k大元素

线段树、树状数组虽然查找第k大元素很方便,树状数组代码更是相当短。但是,两者必须要求数据为一定范围内的整数,否则就不能用区间和来查找第k大元素了。所以,学习用BST查找第k大元素是很有必要的。下面给出代码,Pascal版本的Treap查找第k大元素,写得很丑。

{
小根堆实现,支持插入、删除、findkth等操作,其它的什么findmin什么的应该不难。

主要是要维护一个size和cnt域,另外每次旋转啊插入啊删除啊都要更新一下size域

以编程简单的treap也要写一百多行,当然可以精简一些代码,如果是C/C++应该更短

2011-08-12 22:45
}
const
  INF=19930317;

var
  t:array[0..1000000] of record x,aux,l,r,size,cnt:longint end;
  i,j,k,root,x,n,m,size:longint;

procedure modify(i:longint);
begin
  t[i].size:=t[t[i].l].size+t[t[i].r].size+t[i].cnt;
end;


procedure left(var i:longint);
var
  j:longint;
begin
  j:=t[i].r;
  t[i].r:=t[j].l;
  t[j].l:=i;
  modify(i);
  i:=j;
  modify(i);
end;

procedure right(var i:longint);
var
  j:longint;
begin
  j:=t[i].l;
  t[i].l:=t[j].r;
  t[j].r:=i;
  modify(i);
  i:=j;
  modify(i);
end;



procedure insert(var i:longint; x:longint);
begin
  if i=0 then
  begin
    inc(size);
    i:=size;
    t[size].size:=1;
    t[size].cnt:=1;
    t[size].l:=0;
    t[size].r:=0;
    t[size].aux:=random(INF);
    t[size].x:=x;
  end
  else begin
    if t[i].x=x then
    begin
      inc(t[i].cnt);
    end
    else if x<t[i].x then
    begin
      insert(t[i].l,x);
      if t[t[i].l].aux<t[i].aux then
        right(i);
    end
    else if x>t[i].x then
    begin
      insert(t[i].r,x);
      if t[t[i].r].aux<t[i].aux then
        left(i);
    end;
    modify(i);
  end;
end;


procedure delete(var i:longint; x:longint);
begin
  if i=0 then
    exit;
  if x<t[i].x then
    delete(t[i].l,x)
  else if x>t[i].x then
    delete(t[i].r,x)
  else begin
    if t[i].cnt>1 then
      dec(t[i].cnt)
    else if t[i].l=0 then
      i:=t[i].r
    else if t[i].r=0 then
      i:=t[i].l
    else if t[t[i].l].aux < t[t[i].r].aux then
         begin
           right(i);
           delete(t[i].r,x);
         end
         else begin
           left(i);
           delete(t[i].l,x);
         end
  end;
  if i<>0 then
    modify(i);
end;

function findkth(i,k:longint):longint;
begin
  if k<=t[t[i].l].size then
    exit(findkth(t[i].l,k));
  if k<=t[t[i].l].size+t[i].cnt then
    exit(t[i].x);
  exit(findkth(t[i].r,k-t[t[i].l].size-t[i].cnt));
end;

begin
  randomize;
  t[0].aux:=INF;
  readln(n);
  for i:=1 to n do
  begin
    read(x);
    insert(root,x);
  end;
  readln(m);
  for i:=1 to m do
  begin
    read(x);
    writeln(findkth(root,x));
  end;
  readln(m);
  for i:=1 to m do
  begin
    read(x);
    delete(root,x);
  end;
  readln(m);
  for i:=1 to m do
  begin
    read(x);
    writeln(findkth(root,x));
  end;
end.

posted on 2011-08-14 23:29  oa414  阅读(778)  评论(0编辑  收藏  举报

导航