%%%%%有幾個不同類型的單鏈表,如何用一個查找節點函數、一個插入節點函數、一個刪除節點函數實現對這些鏈表的操作。%%%%%%%%%%在線等待,Another_

  • 主题发起人 主题发起人 leway
  • 开始时间 开始时间
L

leway

Unregistered / Unconfirmed
GUEST, unregistred user!
%%%%%有幾個不同類型的單鏈表,如何用一個查找節點函數、一個插入節點函數、一個刪除節點函數實現對這些鏈表的操作。%%%%%%%%%%在線等待,Another_eYes請進 (50分)<br />type
Link1 = ^ TNodeStatic1;
TNodeStatic1= record
NodeData: TLabel;
Next: Link1;
end;
type
Link2 = ^ TNodeStatic2;
TNodeStatic2 = record
NodeData: TButton;
Next: Link2;
end;
var
List1:Link1;
List2:Link2;

function InsNode(var:鏈表; 鏈表節點) : 鏈表節點; //查找節點函數
function SerNode(var:鏈表; 鏈表節點) : 鏈表節點; //插入節點函數
procedure DelNode(:鏈表; 鏈表節點); //刪除節點函數
要求不用函數重載,用以上三個函數實現對不同類型鏈表的操作。
 
侯捷先生有一本《essential c++》讲过泛型编程。
 
to:思想我知道,但如何在delphi中實現,請舉例說明,謝謝
 
呵呵, 单链表啊。 处理很简单, 但效率不高。 另外你的几个函数返回值要求看不懂,

function InsNode(var Lst: Pointer; Node: Pointer; InsBefore: Pointer): Pointer; // 返回前一个节点, 返回 nil 表示插在首节点
begin
if Lst = InsBefore then
begin
Lst := Node;
Link1(Node)^.Next := InsBefore;
Result := nil;
end
else begin
Result := Lst;
while Link1(Result)^.Next &lt;&gt; InsBefore do
Result := Link1(Result)^.Next;
Link1(Node.Next) := Link1(Result)^.Next;
Link1(Result)^.Next := Node;
end;
end;

function SerNode(Lst, Node: Pointer): Pointer; // 返回前一个节点, 返回为nil 表示找不到或Node=Lst
begin
if Lst = Node then
Result := nil
else begin
Result := Lst;
while (Result &lt;&gt; nil) and (Link1(Result)^.Next &lt;&gt; Node) do
Result := Link1(Result)^.Next;
end;
end;

function DelNode(Lst, Node: Pointer): Pointer; // 返回前一个节点, 返回nil表示删除的是首节点
begin
if Lst = Node then
begin
Result := nil;
Lst := Link1(Node)^.Next;
end
else begin
Result := SerNode(Lst, Node);
if Result &lt;&gt; nil then
Link1(Result)^.Next := Link1(Node)^.Next;
end;
TObject(Link1(Node)^.Label).Free;
FreeMem(Node);
end;

 
to:Another_eYes
你好象沒有看懂我的問題,給你看看我寫的吧,問題是我對每種類型的鏈表,都寫了一個函數(即用了函數重載),我不想用函數重載,想用同一個函數實現對不同類型鏈表的操作(即泛型思想)。即函數於處理的鏈表類型無關。
unit common;

interface

uses
stdctrls,MyClassType;

type
LinkLabel = ^ TNodeLabel;
TNodeLabel = record
NodeData: TLabel;
Next: LinkLabel;
end;
type
LinkEdit = ^ TNodeEdit;
TNodeEdit = record
NodeData: TMyEdit;
//TextData: string;
Next: LinkEdit;
end;
type
LinkButton = ^ TNodeButton;
TNodeButton = record
NodeData: TButton;
//TextData: string;
Next: LinkButton;
end;

var
CurPointer: pointer; //指向向前元件
CurLblPointer: LinkLabel;
CurEdtPointer: LinkEdit;
CurBtnPointer: LinkButton;
ListStatic: LinkLabel; //Label鏈表
ListEdit: LinkEdit; //Edit鏈表
ListButton: LinkButton; //Button鏈表
lableft,labtop,edtleft,edttop,btnleft,btntop:integer;
{新節點、頂點、當前節點位置}
{NowNode, TopNode, NewNodeLabel : LinkLabel;
NewNodeEdit: LinkEdit;}


function InsNode(var nNode: LinkLabel ; sInsData: TLabel) : LinkLabel; overload;
function SerNode(var nNode: LinkLabel ; sSerDataName: string) : LinkLabel; overload;
procedure DelNode(var nNode: LinkLabel; sDelDataName: string); overload;

function InsNode(var nNode: LinkEdit ; sInsData: TMyEdit) : LinkEdit; overload;
function SerNode(var nNode: LinkEdit ; sSerDataName: string) : LinkEdit; overload;
procedure DelNode(var nNode: LinkEdit; sDelDataName: string); overload;

