讨论算法(100分)

  • 主题发起人 主题发起人 barton
  • 开始时间 开始时间
B

barton

Unregistered / Unconfirmed
GUEST, unregistred user!
Delphi中似乎不太讲究算法的精妙性,本身提供的算法大部分情况下已经足够。可是如果
象写服务器之类的系统对算法要求颇高,特别是线程较多的服务器上。如果原先需要多个
时间片上解决的任务能够在一个时间片上完成,将会大大提高服务器性能。例如搜索。
我想提出两个算法大家讨论一下。
一、多层哈希。哈希函数多带一个参数,即级别。当前一级哈希结果相同时,如果仍有冲
突再计算下一级。这样相当于用另一个哈希表解决上一级哈希表中的冲突。如果本级哈希
表成员中无冲突,则表中是成员地址;如果发现冲突则表中是下一级哈希表的地址。例如
字符串,每四个字符构成一级哈希,这样可以直接按整数来比较。
二、双二叉平衡树。一组成员建立两棵平衡二叉树。有必要吗?如果成员结构及关键字都
可自定义,则有必要。一棵树(实体树)按成员关键字建立,另一棵(索引树)按成员实际地
址建立。查找时按实体树搜索。添加成员时,如果有重复关键字存在,则不在实体树建立
新的结点,只在索引树上建立索引结点;如果无重复关键字存在,则同时在两棵树上建立
结点。传统的平衡二叉树删除时也需要根据关键字来删除,否则很难保证实体树继续保持
平衡,有了索引树则不需要根据关键字来寻找结点,直接指定要删除的成员实体,根据索
引树找到结点。
以上只是设想而已。大家讨论讨论,行得通吗?
 
最近数据结构上好贴多多嘛.呵呵,真让人高兴.
就等着各位大侠出招了.
 
算法题目,我很想学习!关注!
 
对于第一个多层哈希,我个人认为,这样做以后,就成了一棵多叉树了,反而体现不出哈西表的优点了
 
