【实验简介】链表是用链接存储的方式来表达线性表,它用指针表示结点间的逻辑关系,链表适用于插入或删除频繁,存储空间需求不定的情形。
【实验内容】定义一个链表存储的线性表,除已给出的表元素插入、删除、查找等基本操作外,再提供表的合并、拆分和逆置等操作。在应用程序中建立两个整型的单链表对象A和B,应用线性表的基本操作对表的实例对象进行操作测试。
1.
设线性链表A=(a1,a2,…,am),,B=(b1,b2,…bm),按下列规则合并A,B为线性表C的算法,即使得
C = (a1,b1,…,am,bm, b
(m+1),…,bn) 当m<=n
或
C
= (a1,b1,…,an,bn,a(n+1),…,am)当m>n
C表利用A表和B表中的结点空间构成。
2. 将C表原地逆置。
3. 将C表的中偶数和奇数分别链接为两个循环链表D和E。
说明:每一次合并、拆分和逆置等操作的结果均要输出。
【主要代码】
单链表头文件:LinkedList.h
#ifndefLINKEDLIST_H
#defineLINKEDLIST_H
#include
#include"LinkNode.h"
template
classLinkedList
{
public:
LinkedList(){first =
newLinkNode;}
//默认构造函数
LinkedList(const T
&x){first =
newLinkNode(x);}
//带形参的构造函数
LinkedList(LinkedList
&L); //复制构造函数
~LinkedList(){makeEmpty();}
//析构函数
void makeEmpty();
//将表置空
int Length()const;
//求表长度
LinkNode
*getHead()const {returnfirst;} //取表头结点指针
LinkNode
*Search(T x); //搜索数据域为x的结点
LinkNode
*Locate(int i)const; //取i号表项的地址
bool getData(int i,T
&x)const; //取i号表项的数据
void setData(int i,T
&x); //用x修改第i个元素的值
bool Insert(int i,T
&x); //在第i个元素后插入x
bool Remove(int i,T
&x); //删除第i个元素,x返回该元素的值
bool IsEmpty()const
//判断表空否,空则返回true
{
returnfirst->link==NULL?true:false;
}
void Output();
//输出
void Turn();
//将单链表的指向倒转
void
Combine(LinkedList&A,LinkedList
&B); //将两个单链表合并
void
Divide(LinkedList&D,LinkedList
&E);
protected:
LinkNode
*first;
};
template
//复制构造函数实现
LinkedList::LinkedList(LinkedList&L)
{
T value;
LinkNode *srcptr
= L.getHead();
LinkNode
*destptr = first =
newLinkNode;
while
(srcptr->link!=NULL)
{
value =
srcptr->link->data;
destptr->link =
newLinkNode(value);
srcptr =
srcptr->link;
destptr =
destptr->link;
}
destptr->link =
NULL;
}
template
//置空函数实现
voidLinkedList::makeEmpty()
{
LinkNode
*p;
while
(first->link!=NULL)
{
p =
first->link;
first->link =
p->link;
delete p;
}
}
template
//求长函数实现
intLinkedList::Length()const
{
LinkNode *p =
first->link;
int count =
0;
while
(p!=NULL)
{
p =
p->link;
count++;
}
return
count;
}
template
//搜索函数实现
LinkNode*LinkedList::Search(T
x)
{
LinkNode
*current =first->link;
while
(current!=NULL)
{
if
(current->data==x)
break;
else
current =
current->link;
return
current;
}
}
template
//定位函数实现
LinkNode*LinkedList::Locate(int
i)const
{
if
(i<0)
return NULL;
LinkNode
*current = first;
int k = 0;
while
(current!=NULL&&k
{
current =
current->link;
k++;
}
return
current;
}
template
//取值函数实现
boolLinkedList::getData(int
i,T &x)const
{
if
(i<=0)
return NULL;
LinkNode
*current = Locate(i);
if
(current==NULL)
return
false;
else
{
x =
current->data;
return true;
}
}
template
//修改函数实现
voidLinkedList::setData(int
i,T &x)
{
if
(i<=0)
return;
LinkNode
*current = Locate(i);
if
(current==NULL)
return;
else
current->data =
x;
}
template
//插入函数实现
boolLinkedList::Insert(int
i,T &x)
{
LinkNode
*current = Locate(i);
if
(current==NULL)
return
false;
LinkNode
*newNode =
newLinkNode(x);
newNode->link =
current->link;
current->link =
newNode;
return true;
}
template
//删除函数实现
boolLinkedList::Remove(int
i,T &x)
{
LinkNode
*current = Locate(i-1);
if(current==NULL||current->link==NULL)
return
false;
LinkNode *del
=current->link;
x =
del->data;
delete del;
return true;
}
template
//输出函数实现
voidLinkedList::Output()
{
LinkNode
*current =first->link;
while
(current!=NULL)
{
cout<data<
current =
current->link;
}
cout<
}
template
//倒置函数实现
voidLinkedList::Turn()
{
if
(first->link==NULL)
return;
LinkNode
*current1 =first->link,*current2 =
first->link->link;
LinkNode
*p;
while(p!=NULL)
{
p =
current2->link;
current2->link
= current1;
current1 =
current2;
current2 =
p;
}
first->link->link =
NULL;//让倒置后的最后一个结点的指针域为空
first->link =
current1;//让附加的表头结点的指针域指向第一个结点
}
template
voidLinkedList::Combine(LinkedList
&A,LinkedList&B)
//合并函数
{
T
value1,value2;
LinkNode
*srcptr1 = A.getHead();
LinkNode
*srcptr2 = B.getHead();
LinkNode
*destptr = first =
newLinkNode;
if
(A.Length()
{
while
(srcptr1->link!=NULL)
{
value1
=srcptr1->link->data;
value2
=srcptr2->link->data;
destptr->link =
newLinkNode(value1);
srcptr1 =
srcptr1->link;
destptr =
destptr->link;
destptr->link =
newLinkNode(value2);
srcptr2 =
srcptr2->link;
destptr =
destptr->link;
}
while
(srcptr2->link!=NULL)
{
value2 =
srcptr2->link->data;
destptr->link =
newLinkNode(value2);
srcptr2 =
srcptr2->link;
destptr =
destptr->link;
}
destptr->link =
NULL;
}
if
(A.Length()==B.Length())
{
while
(srcptr2->link!=NULL)
{
value1
=srcptr1->link->data;
value2 =
srcptr2->link->data;
destptr->link =
newLinkNode(value1);
srcptr1 =
srcptr1->link;
destptr =
destptr->link;
destptr->link =
newLinkNode(value2);
srcptr2 =
srcptr2->link;
destptr =
destptr->link;
}
destptr->link =
NULL;
}
if
(A.Length()>B.Length())
{
while
(srcptr2->link!=NULL)
{
value1
=srcptr1->link->data;
value2
=srcptr2->link->data;
destptr->link =
newLinkNode(value1);
srcptr1 =
srcptr1->link;
destptr =
destptr->link;
destptr->link =
newLinkNode(value2);
srcptr2 =
srcptr2->link;
destptr =
destptr->link;
}
while
(srcptr1->link!=NULL)
{
value1
=srcptr1->link->data;
destptr->link =
newLinkNode(value1);
srcptr2 =
srcptr2->link;
destptr =
destptr->link;
}
destptr->link =
NULL;
}
}
template
voidLinkedList::Divide(LinkedList
&D,LinkedList&E)
{
T value;
LinkNode *srcptr
=this->getHead();
LinkNode
*destptr1 = D.first =new
LinkNode;
LinkNode
*destptr2 = E.first =new
LinkNode;
while(srcptr->link!=NULL&&srcptr->link->link!=NULL)
{
value =
srcptr->link->data;
destptr1->link
=
newLinkNode(value);
srcptr =
srcptr->link->link;
destptr1 =
destptr1->link;
}
destptr1->link
= NULL;
srcptr =
this->getHead();
srcptr =
srcptr->link;
while(srcptr->link!=NULL&&srcptr->link->link!=NULL)
{
value =
srcptr->link->data;
destptr2->link
=
newLinkNode(value);
srcptr =
srcptr->link->link;
destptr2 =
destptr2->link;
}
destptr1->link
= NULL;
}
#endif
节点头文件:LinkNode.h:
#ifndefLINKNODE_H
#defineLINKNODE_H
#include
template
structLinkNode
{
T data;
//数据域
LinkNode *link;
//指针域
LinkNode(LinkNode
*ptr= NULL){link = ptr;} //仅有指针域形参的构造函数
LinkNode(const
T&item,LinkNode
*ptr = NULL) //构造函数
{
data = item;
link = ptr;
}
};
#endif
主函数源文件:Main.cpp:
#include
#include"LinkedList.h"
#include"LinkNode.h"
void main()
{
LinkedListList1,List2,List3,List4,List5;
int a[] =
{1,2,3,4,5,6,7,8,9,10};
int b[] =
{1,2,3,4,5,6,7,8,9,10,11,12};
for (int i =
0;i<10;i++)
List1.Insert(i,b[i]);
for (int j =
0;j<12;j++)
List2.Insert(j,b[j]);
cout<
cout<
";
List1.Output();
cout<
";
List2.Output();
cout<
List3.Combine(List1,List2);
cout<
";
List3.Output();
cout<
List3.Turn();
cout<
";
List3.Output();
cout<
List3.Divide(List4,List5);
cout<
";
List4.Output();
cout<
";
List5.Output();
}
【实验过程】
设计好单链表的建立、拆分、合并、转置代码后,打开C++编译环境,建立两个空的头文件,分别输入节点类和链表类的声明代码及实现代码。然后新建主文件,对两个类的构造函数、复制构造函数以及合并,转置函数等进行调试,最后进行评估。
【实验体会】
转置算法为利用3个指针的经典算法,需要记牢。合并与拆分算法总体都是建立在复制函数算法的基础上。经过这次实验,对单链表的性质有了更深刻的体会。