function InsNode(var nNode: LinkButton ; sInsData: TButton) : LinkButton; overload;
function SerNode(var nNode: LinkButton ; sSerDataName: string) : LinkButton; overload;
procedure DelNode(var nNode: LinkButton; sDelDataName: string); overload;

implementation

//==============================表尾插入節點(Label)====================================
function InsNode(var nNode: LinkLabel ; sInsData: TLabel) : LinkLabel;
var
TempNode,NewNode: LinkLabel;
begin
TempNode:=nNode;
New(NewNode);
NewNode^.NodeData:=sInsData;
NewNode.Next:=NIL;
if (nNode = NIL) then nNode:= NewNode
else
begin
while (TempNode.Next&lt;&gt;NIL) do TempNode:=TempNode.Next;
TempNode.Next:= NewNode;
end;
InsNode:= NewNOde;
end;

//================================查找節點(Label)======================================
function SerNode(var nNode: LinkLabel ; sSerDataName: string) : LinkLabel;
var
tempNode: LinkLabel;
begin
tempNode:= nNode;
while (tempNode.NodeData.Name &lt;&gt; sSerDataName) and (tempNode &lt;&gt; NIL) do tempNode:= tempNode.Next;
SerNode:= tempNode;
end;

//================================刪除節點(Label)======================================
procedure DelNode(var nNode: LinkLabel; sDelDataName: string);
var
pNode,qNode: LinkLabel;
begin
pNode:= nNode;
qNode:= nNode;
while (qNode.NodeData.Name &lt;&gt; sDelDataName) and (qNode.Next &lt;&gt; NIL)do
begin
pNode:= qNode;
qNode:= qNode.Next;
end;
if qNode = nNode then nNode:= nNode.Next
else if qNode.Next = NIL then pNode.next:= NIL
else begin
pNode.Next:= qNode.Next;
qNode.Next:= NIl;
end;
qNode.NodeData.Visible:= false; //隱藏
Dispose(qNode); //釋放空間
end;

//==============================表尾插入節點(Edit)====================================
function InsNode(var nNode: LinkEdit ; sInsData: TMyEdit) : LinkEdit;
var
TempNode,NewNode: LinkEdit;
begin
TempNode:=nNode;
New(NewNode);
NewNode^.NodeData:=sInsData;
NewNode.Next:=NIL;
if (nNode = NIL) then nNode:= NewNode
else
begin
while (TempNode.Next&lt;&gt;NIL) do TempNode:=TempNode.Next;
TempNode.Next:= NewNode;
end;
InsNode:= NewNOde;
end;

//================================查找節點(Edit)======================================
function SerNode(var nNode: LinkEdit ; sSerDataName: string) : LinkEdit;
var
tempNode: LinkEdit;
begin
tempNode:= nNode;
while (tempNode.NodeData.Name &lt;&gt; sSerDataName) and (tempNode &lt;&gt; NIL) do tempNode:= tempNode.Next;
SerNode:= tempNode;
end;

//================================刪除節點(Edit)======================================
procedure DelNode(var nNode: LinkEdit; sDelDataName: string);
var
pNode,qNode: LinkEdit;
begin
pNode:= nNode;
qNode:= nNode;
while (qNode.NodeData.Name &lt;&gt; sDelDataName) and (qNode.Next &lt;&gt; NIL)do
begin
pNode:= qNode;
qNode:= qNode.Next;
end;
if qNode = nNode then nNode:= nNode.Next
else if qNode.Next = NIL then pNode.next:= NIL
else begin
pNode.Next:= qNode.Next;
qNode.Next:= NIl;
end;
qNode.NodeData.Visible:= false; //隱藏
Dispose(qNode); //釋放空間
end;

//==============================表尾插入節點(Button)====================================
function InsNode(var nNode: LinkButton ; sInsData: TButton) : LinkButton;
var
TempNode,NewNode: LinkButton;
begin
TempNode:=nNode;
New(NewNode);
NewNode^.NodeData:=sInsData;
NewNode.Next:=NIL;
if (nNode = NIL) then nNode:= NewNode
else
begin
while (TempNode.Next&lt;&gt;NIL) do TempNode:=TempNode.Next;
TempNode.Next:= NewNode;
end;
InsNode:= NewNOde;
end;

//================================查找節點(Button)======================================
function SerNode(var nNode: LinkButton ; sSerDataName: string) : LinkButton;
var
tempNode: LinkButton;
begin
tempNode:= nNode;
while (tempNode.NodeData.Name &lt;&gt; sSerDataName) and (tempNode &lt;&gt; NIL) do tempNode:= tempNode.Next;
SerNode:= tempNode;
end;