本人以为,建立散列表主要是为了规模不是很大的查找,而且出现冲突的情况一般非常少,
如果多了那么它本身就是失败的.而且一般是明确了有哪些数据后再手动建立hash表,
即使有冲突也不过很少的数量,用顺序查找法是效率更高的.
如果是自动建立hash表的话,而且是多层的,那么就变成多叉树
----效率反而不如二叉树高了. [:(]
对于第二点,我没有领会明白楼主的意思,无法评论.sorry.
btw:"Delphi中似乎不太讲究算法的精妙性,本身提供的算法大部分情况下已经足够。"
不清楚Delphi怎么会和算法联系了?一种语言提供的是数据结构,
给算法提供一个实现的手段,如此而已.就如Delphi,VB,VC++等是兵器,
而算法乃是武功一样,并不能说拿刀的不讲究武功的精妙一样.
 
非常感谢DarwinZhang的参与,怪我没有讲明白意思。
>>Delphi中似乎不太讲究算法的精妙性,本身提供的算法大部分情况下已经足够。
我的意思是评价Delphi中现在源代码中(例如VCL中)没有使用很精妙的算法。譬如,
TStringList的查找就是使用的顺序查找。还有:TList中在删除中间项目的时候会出现大
块的内存移动。而精妙的算法讲究内存移动越少越好。
>>不清楚Delphi怎么会和算法联系了?一种语言提供的是数据结构,
严格来讲,Delphi不算一种语言而是一种产品。就象Pascal是一种语言,而Pascal 7.0
只能算一个产品。同意我的说法吗?说“某种语言不讲究算法”欠妥,但说某种产品不讲究
算法不算错。是这个意思吗?
>>如果多了那么它本身就是失败的.而且一般是明确了有哪些数据后再手动建立hash表
有时候冲突是不是很少有时候事先是很难预计的。不过我本人对多层哈希也持怀疑态度。
>>对于第二点,我没有领会明白楼主的意思
平衡二叉树总能够保证最快地找到结点,也很容易添加。不过如果你考虑两点:
1.当多个项有相同关键字时候,到底建立几个结点?如果建立多个结点,显然会降低查找
效率。当建立一个项的时候,你如何才能确定这个结点上挂了几个实例?这一点很重要。
因为你不知道删除这个结点的时候是不是该删除这个结点。
2.删除这个结点的时候是不是还需要提供关键字?删除项的时候已经知道指针了。还需要
调用者提供关键字好象不合理。不过为了维护树的平衡,删除结点的时候是需要提供关键
字的。可是如果某个结点上挂了三个项,而只删除其中一个,是不需要维护结点平衡的,
也不需要作关键字比较。
但是,项的地址是唯一的,没有冲突的。这样,在建立结点的时候自动建立另外一棵二叉
树,一方面保证调用者提供的项目地址是存在的,另一方面确认是否真的需要删除主树中的结点。
其实我提的两个问题是有关联的,双平衡二叉树也是解决表的冲突问题。
为什么提出这个问题?
大家常常用到TMemoryStream,用的时候建立,不用的时候释放。如果反复用的话,可以
建立一个TMemoryStream池,免得来回申请内存、释放内存。那么为了改可能少地调用
ReAllocMemory,需要将池中的TMemoryStream按Capacity索引,每次需要的时候找最接近
并大于需要容量的空闲的。如果池中的TMemoryStream全是按某个尺寸建立的,效率将最
低,只能顺序查找了。当然这只是个比方。
不知道各位是否明白我的意思?
 
TStringList在D7如果是排序的话,他是利用hash表查找的,
>>大家常常用到TMemoryStream,用的时候建立,不用的时候释放。如果反复用的话,可以
>>建立一个TMemoryStream池,免得来回申请内存、释放内存。那么为了改可能少地调用
>>ReAllocMemory,需要将池中的TMemoryStream按Capacity索引,每次需要的时候找最接近
>>并大于需要容量的空闲的。如果池中的TMemoryStream全是按某个尺寸建立的,效率将最
>>低,只能顺序查找了。当然这只是个比方。/
你所说的,其实就是操作系统的内存管理,DELPHI的GetMem什么的就内部进行了这个方面的工作
 
to 张无忌:
我怎么没有看到D7的TStringList用hash表?如果TStringList是Sort的,则用二分法查找。
 
那我可能是我记错了
 
我不需要复杂到操作系统的内存池管理。我只需要尽可能少地调用内存API、尽可能少地
执行内存块移动。
 
Delphi是实现Object Pascal的一个实例,
可以说Delphi的实现过程中是否讲究算法,
其实这也是相当讲究算法的,我在
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1449133
讨论Case的实现中就有相关的论点。
另外,TList是指针数组,他的成员是指向一块内存的,
在移动TList成员时,它指向的这块内存是不会移动的。
而TList应用的范围显然不可能全面
(在删除,插入成员时不如链表但随机查找则胜一筹),
而且其他的开发工具也不可能提供全面胜任的东西。
我以为动态的查找用B(+)数比较合适。
 
学习.................
 
这是最后的版本(仅列出算法部分,有兴趣者可索要全部代码):
type
TIndexedChainedList = class;
TCompareMethod = function(Key, Dest: Pointer): Integer of object;
TBalance = (nbLeftTilt, nbNeutral, nbRightTilt);
// 双平衡二叉树结点结构
// 第一部分记录关键字项,每一关键字一个结点,按关键字搜索
// 第二部分记录用户自定义项,每一项一个结点,按实体搜索,并可引用关键字项
PAVLNodeDesc = ^TAVLNodeDesc;
// 全局结点管理器管理
TAVLNodeDesc = packed record
Left, Right: PAVLNodeDesc;
// 二叉树左右结点
Balance: TBalance;
// 平衡状态
case Integer of
0: (Key: Pointer;
// 关键字
EntityNode: PAVLNodeDesc;
// 指向第一个索引结点
DummyNode: Pointer);
// 空指针,区别两类结点
1: (Entity: Pointer;
// 实体结构
Next: PAVLNodeDesc;
// 指向下一项索引节点
KeyNode: PAVLNodeDesc);
// 指向主关键结点
end;

{******************************************************************************}
{ }
{ 双平衡二叉树函数 }
{ 建立和维护双平衡二叉树 }
{ }
{ 两棵平衡二叉树中只有第一棵是按用户自定义关键字建立的,称为关键树 }
{ 第二棵仅仅是第一棵树的实体项索引,称为搜索树 }
{ 搜索树唯一的作用是根据实体找到该实体所在的关键字项 }
{ 这样,在释放实体是保证不需要用关键字来寻找关键字结点 }
{ }
{ 搜索树自维护,建立关键字项时,自动建立实体搜索项 }
{ }
{******************************************************************************}
function AVLCompareKey(Index: PIndexDesc;
Key, Entity: Pointer): TBalance;
// 根据索引项提供的方法比较关键字,由平衡二叉树寻找结点和重新平衡时调用
var
I: Integer;
begin
Result := nbNeutral;
if Assigned(Index^.Method) then
begin
I := Index^.Method(Key, Entity);
if I < 0 then
Result := nbLeftTilt
else
if I > 0 then
Result := nbRightTilt;
end;
end;

function AVLAccessFromKey(Index: PIndexDesc;
Key: Pointer;
Src: PAVLNodeDesc;
var Dest: PAVLNodeDesc): Boolean;
// 在关键树中搜索关键字项
begin
if Src = nil then
Result := False
else
case AVLCompareKey(Index, Key, Src^.EntityNode^.Entity) of
nbLeftTilt:
Result := AVLAccessFromKey(Index, Key, Src^.Left, Dest);
nbRightTilt:
Result := AVLAccessFromKey(Index, Key, Src^.Right, Dest);
else
Result := True;
Dest := Src;
end;
end;

procedure AVLRotateLeft(var Node: PAVLNodeDesc);
// 向左旋转二叉树
var
Inst: PAVLNodeDesc;
begin
Inst := Node^.Right;
Node^.Right := Inst^.Left;
Inst^.Left := Node;
Node := Inst;
end;

procedure AVLRotateRight(var Node: PAVLNodeDesc);
// 向右旋转二叉树
var
Inst: PAVLNodeDesc;
begin
Inst := Node^.Left;
Node^.Left := Inst^.Right;
Inst^.Right := Node;
Node := Inst;
end;

procedure AVLGrownLeft(var Node: PAVLNodeDesc;
var State: Boolean);
// 结点向左生长
begin
case Node^.Balance of
nbLeftTilt:
begin
if Node^.Left^.Balance = nbLeftTilt then
begin
Node^.Left^.Balance := nbNeutral;
Node^.Balance := nbNeutral;
AVLRotateRight(Node);
end
else
begin
case Node^.Left^.Right^.Balance of
nbLeftTilt:
begin
Node^.Balance := nbRightTilt;
Node^.Left^.Balance := nbNeutral;
end;
nbRightTilt:
begin
Node^.Balance := nbNeutral;
Node^.Left^.Balance := nbLeftTilt;
end;
else
Node^.Balance := nbNeutral;
Node^.Left^.Balance := nbNeutral;
end;
Node^.Left^.Right^.Balance := nbNeutral;
AVLRotateLeft(Node^.Left);
AVLRotateRight(Node);
end;
State := False;
end;
nbRightTilt:
begin
Node^.Balance := nbNeutral;
State := False;
end;
else
Node^.Balance := nbLeftTilt;
State := True;
end;
end;

procedure AVLGrownRight(var Node: PAVLNodeDesc;
var State: Boolean);
// 结点向右生长
begin
case Node^.Balance of
nbLeftTilt:
begin
Node^.Balance := nbNeutral;
State := False;
end;
nbRightTilt:
begin
if Node^.Right^.Balance = nbRightTilt then
begin
Node^.Balance := nbNeutral;
Node^.Right^.Balance := nbNeutral;
AVLRotateLeft(Node);
end
else
begin
case Node^.Right^.Left^.Balance of
nbRightTilt:
begin
Node^.Balance := nbLeftTilt;
Node^.Right^.Balance := nbNeutral;
end;
nbLeftTilt:
begin
Node^.Balance := nbNeutral;
Node^.Right^.Balance := nbRightTilt;
end;
else
Node^.Balance := nbNeutral;
Node^.Right^.Balance := nbNeutral;
end;
Node^.Right^.Left^.Balance := nbNeutral;
AVLRotateRight(Node^.Right);
AVLRotateLeft(Node);
end;
State := False;
end;
else
Node^.Balance := nbRightTilt;
State := True;
end;
end;

procedure AVLInsertKeyInto(Index: PIndexDesc;
var Node: PAVLNodeDesc;
Key, Entity: Pointer;
EntityNode: PAVLNodeDesc;
var State: Boolean);
// 添加一个关键项到关键树
var
Next: PAVLNodeDesc;
begin
if Node = nil then
begin
Node := GlobalCreateKeyNode(Index);
//在此添加一片叶
Node^.Left := nil;
Node^.Right := nil;
Node^.Balance := nbNeutral;
Node^.Key := Key;
Node^.EntityNode := EntityNode;
Node^.DummyNode := nil;
EntityNode^.KeyNode := Node;
Index^.LastKeyNode := Node;
State := True;
end
else
case AVLCompareKey(Index, Key, Node^.EntityNode^.Entity) of
nbLeftTilt: // 向左搜索
begin
AVLInsertKeyInto(Index, Node^.Left, Key, Entity, EntityNode, State);
if State then
// 左子树变深
AVLGrownLeft(Node, State);
end;
nbRightTilt: // 向右搜索
begin
AVLInsertKeyInto(Index, Node^.Right, Key, Entity, EntityNode, State);
if State then
// 右子树变深
AVLGrownRight(Node, State);
end;
else
// 关键字相重
State := False;
Next := Node^.EntityNode;
while Next^.Next <> nildo
// 轮询所有的实体结点
Next := Next^.Next;
Next^.Next := EntityNode;
EntityNode^.KeyNode := Node;
end;
end;

procedure AVLInsertEntityInto(Index: PIndexDesc;
var Node: PAVLNodeDesc;
Key, Entity: Pointer;
var State: Boolean);
// 添加一个实体搜索项到搜索树,由关键树维护函数调用
begin
if Node = nil then
begin
Node := GlobalCreateEntityNode(Index);
//在此添加一片叶
Node^.Left := nil;
Node^.Right := nil;
Node^.Entity := Entity;
Node^.Balance := nbNeutral;
Node^.Next := nil;
Index^.LastEntityNode := Node;
State := False;
AVLInsertKeyInto(Index, Index^.KeyRoot, Key, Entity, Node, State);
State := True;
end
else
//实体不允许重复,所以不需要维护重复项
if Longint(Entity) < Longint(Node^.Entity) then
// 向左搜索
begin
AVLInsertEntityInto(Index, Node^.Left, Key, Entity, State);
if State then
// 左子树变深
AVLGrownLeft(Node, State);
end
else
if Longint(Entity) > Longint(Node^.Entity) then
// 向右搜索
begin
AVLInsertEntityInto(Index, Node^.Right, Key, Entity, State);
if State then
// 右子树变深
AVLGrownRight(Node, State);
end;
end;

procedure AVLShrunkLeft(var Node: PAVLNodeDesc;
var State: Boolean);
// 结点向左收缩
begin
case Node^.Balance of
nbLeftTilt:
begin
Node^.Balance := nbNeutral;
State := True;
end;
nbRightTilt:
begin
if Node^.Right^.Balance = nbRightTilt then
begin
Node^.Balance := nbNeutral;
Node^.Right^.Balance := nbNeutral;
AVLRotateLeft(Node);
State := True;
end
else
if Node^.Right^.Balance = nbNeutral then
begin
Node^.Balance := nbRightTilt;
Node^.Right^.Balance := nbLeftTilt;
AVLRotateLeft(Node);
State := False;
end
else
begin
case Node^.Right^.Left^.Balance of
nbLeftTilt:
begin
Node^.Balance := nbNeutral;
Node^.Right^.Balance := nbRightTilt;
end;
nbRightTilt:
begin
Node^.Balance := nbLeftTilt;
Node^.Right^.Balance := nbNeutral;
end;
else
Node^.Balance := nbNeutral;
Node^.Right^.Balance := nbNeutral;
end;
Node^.Right^.Left^.Balance := nbNeutral;
AVLRotateRight(Node^.Right);
AVLRotateLeft(Node);
State := True;
end;
end;
else
Node^.Balance := nbRightTilt;
State := False;
end;
end;

procedure AVLShrunkRight(var Node: PAVLNodeDesc;
var State: Boolean);
// 结点向右收缩
begin
case Node^.Balance of
nbRightTilt:
begin
Node^.Balance := nbNeutral;
State := True;
end;
nbLeftTilt:
begin
if Node^.Left^.Balance = nbLeftTilt then
begin
Node^.Balance := nbNeutral;
Node^.Left^.Balance := nbNeutral;
AVLRotateRight(Node);
State := True;
end
else
if Node^.Left^.Balance = nbNeutral then
begin
Node^.Balance := nbLeftTilt;
Node^.Left^.Balance := nbRightTilt;
AVLRotateRight(Node);
State := False;
end
else
begin
case Node^.Left^.Right^.Balance of
nbLeftTilt:
begin
Node^.Balance := nbRightTilt;
Node^.Left^.Balance := nbNeutral;
end;
nbRightTilt:
begin
Node^.Balance := nbNeutral;
Node^.Left^.Balance := nbLeftTilt;
end;
else
Node^.Balance := nbNeutral;
Node^.Left^.Balance := nbNeutral;
end;
Node^.Left^.Right^.Balance := nbNeutral;
AVLRotateLeft(Node^.Left);
AVLRotateRight(Node);
State := True;
end;
end;
else
Node^.Balance := nbLeftTilt;
State := False;
end;
end;

procedure AVLDeleteKeyFrom(Index: PIndexDesc;
var Node: PAVLNodeDesc;
Key: Pointer;
var State: Boolean);
forward;
procedure AVLRemoveNode(Index: PIndexDesc;
Src, Dest: PAVLNodeDesc);
// 执行删除
// Index: 索引对象
// Src/Dest: 源结点/目标结点:将目标结点Dest的内容移到Src上
var
KeyNode, EntityNode, NextNode, RelNode: PAVLNodeDesc;
State: Boolean;
begin
if Dest^.DummyNode = nil then
begin
// 关键结点
if Src <> nil then
begin
Src^.Key := Dest^.Key;
Src^.EntityNode := Dest^.EntityNode;
EntityNode := Src^.EntityNode;
while EntityNode <> nildo
begin
EntityNode^.KeyNode := Src;
EntityNode := EntityNode^.Next;
end;
end;
GlobalReleaseKeyNode(Index, Dest);
end
else
begin
// 索引结点
// 先维护关键结点
if Src <> nil then
RelNode := Src
else
RelNode := Dest;
KeyNode := RelNode^.KeyNode;
NextNode := RelNode^.Next;
if KeyNode^.EntityNode = RelNode then
begin
// 关键结点的第一个索引结点
if NextNode = nil then
begin
State := False;
AVLDeleteKeyFrom(Index, Index^.KeyRoot, KeyNode^.Key, State);
end
else
KeyNode^.EntityNode := NextNode;
end
else
begin
// 不是第一个结点,在链中删除
EntityNode := KeyNode^.EntityNode;
while EntityNode^.Next <> RelNodedo
EntityNode := EntityNode^.Next;
EntityNode^.Next := NextNode;
end;

// 替换属性
if Src <> nil then
begin
Src^.Entity := Dest^.Entity;
Src^.KeyNode := Dest^.KeyNode;
EntityNode := Dest^.KeyNode^.EntityNode;
if EntityNode = Dest then
begin
// 加到首项
Src^.Next := EntityNode^.Next;
Src^.KeyNode^.EntityNode := Src;
end
else
begin
// 加到中间项或尾部
while EntityNode^.Next <> Destdo
EntityNode := EntityNode^.Next;
Src^.Next := EntityNode^.Next^.Next;
EntityNode^.Next := Src;
end;
end;

GlobalReleaseEntityNode(Index, Dest);
end;
end;

function AVLFindHighest(Index: PIndexDesc;
Src: PAVLNodeDesc;
var Node: PAVLNodeDesc;
var State: Boolean): Boolean;
// 搜索树的最右结点,用于旋转置换
begin
State := True;
if Node = nil then
Result := False
else
if Node^.Right <> nil then
begin
if AVLFindHighest(Index, Src, Node^.Right, State) then
begin
if State then
AVLShrunkRight(Node, State);
Result := True;
end
else
Result := False;
end
else
begin
// 执行删除
AVLRemoveNode(Index, Src, Node);
Node := Node^.Left;
Result := True;
end;
end;

function AVLFindLowest(Index: PIndexDesc;
Src: PAVLNodeDesc;
var Node: PAVLNodeDesc;
var State: Boolean): Boolean;
begin
State := True;
if Node = nil then
Result := False
else
if Node^.Left <> nil then
begin
if AVLFindLowest(Index, Src, Node^.Left, State) then
begin
if State then
AVLShrunkLeft(Node, State);
Result := True;
end
else
Result := False;
end
else
begin
// 执行删除
AVLRemoveNode(Index, Src, Node);
Node := Node^.Right;
Result := True;
end;
end;

procedure AVLDeleteKeyFrom(Index: PIndexDesc;
var Node: PAVLNodeDesc;
Key: Pointer;
var State: Boolean);
// 从关键树释放一个关键项
begin
if Node = nil then
State := False
else
case AVLCompareKey(Index, Key, Node^.EntityNode^.Entity) of
nbLeftTilt:
begin
AVLDeleteKeyFrom(Index, Node^.Left, Key, State);
if State then
AVLShrunkLeft(Node, State);
end;
nbRightTilt:
begin
AVLDeleteKeyFrom(Index, Node^.Right, Key, State);
if State then
AVLShrunkRight(Node, State);
end;
else
State := False;
if Node^.Left <> nil then
begin
if AVLFindHighest(Index, Node, Node^.Left, State) then
if State then
AVLShrunkLeft(Node, State);
end
else
if Node^.Right <> nil then
begin
if AVLFindLowest(Index, Node, Node^.Right, State) then
if State then
AVLShrunkRight(Node, State);
end
else
begin
// 执行删除
AVLRemoveNode(Index, nil, Node);
Node := nil;
State := True;
end;
end;
end;

procedure AVLDeleteEntityFrom(Index: PIndexDesc;
var Node: PAVLNodeDesc;
Entity: Pointer;
var State: Boolean);
// 从搜索树释放一个实体搜索项,由关键树维护函数调用
begin
if Node = nil then
State := False
else
if Longint(Entity) < Longint(Node^.Entity) then
// 向左搜索
begin
AVLDeleteEntityFrom(Index, Node^.Left, Entity, State);
if State then
AVLShrunkLeft(Node, State);
end
else
if Longint(Entity) > Longint(Node^.Entity) then
// 向右搜索
begin
AVLDeleteEntityFrom(Index, Node^.Right, Entity, State);
if State then
AVLShrunkRight(Node, State);
end
else
begin
// 已找到
if Node^.Left <> nil then
begin
if AVLFindHighest(Index, Node, Node^.Left, State) then
if State then
AVLShrunkLeft(Node, State);
end
else
if Node^.Right <> nil then
begin
if AVLFindLowest(Index, Node, Node^.Right, State) then
if State then
AVLShrunkRight(Node, State);
end
else
begin
// 最后删除搜索树中的项
AVLRemoveNode(Index, nil, Node);
Node := nil;
State := True;
end;
end;
end;
 
谢谢了。
dirk_c@sina.com
 
xiaolin0522@163.com
我要源代码,谢谢。
上次一个朋友给的一个vc代码。
里面的平衡算法竟然是: 把所有的结点 保存到一个数组中,然后重新建立二叉树
那样,虽然可以达到平衡,可是完全失去 建立平衡二叉树的意义了。
ps:本人现在还不知道 平衡二叉树 由不平衡到平衡的 算法,:)
 
呵呵,AVL 我也写过,不过比你简单得多,只有插入操作,删除操作比较复杂,
还没写出来。[:(].很想看看你的大作 IStream@jstel.net 谢谢!
 
给一个看看,yzdbs#msn.com
 
多人接受答案了。
 
后退
顶部