一、实验目的
- 掌握线性表的链式存储结构的定义;
- 掌握链式存储结构结点的访问方法;
- 熟练运用链表的基本操作。
二、实验内容
1. 用linkedlist.h和linkedlist.cpp创建项目,并思考以下问题:
1)观察线性表的各接口函数的函数名,参数表,返回值;明确接口函数的调用方法。思考若要改变线性表元素的类型应如何操作?若添加新的接口函数,需要在哪些文件中进行修改?
答:若要改变线性表元素的类型应更改linkedist.h文件中的typedef char ElemType;若要添加新的接口函数应先在linkedist.h中声明函数,再在linkedist.cpp中编写函数内容
2) 在同一项目中,新建content.cpp文件,在该文件中设计主程序main函数,完成如下功能:
a) 定义管理单链表的头指针L;
b) 初始化单链表L;
c) 在L的头部依次插入 ‘a’, ‘b’, ‘c’, ‘d’ 元素;(可思考如何在尾部插入?)
d) 若L非空,则输出L的长度及L中的元素;
e) 输出L的第三个元素;
f) 输出元素 ‘a’ 的位置;
g) 在L第3个位置上插入元素 'f ',并输出L中元素;
h) 删除第2个元素,输出被删元素的值,并输出L中元素;
i) 删除用户指定的任意元素,若删除成功则输出删除后L中的元素,删除失败给出适当的提示;
j) 释放单链表L。
【参考输出效果】
如需了解程序运行过程,可在循环语句的循环体处设置断点,观察程序运行时,各变量的当前值。
已实现功能的主程序main函数如下:
#include "linkedlist.h"
int main() {
//a
LinkNode* L;
//b
InitList(L);
//c
for (int i = 0; i<4; i++){
ListInsert(L, 1, 'a'+i);
}
//d
if (!ListEmpty(L)){
cout << "当前链表长是" << ListLength(L) << ", 表中元素为:";
TraverseList(L);
}
//e
ElemType data_3;
Find_pos(L, 3, data_3);
cout << "第3个元素是 " << data_3 << endl;
//f
cout << "a在" << Find_item(L, 'a') << "号位置" << endl;
//g
ListInsert(L, 3, 'f');
cout << "在3号位插入f后,表中元素为:";
TraverseList(L);
//h
ElemType data_2;
ListDelete(L, 2, data_2);
cout << "删除第2个元素" << data_2 << "成功。表中元素为:";
TraverseList(L);
//i
ElemType delet_data;
cin >> delet_data;
cout << "请输入你想删除的元素:";
if (ListDelete(L, delet_data)){
cout << "删除" << delet_data << "成功。表中元素为:";
TraverseList(L);
}
//j
DestroyList(L);
return 0;
}
运行结果如图所示:
3) 总结使用单链表的一般步骤。
答:
1.创建一个单链表结构体
2.初始化单链表的头指针,头指针数据域为空,指针域指向第一个结点
3.对单链表进行基本操作增删查
3.1)增操作实现步骤:
在单链表的头结点之后第一个数据结点之前插入一个新结点,head指向表头结点,head->next表示表头的后继结点,指针 t 指向待插入结点。
3.2)删操作实现步骤:
首先找到被删除位置的前一个结点,并用指针 p 指向删除位置的前驱结点,指针 t 指向被删除的结点;
再将指针p所指结点的指针域修改为t所指结点的后继;
最后释放被删结点t,即delete t
3.3)查操作实现步骤:
设置一个跟踪链表结点的指针p,初始时p指向链表中的第一个结点,然后顺着next域依次指向每个结点。
每指向一个结点就判断其是否等于指定结点,若是,则返回该结点地址。否则继续向后搜索,直到p为NULL ,表示链表中无此元素,返回NULL。
2.假设单链表的数据域为递增有序的整数,设计接口函数:
bool ListInsert_order (LinkNode *L, ElemType item);
向单链表L中插入新的元素item,插入后单链表仍然有序。
linkedlist.h文件:
typedef int ElemType;
linkedlist.cpp文件:
bool ListInsert_order(LinkNode *L, ElemType item)
{
LinkNode *p = L;
while (p->next->data < item &&p->next)
p = p->next;
LinkNode *t = new LinkNode;
t->data = item;
t->next = p->next;
p->next = t;
return true;
}
content.cpp文件:
#include "linkedlist.h"
int main()
{
LinkNode *L;
InitList(L);
ElemType sorted_nums[] = { 3, 6, 9, 12 };
for (int i = 1; i <= 4; i++)
ListInsert(L, i, sorted_nums[i - 1]);
cout << "有序序列:" << endl;
TraverseList(L);
ListInsert_order(L, 8);
cout << "插入8后:" << endl;
TraverseList(L);
return 0;
}
【课后练习】
3. 假设单链表的数据域为整数,且数值都不相同,设计接口函数:
bool Delete_max (LinkNode *L, ElemType &item);
把单链表中数据域最大的结点删除,其余结点继续保留。
linkedlist.h文件:
typedef int ElemType;
linkedlist.cpp文件:
bool Delete_max(LinkNode *L, ElemType &item)
{ LinkNode *p = L, *max = L->next, *pre_to_max = L;
while (p->next) {
if (p->next->data > max->data) {
max = p->next;
pre_to_max = p;
}
p = p->next;
}
if (max != NULL) {
pre_to_max->next = max->next;
item = max->data;
delete max;
return true;
}
return false;
}
content.cpp文件:
#include "linkedlist.h"
int main()
{
LinkNode *L;
InitList(L);
ElemType nums[] = { 9, 18, 10, 13 };
for (int i = 1; i <= 4; i++)
ListInsert(L, i, nums[i - 1]);
cout << "序列为:";
TraverseList(L);
ElemType temp;
if (Delete_max(L, temp)) {
cout << "删除的最大值为:" << temp << endl;
cout << "删除后的序列为:";
TraverseList(L);
}
return 0;
}
4.修改项目,以结构体存储学生的两项信息,即:{学号,成绩}:{101,85},{103,90.5},{104,73},{105, 55},并且要让下面的主函数可以正常运行。(此处每对大括号表示一个结构体)
链表结点示意图:
【提示1】重新设计链表中的元素类型ElemType;
【提示2】修改链表中的相关操作以符合新的元素类型;
【提示3】设计新的接口,删除链表中学号为number的结点。
int main()
{ LinkNode *L;
InitList(L);
ElemType A[]={ {101,85}, {103,90.5}, {104,73}, {105,55} };
for(int i=0; i<4; i++)
ListInsert(L, i+1, A[i]);
cout << "学号 成绩" << endl;
TraverseList(L);
ListDelete(L, 103);
cout << "学号 成绩" << endl;
TraverseList(L);
DestroyList(L);
return 0;
}
“linkedlist.h”文件中:
struct Grade
{
int id;
float score;
};
typedef Grade ElemType;
typedef struct LNode
{ ElemType data;
struct LNode *next;
} LinkNode;
//删除链表中学号为number的结点
bool ListDelete (LinkNode *L, int number);
“linkedlist.cpp”文件中,将Find_item函数注释:
//遍历单链表
void TraverseList(LinkNode *L)
{ //L为指向单链表的头指针
LinkNode *p=L->next;
while(p)
{
cout<<p->data.id<<" "<<p->data.score<<endl;
p=p->next;
}
cout<<endl;
}
//删除链表中学号为number的结点
bool ListDelete (LinkNode *L, int number)
{
LinkNode *p=L, *t;
while( p->next && p->next->data.id != number){ //查找number的前驱
p=p->next;
}
if(p->next==NULL){ //查找不成功,退出运行
cout<<"删除元素不存在"<<endl;
return false;
}
t=p->next; //①t为被删除结点
p->next=t->next; //②删除t的链接关系
delete t; //③释放被删结点
return true;
}