17、node; //使链表首和链表尾指针都指向这结点
node->Next=node—〉Prev=0; //指该结点的前后向指针置为空
}
else { //链表不为空,找到插入位置
Node *pn = Head;
while (pn ) { //B
Object &obj= *(node->Info);
if( pn—>Info->IsGreat( obj) <=0 ) break; //C
else pn = pn—>Next;
}
if(pn == 0 ){
18、 //D
Tail-〉Next=node; //使原链表尾结点的后向指针指向这结点
node—>Prev=Tail; //使该结点的前向指针指向原链表尾结点
Tail=node; //使Tail指向新的链表尾结点
node—>Next=0;
}
else { //插在pn所指向结点之前
if( pn == Head ){ //E
node-〉Next = Head;
Head->Prev = node;
node—>Prev =
19、0;
Head = node;
}
else{ //F
pn->Prev->Next = node; //使pn指向结点的前一个结点指向node
node-〉Next = pn;
node->Prev = pn; //设置后向链
pn—>Prev = node;
}
}
}
}
A行中条件成立时,双向链表为空链,要插入结点为链表上的第上一个结点,初始化这个双向链表.B行中的循环语句实现查找插入位置,当找到插入位置或整个链表上的结点都查完后,结束这个循环语句.C行中的条
20、件成立时,表示要把结点插在pn所指向的结点之前。D行中的条件成立时,表示要把结点插入链尾.若E行中的条件成立时,要把结点插在第一个结点之前;否则将结点插在pn所指向的结点之前。
一个完整的参考程序如下:
#include 〈iostream。h>
#include
class Object{ //定义一个用于派生结点信息的抽象类
public:
Object(){}
virtual int IsEqual(Object &)=0; //判二个结点是否相等
virtual void Show()=0; //输出一个结
21、点上的数据
virtual int IsGreat(Object &)=0; //判二个结点的大小
virtual ~Object(){ };
};
class Node{ //结点类
private:
Object *Info; //指向描述结点的数据域
Node *Prev,*Next; //用于构成链表的前后向指针
public:
Node (){ Info=0; Prev=0; Next=0;}
Node ( Node &node) //完成拷贝功能的构造函数
{
Info=node.
22、Info; Prev=node。Prev; Next=node.Next;
}
void FillInfo(Object *obj){Info =obj;} //使Info指向数据域
friend class List; //定义友元类
};
class List{ //实现双向链表操作的类
Node *Head,*Tail; //链表首和链表尾指针
public:
List(){Head=Tail=0;} //置为空链表
~List(){DeleteList();} //释放链表占用的存储空间
v
23、oid AddNode(Node *); //在链表尾加一个结点
Node * DeleteNode(Node *); //删除链表中的一个指定的结点
Node *LookUp(Object &); //在链表中查找一个指定的结点
void ShowList(); //输出整条链表上的数据
void DeleteList(); //删除整条链表
};
void List::AddNode(Node *node)
{
if(Head ==0){ //条件成立时,为空链表
Head=Tail=node; /
24、/使链表首和链表尾指针都指向这结点
node—〉Next=node->Prev=0; //指该结点的前后向指针置为空
}
else { //链表不为空,找到插入位置
Node *pn = Head;
while (pn ) {
Object &obj= *(node->Info);
if( pn-〉Info-〉IsGreat( obj) <=0 ) break;
else pn = pn—>Next;
}
if(pn == 0 ){ //插入链尾
Tail->Next=
25、node; //使原链表尾结点的后向指针指向这结点
node-〉Prev=Tail; //使该结点的前向指针指向原链表尾结点
Tail=node; //使Tail指向新的链表尾结点
node->Next=0;
}
else { //插在pn所指向结点之前
if( pn == Head ){ //插在第一个结点之前
node-〉Next = Head; Head->Prev = node;
node->Prev = 0; Head = node;
26、}
else{ //使pn指向结点的前一个结点指向node
pn—〉Prev—〉Next = node;
node—〉Next = pn;
node—〉Prev = pn; //设置后向链
pn->Prev = node;
}
}
}
}
Node * List::DeleteNode(Node *node) //删除指定的结点
{
if( node == Head ) //二者相等,表示删除链表首结点
if(node == Tail) //二者相等,表示链表上
27、只有一个结点
Head=Tail=0;
else { //删除链表首结点
Head=node-〉Next;
Head->Prev=0;
}
else { //删除的结点不是链表上的首结点
node->Prev—〉Next=node—〉Next; //从后向链指针上取下该结点
if(node != Tail ) node—〉Next-〉Prev=node->Prev;
else Tail = node-〉Prev ; //要删除的结点为链表尾结点
}
node->P
28、rev=node->Next=0; //将已删除结点的前后向指针置为空
return( node);
}
Node * List::LookUp(Object &obj) //从链表上查找一个结点
{
Node *pn=Head;
while(pn) {
if(pn-〉Info-〉IsEqual(obj)) return pn; //找到要找的结点
pn=pn-〉Next;
}
return 0; //链表上没有要找的结点
}
void List ::ShowList() //输出链表上各结点的数据值
{
N
29、ode *p=Head;
while(p) {
p->Info-〉Show(); p=p—〉Next;
}
}
void List::DeleteList() //删除整条链表
{
Node *p,*q;
p=Head;
while (p) {
delete p—>Info; //释放描述结点数据的动态空间
q=p; p=p-〉Next;
delete q; //释放Node占用的动态空间
}
}
class MenNode :public Object{ //由抽象类派生出描述结点数据的类
30、 char *Name; //姓名
char *Addr; //地址
int Salary; //工资
public:
MenNode(char *n=0, char *a=0, int s =0)
{
if( n==0 ) Name =0;
else {
Name = new char [strlen(n)+1]; strcpy(Name,n);
}
if( a==0 ) Addr =0;
else {
Addr = new char [strlen(a)+1]; strcpy(Add
31、r,a);
}
Salary =s;
}
void SetData(char * ,char *, int );
int IsEqual(Object &);
int IsGreat(Object &);
~MenNode( )
{
if(Name) delete [ ] Name;
if( Addr) delete [ ] Addr;
}
void Show() //重新定义虚函数
{ cout <<"姓名:"〈〈 Name〈<’\t’<〈
"地址:"<32、\n';
}
};
void MenNode::SetData(char *n ,char *a, int s)
{
if(Name) delete [ ] Name;
if(Addr) delete [ ] Addr;
if( n==0 ) Name =0;
else {
Name = new char [strlen(n)+1]; strcpy(Name,n);
}
if( a==0 ) Addr =0;
else {
Addr = new char [strlen(a)+1]; strcpy(Addr,a);
}
Sal
33、ary =s;
}
int MenNode::IsEqual(Object &obj) //定义比较结点是否相等的虚函数
{
MenNode &temp=(MenNode &) obj;
return (Salary == temp.Salary); //相等返回1,否则返回0
}
int MenNode::IsGreat(Object &obj) //定义比较结点大小的虚函数
{
MenNode &temp=(MenNode &) obj;
return (temp.Salary—Salary);
}
void main(void )
34、
{
MenNode *p;
Node *pn,*pt, node;
List list;
for (int i=1;i<5;i++) { //建立包含五个结点的双向链表
p= new MenNode; //动态建立一个IntOb类的对象
char name[20],addr[40];
int s;
cout<〈"输入姓名,地址和工资:";
cin。getline(name,20);
cin.getline(addr,40);
cin〉〉s;cin。get();
p—〉SetData(name,addr
35、s);
pn= new Node; //建立一个新结点
pn->FillInfo(p); //填写结点的数据域
list。AddNode(pn); //将新结点加入链表尾
}
list。ShowList(); //输出链表上各结点的数据值
cout〈<’\n';
MenNode da;
da.SetData( "zhang”, ”NanJin”, 2000); //置要查找的结点数据值
pn=list.LookUp(da); //从链表上查找指定的结点
if (pn) pt=list.DeleteNode(pn); //若找到,则从链表上删除该结点
list.ShowList(); //输出已删除结点后的链表
cout<<’\n';
if (pn) list.AddNode(pt); //将这结点加入链表尾
list。ShowList(); //输出已加一个结点后的链表
}
⑵上机要求
自己设计测试数据,完成程序的调试工作。
⑶写出实验报告。
4。3项目选做
在以上程序的基础上,设计一个双向链表上的结点为通讯录的程序,要求按姓名的字典序排序。