(1)实验目的
通过该实验,深入理解链表的逻辑结构、物理结构等概念,掌握链表基本操作的编程实现,熟练掌握C语言中指针的操作。和实验2对比,掌握线性结构两种不同存储方式的区别。
(2)实验内容
编程实现链表下教材第二章定义的线性表的基本操作,最好用菜单形式对应各个操作,使其编程一个完整的小软件。注意,每个功能模块一定要考虑非法的情况,并作出相应的提示,例如:求前驱,要分别能够测试第一个元素的前驱、其他正常的元素的前驱、输入一个在表中不存在的元素求其前驱,这三种情况应给出相应的提示语和结果值;插入和删除时要考虑插入或删除的位置是否合法等。
(3)实验要求:
菜单项包括:
1.初始化或重置链表
2.销毁链表
3.清空链表
4.链表长度
5.指定位置的元素值
6.链表已存在元素的位序
7.求输入元素的直接前驱
8.求输入元素的直接后继
9.在第i个位置插入一个元素
10.删除第i个元素
11.输出有的链表元素
12.初始化并用头插法(或尾插法)输入元素
13.实现单链表的逆序存放
要求:所有的提示语和输出语句不允许出现在自定义的函数中(输出函数除外),只能在main函数中出现提示语。
注:销毁链表时需要循环释放每个结点所占用的空间。
注:求前驱是指,输入一个元素值(而不是位置),求该元素在顺序表中的直接前驱元素值。求后继是指:输入一个元素值(而不是位置),求该元素在顺序表中的直接后继元素值。
(4)验收/测试用例
参考实验2
#include<iostream>
using namespace std;
typedef int ElemType;
typedef int Status;
typedef struct Lnode {
ElemType data; //数据域
struct Lnode* next;//指针域
}Lnode, * LinkList;
#define OK 1
#define ERROR 0
//1.初始化或重置链表
Status InitList(LinkList& L) {
L = (LinkList)malloc(sizeof(Lnode));//申请内存空间
if (L == NULL) {
exit(OVERFLOW);
}//内存空间分配失败,退出程序,并返回OVERFLOW的值给主调进程
L->next = NULL;//next节点指向空
return OK;
}
//2.销毁链表
Status DeleteList(LinkList& L) {
LinkList p;//定义一个指针
while (L) {//while循环重复进行,实现释放全部节点
p = L;//设置一个指针p与头指针相投,并依次断开头部指针
L = L->next;
free(p);//释放节点的内存
}
L = NULL;//设置头指针为空
return OK;
}
//3.清空链表
Status ClearList(LinkList& L) {
LinkList p, q;//定义两个指针
p = L->next;//p为首元节点
if (!p) {//p不存在的情况下,链表中不存在元素,返回错误
return ERROR;
}
while (p) {//当p存在时进行循环
q = p->next;//q为p的下一个节点
free(p);//释放p的空间
p = q;//令p与下一个节点相连
}
L->next = NULL;//设置头指针为空
return OK;
}
//4.链表长度
Status ListLength(LinkList& L) {
int i = 0;//定义一个整型变量并初始化为0,代表头节点
LinkList p;//定义一个指针
p = L;//p指向头节点
while (p->next) {//当p指向的地址不为空时,进入循环
p = p->next;//p指向下一个节点
i++;//当节点不为空时,i加1,直到p指向的地址为空时结束
}
return i;//返回长度值
}
//5.指定位置的元素值
Status GetElem(LinkList L, int i, ElemType& e) {
LinkList p;
p = L->next;//p指向首元节点
int j = 1;
while (p && j < i) {//while循环寻找所求元素的位置,当p不为空并且j<输入位置时进入循环
p = p->next;
++j;
}
if (!p || j > i) {//当输入的位置过大或过小时,输出错误
return ERROR;
}
e = p->data;
return e;
}
//6.链表已存在元素的位序
Status ListLocate(LinkList& L, int&i, ElemType e) {
LinkList p;
i = 1;
p = L->next;//p指向首元节点
while (p) {//当p不为空时,进入循环
if (p->data == e) {//当元素等于输入数字时,结束循环
return OK;
}
i++;
p = p->next;//p等于p的下一个元素
}
return ERROR;//当表中的所有元素都不相等时,返回错误
}
//7.求输入元素的直接前驱
Status PriorList(LinkList L, ElemType& e) {
LinkList p, q = nullptr;
int i = 1;
p = L->next;
while (p != NULL) {
if (p->data == e && i != 1)
{
return q->data;
}
else if (p->data==e&&i==1)
{
return ERROR;
}
q = p;
p = p->next;
i++;
}
return ERROR;
}
//8.求输入元素的直接后继
Status NextList(LinkList L, ElemType& e) {
int i = 0;
LinkList p;
p = L;
while (p != NULL)
{
if (p->data == e)
{
if (p->next != NULL)
return p->next->data;
else
return ERROR;
}
p = p->next;
}
return ERROR;
}
//9.在第i个位置插入一个元素
Status ListInsert(LinkList& L, int i, ElemType& e) {
LinkList p, s;
p = L;
int j = 0;
while (p && j < i - 1) {
p = p->next;
++j;
}
if (!p || j > i - 1) {
return ERROR;
}
s = (LinkList)malloc(sizeof(Lnode));
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
//10.删除第i个元素
Status ListDelete(LinkList& L, int i) {
LinkList p, s;
int j = 0;
p = L;
while (p->next && j < i - 1) {
p = p->next;
++j;
}
if (!p->next || j > i - 1) {
return ERROR;
}
s = p->next;
p->next = s->next;
free(s);
return OK;
}
//11.输出所有的链表元素
Status OutPutList(LinkList& L) {
LinkList p;
p = L;
if (p->next == NULL) {//当链表为空时,直接输出错误
return ERROR;
}
while (p->next != NULL) {
p = p->next;
cout << p->data << " ";
}
return OK;
}
//12.初始化并用头插法(或尾插法)输入元素
// 头插法
Status HeadList(LinkList& L, int n) {
LinkList p;
int i;
L = (LinkList)malloc(sizeof(Lnode));
L->next = NULL;
for (i = n;i > 0;i--) {
p = (LinkList)malloc(sizeof(Lnode));
cin >> p->data;
p->next = L->next;
L->next = p;
//L->next = L;
}
OutPutList(L);
return OK;
}
// 尾插法
Status TailList(LinkList& L, int n, ElemType& e) {
LinkList p, q;
int i;
L = (LinkList)malloc(sizeof(Lnode));
L->next = NULL;
p = L;
for (i = 0;i < n;i++) {
q = (LinkList)malloc(sizeof(Lnode));
cin >> e;
q->data = e;
q->next = NULL;
p->next = q;
p = p->next;
}
OutPutList(L);
return OK;
}
//13.实现单链表的逆序存放
Status ListInverse(LinkList& L) {
LinkList p, q;
p = L->next;
L->next = NULL;
while (p) {
q = p;
///
p = p->next;
q->next = L->next;
L->next = q;
}
OutPutList(L);
return OK;
}
int main() {
LinkList L = 0;
bool initlist = false;
ElemType e = 0;
int op = 0;
int i;
cout << "1.初始化或重置链表" << endl;
cout << "2.销毁链表" << endl;
cout << "3.清空链表" << endl;
cout << "4.链表长度" << endl;
cout << "5.指定位置的元素值" << endl;
cout << "6.链表已存在元素的位序" << endl;
cout << "7.求输入元素的直接前驱" << endl;
cout << "8.求输入元素的直接后继" << endl;
cout << "9.在第i个位置插入一个元素" << endl;
cout << "10.删除第i个元素" << endl;
cout << "11.输出所有的链表元素" << endl;
cout << "12.初始化并用头插法(或尾插法)输入元素" << endl;
cout << "13.实现单链表的逆序存放" << endl;
cout << "输入一个负数,退出程序" << endl;
int n = 1;
while (n) {
int select;
cout << "------------------------------------" << endl;
cout << "请输入你选择的功能:";
cin >> select;
switch (select) {
case 1:
if (InitList(L)) {
initlist = true;
cout << "链表初始化成功" << endl;
}
else {
cout << "错误,链表初始化失败" << endl;
}
break;
case 2:
if (initlist == true) {
if (DeleteList(L)) {
initlist = false;
cout << "链表销毁成功" << endl;
}
}
else {
cout << "请先初始化链表" << endl;
}
break;
case 3:
if (initlist == true) {
if (ClearList(L)) {
cout << "链表已清空" << endl;
}
else {
cout << "链表为空" << endl;
}
}
else {
cout << "请先初始化链表" << endl;
}
break;
case 4:
if (initlist == true) {
if (ListLength(L)) {
cout << "链表长度为" << ListLength(L) << endl;
}
else {
cout << "链表为空" << endl;
}
}
else {
cout << "请先初始化链表" << endl;
}
break;
case 5:
if (initlist == true) {
if (L->next != NULL) {
do {
cout << "请输入你要获取元素的位置:";
cin >> i;
if (GetElem(L, i, e)) {
cout << "第" << i << "个元素为:" << GetElem(L, i, e) << endl;
}
else {
cout << "你要获取的位置错误" << endl;
}
cout << "1.继续 2.退出" << " ";
cin >> op;
} while (op == 1);
}
else {
cout << "链表为空" << endl;
}
}
else {
cout << "请先初始化链表" << endl;
}
break;
case 6:
if (initlist == true) {
if (L->next != NULL) {
do {
int i = 1;
cout << "请输入你要获取位置的元素:";
cin >> e;
if (ListLocate(L, i, e)) {
cout << "元素" << e << "的位序是:" << i << endl;
}
else {
cout << "此元素不存在" << endl;
}
cout << "1.继续 2.退出" << " ";
cin >> op;
} while (op == 1);
}
else {
cout << "链表为空" << endl;
}
}
else {
cout << "请先初始化链表" << endl;
}
break;
case 7:
if (initlist == true) {
if (L->next != NULL) {
cout << "请输入你要求前驱的元素:";
cin >> e;
i = 1;
if (PriorList(L, e) == ERROR) {
cout << "首元素无前驱或元素不存在" << endl;
}
else {
cout << "元素" << e << "的前驱为:" << PriorList(L, e) << endl;
}
}
else {
cout << "链表为空" << endl;
}
}
else {
cout << "请先初始化链表" << endl;
}
break;
case 8:
if (initlist == true) {
cout << "请输入你要求后继的元素:";
cin >> e;
if (NextList(L, e) == ERROR) {
cout << "尾元素无后继或元素不存在" << endl;
}
else {
cout << "元素" << e << "的后继为:" << NextList(L, e) << endl;
}
}
else {
cout << "请先初始化链表" << endl;
}
break;
case 9:
if (initlist == true) {
int lo;
do {
int i = ListLength(L);
cout << "请输入你要插入的位置:";
cin >> lo;
if (lo <= 0) {
cout << "插入位置过小" << endl;
}
else if (lo > i + 1) {
cout << "插入位置过大" << endl;
}
else {
cout << "请输入你要插入的元素:";
cin >> e;
if (ListInsert(L, lo, e)) {
cout << "插入成功" << endl;
}
else {
cout << "插入失败" << endl;
}
}
cout << "1.继续 2.退出" << " ";
cin >> op;
} while (op == 1);
}
else {
cout << "请先初始化链表" << endl;
}
break;
case 10:
if (initlist == true) {
if (L->next != NULL) {
do {
cout << "请输入你要删除的位置:";
cin >> i;
if (ListDelete(L, i)) {
cout << "删除成功" << endl;
}
else {
cout << "删除位置错误" << endl;
}
cout << "1.继续 2.退出" << " ";
cin >> op;
} while (op == 1);
}
else {
cout << "链表为空" << endl;
}
}
else {
cout << "请先初始化链表" << endl;
}
break;
case 11:
if (initlist == true) {
if (L->next != NULL) {
OutPutList(L);
cout << endl;
}
else {
cout << "链表为空" << endl;
}
}
else {
cout << "请先初始化链表" << endl;
}
break;
case 12:
{cout << "1.初始化并用头插法输入元素" << endl;
cout << "2.初始化并用尾插法输入元素" << endl;
cout << "输入负数退出程序" << endl;
cout << "请输入你的选择:";
int i;
cin >> op;
switch (op) {
case 1:
cout << "头插法输入元素" << endl;
cout << "请输入你要插入的元素个数:";
cin >> i;
cout << "请输入你要插入的元素:";
HeadList(L, i);
initlist = true;
cout << endl;
break;
case 2:
cout << "尾插法输入元素" << endl;
cout << "请输入你要插入的元素个数:";
cin >> i;
cout << "请输入你要插入的元素:";
TailList(L, i, e);
initlist = true;
cout << endl;
break;
default:
if (op < 0) {
cout << "退出程序" << endl;
}
}
break;
case 13:
if (initlist == true) {
if (L->next != NULL) {
ListInverse(L);
cout << endl;
}
else {
cout << "链表为空" << endl;
}
}
else {
cout << "请先初始化链表" << endl;
}
break;
default:
if (select < 0) {
cout << "退出程序" << endl;
n = 0;
}
}
}
}
}