#include <iostream>
#include "stdio.h"
#include "stdlib.h"
using namespace std;
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
//00定义线性表的链式存储结构三个:数据元素是原子类型不用struct,节点必须两个域的结构体变量,数据结构用一个4B大小原子类型指针变量即可。
//定义数据对象、结点(含数据域、指针域)
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode, *LinkList;//*ptrLNode; Linklist L L一看就是个链表;linklist r,p 一看r p给人的感觉也是链表,但实际不是; 不如ptrLNode r,p; 一看r和p就是指向节点的指针。
//定义数据结构(见上 *LinkList)。注:单链表每次插入必先循环找尾结点且不知长度,也可写个结构体,为了和教材一致用上而不用下,仅供思考拓展
typedef Struct{
struct LNode *head;//指向头结点
struct LNode *tail;//指向尾结点
int length;
}LinkList;//本实验未采用该定义,仅供拓展思想用
//01初始化一个线性表
Status InitLinkList(LinkList &L);
//02创建一个包含n个正整数值的线性表(线性表的长度n和表中元素的值随机输入)
Status CreateLinkList_R(LinkList &L);
//03将一个数x插在第i个元素前
Status LinkListInsert(LinkList L, int i, ElemType x);
//04删除第i个元素,并在删除结束后输出删除元素的值
Status LinkListDelete(LinkList L, int i, ElemType &e);
//05查找指定元素e是否在线性表中存在,若存在返回此元素的位序,否则返回0
int LocateElem(LinkList L, ElemType e);
//06查找指定位置元素的值并输出
Status Getelem(LinkList L, int i, ElemType &e);
//07输出线性表中所有元素
Status TraverseLinkList(LinkList L);
//08销毁单链表
Status DestroyLinkList(LinkList &L);
//09求单链表的长度
int ListLength(LinkList L);
//10将两个有序表合并到一个新表LC中(重复的也合并进去,非递减顺序-->)
Status OrderLinkList_Merge(LinkList &LA, LinkList &LB, LinkList &LC);
int main()
{
ElemType e, x;
int i, k;
LinkList L = NULL;
do {
cout << "\n=========单链表的操作===========";
cout << "\n 1.初始化单链表";
cout << "\n 2.创建单链表";
cout << "\n 3.在第i个位置前插入元素x";
cout << "\n 4.删除第i个元素";
cout << "\n 5.查找指定元素位置";
cout << "\n 6.查找指定位置元素";
cout << "\n 7.遍历当前单链表";
cout << "\n 8.销毁当前单链表";
cout << "\n 9.有序表合并";
cout << "\n 0.结束程序运行";
cout << "\n================================";
cout << "\n请输入您的选择(1,2,3,4,5,6,7,8,0):";
cin >> k;
switch (k)
{
case 1:
if (InitLinkList(L))
cout << " 初始化成功!";
else
cout << " 初始化失败!";
break;
case 2:
if(CreateLinkList_R(L))
cout << " 创建成功!";
else
cout << " 创建失败!";
break;
case 3:
cout << "请输入插入元素的位置i及值x:";
cin >> i >> x;
LinkListInsert(L, i, x);
break;
case 4:
cout << "请输入要删除元素的位置i:";
cin >> i;
LinkListDelete(L, i, e);
cout << "删除第" << i << "个元素的值为:" << e << endl;
break;
case 5:
cout << "请输入要查找指定元素e:";
cin >> e;
cout << "该元素的位置是:" << LocateElem(L, e) << endl;
break;
case 6:
cout << "请输入要查找元素的位置:";
cin >> i;
Getelem(L, i, e);
cout << "正在查找的第" << i << "个元素值是:" << e << endl;
break;
case 7:
cout << "当前单链表为:";
TraverseLinkList(L);
break;
case 8:
DestroyLinkList(L);
break;
case 9:
LinkList LA, LB, LC;
InitLinkList(LA);
InitLinkList(LB);
//InitLinkList(LC);//在合并代码里有LC=LA,故不用初始化,因LC利用了LA的头节点
cout << "请创建有序链表LA:";
CreateLinkList_R(LA);
cout << "请创建有序链表LB:";
CreateLinkList_R(LB);
cout << "LA、LB合并到LC:";
OrderLinkList_Merge(LA, LB, LC);
TraverseLinkList(LC);
break;
case 0:
break;
default:
cout << "无效选项,请重新输入!" << endl;
}/*switch*/
} while (k != 0);
system("pause");
return 0;
}/*main*/
//01初始化一个线性表L
Status InitLinkList(LinkList &L)
{
L = new LNode; //创建一个头结点
L->next = NULL;//指针域初始为空
return OK;
}
//02创建一个包含n个正整数值的线性表(线性表的长度n和表中元素的值随机输入---尾插法)
Status CreateLinkList_R(LinkList &L)
{
if (!L)InitLinkList(L); //线性表不存在则初始化一个线性表
//L = new LNode;
//L->next = NULL;
int n;
LinkList r, p;
r = L; //尾指针r指向尾结点(初始空表的尾结点为头结点)
cout << "请输入要创建单链表元素的个数n:";
cin >> n;
cout << "请输入 " << n << " 个正整数:";
for (int i = 0; i<n; i++)
{
p = new LNode;
cin >> p->data;
p->next = NULL;
r->next = p;
r = p; //尾指针r指向新的尾结点
}
return OK;
}
//03将一个数x插在第i个元素前
Status LinkListInsert(LinkList L, int i, ElemType x)
{
if (!L)
{
cout << "链表不存在,请先初始化创建链表";
return ERROR; //表不存在
}
if ((i<1) || i>ListLength(L) + 1)
{
cout << "输入的位置非法!";
return ERROR;
}//i值不合法
int j = 0;
LinkList p, s;
p = L;
while (j < i - 1)
{
p = p->next;
++j; //查找第i-1个结点,并另p指向该结点
}
s = new LNode;
s->data = x;
s->next = p->next; //将结点*s的指针域指向ai
p->next = s; //将结点*p的指针域指向s
return OK;
}
//04删除第i个元素,并在删除结束后输出删除元素的值
Status LinkListDelete(LinkList L, int i, ElemType &e)
{
if (!L)
{
cout << "链表不存在,请先初始化创建链表";
return ERROR; //表不存在
}
if ((i<1) || i>ListLength(L))
{
cout << "输入的位置非法!";
return ERROR;
}//i值不合法
int j = 0;
LinkList p, q;
p = L;
while (j <i - 1)
{
p = p->next;
++j; //查找第i-1个结点,并让p指向该结点。因是单链表,指针向右,后面的节点只能用前面的节点来表示
}
q = p->next; //q指向第i个要删除的结点,起暂存的作用,以便del
p->next = q->next;
e = q->data;
delete q; //释放q
return OK;
}
//05查找指定元素e是否在线性表中存在,若存在返回此元素的位序,否则返回0
int LocateElem(LinkList L, ElemType e)
{
if (!L)
{
cout << "链表不存在,请先初始化创建链表";
return ERROR; //链表不存在
}
LinkList p = L->next; //p指向第一个结点
int i = 1;
while (p&&p->data != e)
{
p = p->next;
i++;
}
if (i <= ListLength(L))
return i;
else
return 0;
}
//06查找指定位置元素的值并输出
Status Getelem(LinkList L, int i, ElemType &e)
{
if (!L)
{
cout << "链表不存在,请先初始化创建链表";
return ERROR; //表不存在
}
if ((i<1) || i>ListLength(L))
{
cout << "输入的位置非法!";
return ERROR;
} //i值不合法
LinkList p = L->next; //p指向第一个元素
int j = 1;
while (p&&j < i)
{
p = p->next;
++j;
} //找到第i个元素
e = p->data;
return OK;
}
//07输出单链表中所有元素
Status TraverseLinkList(LinkList L)
{
if (!L)
{
cout << "链表不存在!";
return ERROR; //表不存在
}
LinkList p = L->next; //p指向第一个结点
while (p)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
return OK;
}
//08销毁当前单链表
Status DestroyLinkList(LinkList &L)
{
if (!L)
{
cout << "链表不存在!\n";
return ERROR;
}
LinkList q;
while (L)
{
q = L; //q指向要删除的结点
L = L->next; //L指向q的后继结点
delete q;
} //销毁以L为头指针的单链表,释放链表中所有节点的空间
L = NULL; //虽然头节点占有的空间已经释放,但指针变量L中的值没有改变,为安全起见,置L为空,以防止对系统空间的访问
cout << "链表已销毁!" << '\n';
return OK;
}
//09求单链表的长度
int ListLength(LinkList L)
{
if (L == NULL)
{
cout << "链表不存在,请先选择2创建单链表\n";
return 0;
}
LinkList p = L->next; //p指向链表第一个结点
int len = 0;
while (p)
{
len++;
p = p->next;
}
return len;
}
//10将两个有序表LA\LB合并到一个新表LC中(重复的也合并进去,非递减顺序)
Status OrderLinkList_Merge(LinkList &LA, LinkList &LB, LinkList &LC)
{
LinkList pa, pb, pc;
pa = LA->next;//pa意思是LA中还未插入LC剩余那一段单链表的指针,当然一开始从a1到an都未插入;
pb = LB->next;//同上
LC = LA; //LC在主函数中不需要初始化,声明下即可。
pc = LC;//pc意思LC的尾结点指针,便于将上面的结点插入到LC,且插入后pc要指向新的尾结点
while (pa&&pb)
{
if (pa->data <= pb->data)
{
pc->next = pa;
pc = pa; //pc始终指向LC的尾节点
pa=pa->next; //pa指向下一节点
}
else
{
pc->next = pb;
pc = pb; //pc始终指向LC的尾节点
pb = pb->next;//pb指向下一节点
}
}//while循环中,pa pb不会同时为空,因为里面是if else 互斥,一次pc只能加一个节点
if (pa)
pc->next = pa;
else
pc->next = pb;//while循环结束后,pa、pb必有一空,一不空。
//pc->next = pa ? pa : pb;//一行即可替代上面if else,pc->next = pa含义是把pa赋值给pc->next,然后pc->next为空? 非空则pc->next=pa,空则pc->next=pb。
delete LB;
return OK;
}
//两个链表按值大小进行合并参考:https://www.cnblogs.com/wwttsqt/p/7783179.html,其中合并没调用子函数。