//================================刪除節點(Button)======================================
procedure DelNode(var nNode: LinkButton; sDelDataName: string);
var
pNode,qNode: LinkButton;
begin
pNode:= nNode;
qNode:= nNode;
while (qNode.NodeData.Name &lt;&gt; sDelDataName) and (qNode.Next &lt;&gt; NIL)do
begin
pNode:= qNode;
qNode:= qNode.Next;
end;
if qNode = nNode then nNode:= nNode.Next
else if qNode.Next = NIL then pNode.next:= NIL
else begin
pNode.Next:= qNode.Next;
qNode.Next:= NIl;
end;
qNode.NodeData.Visible:= false; //隱藏
Dispose(qNode); //釋放空間
end;


end.
 
請將以上對不同類型鏈表的相同操作用泛型思想實現。
 
奇怪, 您理解我的代码了吗? 我几个函数的参数和返回类型可都是无类型指针啊。 我不管你传入的是Link1类型还是Link2类型, 总之函数都能正确处理。 这还不够“泛”吗?
 
to: Another_eYes
不好意思,好久沒跟你聯系。你的代碼我仔細看過,寫得確實很精煉。但還存在一些小問題。
几个函数的参数和返回类型可都是无类型指针,但在函數中為什麼有這樣得語句:
Link1(Node)^.Next := InsBefore;
Link1(Node.Next) := Link1(Result)^.Next;
Link1(Result)^.Next := Node;
等等,我不一一列舉了。
這樣寫得話,如果傳入Link2,那末這幾個函數不就不對了碼?
請想想,給出答案。並在此謝謝指教。
 
是的,我的代码有局限性。 不过局限不是你说的类型不符。 而是各个结构中的Next必须位于相同的位置(即Next到结构头的偏移量必须一致)
如:
TLink1 = record
NodeData: TLabel;
Next: TLink1;
end;

TLink2 = record
AInt: Integer;
Next: TLink2;
OtherFloat: Extended;
OtherInteger: Integer;
OtherString: string;
end;

这种结构我的程序就能正确处理。
而如:
TLink1 = record
NextNode: TLabel;
Next: TLink1;
end;

TLink2 = record
Next: TLink2;
OtherData: Integer;
end;

这种结构就无法处理了。 要正确处理必须修改TLink2的定义, 哪怕在TLink2.Next前加一个无用的整数就能处理了。

看来你还不了解指针和强制类型转换的强大功能吧。
 
就你的具体问题,我想可以如下解决:
type
PLink = ^ TNodeLabel;
TNodeLabel = record
NodeData: TCompnent;
Next: LinkLabel;
end;
var
List1: PLink; //这里放Label;
List2: Plink; //这里放Button;

使用时(List1^.NodeData as TLabel)就行了。
 
to: Another_eYes
您的回答,我反復看了幾遍,也思考了幾遍,仍有不解的地方。
您說各个结构中的Next必须位于相同的位置(即Next到结构头的偏移量必须一致)
如:
TLink1 = record
NodeData: TLabel;
Next: TLink1;
end;

TLink2 = record
AInt: Integer;
Next: TLink2;
OtherFloat: Extended;
OtherInteger: Integer;
OtherString: string;
end;
以上兩個Next到结构头的偏移並不一致呀?一個Next前是NodeData: TLabel;另一個是AInt: Integer;偏移量怎麼會一致呢?
另一個不解是您為何要將傳入的鏈表都要轉化成Link1,Link1和Link2中節點的類型是不一樣的。一個是TLabel,一個是TButton。
 
呵呵。 注意我说的是偏移而不是类型。 所谓偏移指的是字节数。 TLabel和TButton和Integer和Pointer和....(省略n种)它们占用的字节数是一样的, 都是4字节。
Link1(Result)^.Next的意思是:"把Result指向的内存看成Link1类型, 然后取那块内存中相当于Link1的Next位置处的数据"
所以转成Link1和转成Link2类型没有区别, 因为它们的Next相对于结构头的位置是一样的,都是4字节, 至于这4字节中存的具体是TLabel还是TButton还是String还是Integer还是鬼知道是什么东西和我的程序没有任何关系, 我程序关心的就是Next位置距离头部都是4字节远。
 
to; Another_eYes
您這樣解釋,我開始明白了。但有一點我不明白,如下:
TLabel和TButton和Integer和Pointer和....(省略n种)它们占用的字节数是一样的, 都是4字节。這是為什麼?
謝謝您的解答。
 
这些类型的具体数据都存放于一块另外申请的内存中, 变量中保存的只不过是那块内存的起始/特定(一般是起始地址,例外是string,它保存的是起始地址+8)地址。 所以只需要一块32位整数长度的内存就能够了(以后64位系统就是64位),这个数值就是4字节。
 
接受答案了.
 
后退
顶部