(以下主要内容由学生完成)
- 实验项目名称
链表及其应用
- 实验要求
1.掌握链表的灵活运用;
2.学习链表初始化和建立一个新的链表;
3.知道怎样去实现链表删除结点操作与插入结点;
4.理解链表的基本操作(包括数据域数据的相加)并能灵活运用。
- 实验内容
1. 实现线性表的链式存储方法,单链表建立、插入、删除、查找等基本操作。
2. 基于单链表的基本操作,编写算法函数LinkListReverse(LinkList L),实现单链表的就地逆置。
- 算法分析
LinkList InitList(void) {// 创建单链表
LinkList L = new LNode;
L->next = NULL;
LNode* r = L;
int i = 0;
cout << "输入" << END << "结束" << endl;
while (true) {// 通过后插法创建单链表
LNode* p = new LNode;
cout << "请输入第" << ++i << "个数据" << endl;
cin >> p->data;
if (p->data == END) {
break;
}
p->next = NULL;
r->next = p;
r = p;
}
return L;
}
创建单链表:通过后插法创建单链表,返回链表头指针,时间复杂度O(n)。
int ListLength(LinkList L) {// 输出表长
LNode* p = L->next;
int j = 0;// 计数器
while (p) {
p = p->next;
++j;
}
return j;
}
输出表长:通过遍历链表输出链表长度,时间复杂度O(n)。
void ShowList(LinkList L) {// 显示每个节点数据
LNode* p = L->next;
for (int i = 0; i < ListLength(L); i++) {
cout << "第" << i + 1 << "个数据为" << p->data << endl;
p = p->next;
}
}
显示每个节点数据,时间复杂度O(n)。
Status GetElem(LinkList L, int i, ElemType& e) {// 取值
LNode* p = L->next;
int j = 1;// 计数器
while (p && (j < i)) {
p = p->next;
++j;
}
if (!p || j > i) {
return ERROR;
}
e = p->data;
return OK;
}
取值:输入节点位置和数据,如果存在于链表中,返回OK,否则返回ERROR,时间复杂度O(n)。
int LocateElem(LinkList L, ElemType e) {// 查找
LNode* p = L->next;
int i = 1;// 计数器
while (p) {
if (p->data == e) {
return i;
}
p = p->next;
i++;
}
return ERROR;
}
查找:输入数据,通过遍历整个链表,返回该数据在链表中第一次出现的位置,时间复杂度O(n)。
Status ListInsert(LinkList& L, int i, ElemType e) {// 插入
LNode* p = L;
int j = 0;
while (p && (j < (i - 1))) {
p = p->next;
j++;
}
if (!p || j > (i - 1)) {
return ERROR;
}
LNode* s = new LNode;
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
插入:输入插入的位置和数据信息,遍历找到位置,再通过指针操作插入,时间复杂度O(n)。
Status ListDelete(LinkList& L, int i) {// 删除
LNode* p = L;
int j = 0;
while (p && (j < (i - 1))) {
p = p->next;
j++;
}
if (!p || j > (i - 1)) {
return ERROR;
}
LNode* q = new LNode;
q = p->next;
p->next = q->next;
delete q;
return OK;
}
删除:输入删除的位置,遍历找到位置,再通过指针操作删除,时间复杂度O(n)。
LinkList LinkListReverse(LinkList L) {// 逆置
LinkList LL = new LNode;
LL->next = NULL;
LNode* s = L;
while (s->next) {// 前插法创建一个新单链表
LNode* p = new LNode;
p->data = s->next->data;
s = s->next;
p->next = LL->next;
LL->next = p;
}
return LL;
}
逆置:传入需要逆置的链表,再通过前插法创建一个新的链表,再返回该新链表,时间复杂度O(n)。
- 实验步骤
int main(void) {
LinkList L = InitList();// 创建单链表
cout << "表长为" << ListLength(L) << endl;
ShowList(L);
while (true) {
cout << "1.取值 2.查找 3.插入 4.删除 5.逆置 6.显示 7.退出" << endl;
int a = 0;
cin >> a;
switch (a)
{
case 1:
{
cout << "请输入取数编号和数据" << endl;
int b1;
ElemType c1;
cin >> b1 >> c1;
if (GetElem(L, b1, c1) == OK) {
cout << "OK" << endl;
}
else {
cout << "ERROR" << endl;
}
}
break;
case 2:
{
cout << "请输入要查找的数" << endl;
ElemType a2;
cin >> a2;
int b2 = LocateElem(L, a2);
if (b2 == 0) {
cout << "未找到" << endl;
}
else if (b2 != 0) {
cout << "该数为第" << b2 << "个数" << endl;
}
}
break;
case 3:
{
cout << "请输入要插入的数的编号和数" << endl;
ElemType a3;
int b3;
cin >> b3 >> a3;
if (ListInsert(L, b3, a3)) {
cout << "OK" << endl;
}
}
break;
case 4:
{
cout << "请输入要删除数的编号" << endl;
int b4;
cin >> b4;
if (ListDelete(L, b4)) {
cout << "OK" << endl;
}
}
break;
case 5:
L = LinkListReverse(L);
break;
case 6:
ShowList(L);
break;
case 7:
exit(1);
break;
default:
break;
}
}
return 0;
}
主函数
- 实验结果
- 思考体会
链表其实并不难,难在你没有一个链表的思维:链表必须有头指针,当中可能有结点,链表的最后一个指向:如果是单链表就指向NULL,循环链表指向他的头结点。每次定义结点,必须给出他的链域的下一个指向的结点或NULL;如果是双向链表,还要指出他的上一个指向结点。