end.
因为
二叉排序树的左
子树若不为空则左子树的所有结点的值均小于它的
根结点的值,而右子树若不为空,则右子树的所有结点的值均不小大于它的根结点的值,根据这个性质
查找算法如下(Pascal):
else if x=p^.w then searchtr:=true
else if x
else searchtr:=searchtr(x,p^.right);
end;
begin
first:=nil;k:=true;
for i:=1 to 8 do maketr(a[i],first);
write('want find data x:');read(x);
if searchtr(x,first) then writeln('yes') else writeln('No');
end.
以上讲的查找方法基于比较的,查找效率依赖比较次数,其实理想的查找希望不经比较,一次存取便能得到所查记录,那就必须在记录的存储位置和它的关键字之间建立一个确定的对应关系f,这样查找k时,只要根据这个对应关系f找到
给定值k的像f(
hash)函数。按这种思想建立的表叫
哈希表(也叫散列表)。哈希表存取方便但存储时容易冲突(
collision):即不同的关键字可以对应同一哈希地址。如何确定
哈希函数和解决冲突是关键。
直接定址法:H(k)=k 或H(k)=a*k+b(
线形函数)
如:关键字如下:若
哈希表长为100则可取中间两位10
进制数作为哈希地址。
折叠法:将关键数字分割成位数相同的几部分(最后一部分的位数可以不同)然后取几部分的叠加和(舍去进位)作为哈希地址。
除留
余数法:取关键字被某个不大于表长m的数p除后所得的余数为哈希地址。
H(k)=k mod p p<=m
⒉处理冲突的方法
0<=Hi<=n-1),即在处理冲突时若得到的另一个哈希地址H1仍发生冲突,再求下一地址H2,若仍冲突,再求H3...。怎样得到Hi呢?
开放定址法:Hi=(H(k)+di) mod m (H(k)为
哈希函数;m为
哈希表长;di为增量序列)
当di=1,2,3,... m-1 时叫
线性探测再散列。
当di=1,-1,2,-2,3,-3,...,k,-k时叫二次探测再散列。
例:长度为11的哈希表关键字分别为17,60,29,哈希函数为H(k)=k mod 11,第四个记录的关键字为38,分别按上述方法添入哈希表的地址为8,4,3(
随机数=9)。
再哈希法:Hi=RHi(key) i=1,2,...,k,其中RHi均为不同的
哈希函数。
链地址法:这种方法很象
基数排序,相同的地址的关键字值均链入对应的
链表中。
建立公益区法:另设一个溢出表,不管得到的哈希地址如何,一旦发生冲突,都填入溢出表。
例:如下一组关键字按哈希函数H(k)=k mod 13和线性探测处理冲突所得的哈希表a[0..15]:
当给定值k=84,则首先和a[6]比在依次和a[7],a[8]比结果a[8]=84查找成功。
当给定值k=38,则首先和a[12]比,再和a[13]比,由于a[13]没有,查找
不成功,表中不存在关键字等于38的记录。
查找第k小元素
查找第k小元素即在n个元素中(未排序)找到第k小的元素。方法同
快速排序,采用递归方式。
程序如下(Pascal):
program kspv;
const n=7;
type
arr=array[1..n] of integer;
var
b:arr;
i,k:integer;
function p(s,t:integer):integer;
var i,j,t1,x:integer;
begin
i:=s;j:=t;x:=b[i];
repeat
while (b[j]>=x) and (j>i) do j:=j-1;
if j>i then begin t1:=b[i]; b[i]:=b[j];b[j]:=t1;end;
while (b[i]<=x) and (i
if i
until i=j;
b[i]:=x;
p:=i;
end;
function find(s,t,k:integer):integer;
var p1,q:integer;
begin
if s=t then find:=b[s] else
begin
p1:=p(s,t);
q:=p1-s+1;
if k<=q then find:=find(s,p1,k) else find:=find(p1+1,t,k-q);
end;
end;
begin
for i:=1 to n do read(b[i]);
readln;
write('input k:');read(k);
write('output data:');
writeln('kthsmall:=',find(1,n,k));
end.