单链表的各种操作
运行环境:VS2022
运行位数:X64
注释齐全
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
typedef struct _LinkNode {
int data; //结构点的数据域
struct _LinkNode* next; //节点的指针域
}LinkNode, Linklist; //Linklist是头结点 LinkNode是增加的节点
//初始化
bool InitList(Linklist*& L) { //构造一个空的单链表
L = new LinkNode; //生成新结点作为头结点,用头指针 L 指向头结点
if (!L) { return false; } //失败
L->next = NULL; //头结点的指针域置空
return true;
}
bool ListInstrt_front(Linklist*& L, LinkNode* node) { // 前插法
if (!L || !node) { return false; }
node->next = L->next; //存下一个节点的地址
L->next = node; //把自己的地址赋值到上一个节点的指针域
/*
* 插入一个新元素,是先让自己的指针域指向下一个节点
* 然后在让上一个节点的指针域指向自己
*/
return true;
}
bool ListInstrt_back(Linklist*& L, LinkNode* node) { //尾插法
if (!L || !node) { return false; }
LinkNode* p = NULL;
/*
* 之所以要定义一个指针不使用原本的L是因为L是头结点
* 头结点不能移动,所以要定义一个指针移动到最后一个节点
*/
p = L;
while (p->next)p = p->next;
/*
* p->next是判断p->next是否为真
* 为真就执行p = p->next,
*因为p->next里面存的值就是下一个节点的值,把下一个节点的值赋值到p
*就进入到下一个节点了.从而一直遍历到尾结点
*/
node->next = NULL; //存的下一个节点的地址
p->next = node; //将上一个节点的指针域指向自己
return true;
}
bool LinkInsert(Linklist*& L, int i, int& e) { //在任意位置插入节点
int j = NULL;
Linklist* p, * s;
p = L;
while (p && j < i - 1) {
p = p->next;
j++;
}
if (!p || j > i - 1) {
cout << "插入失败!" << endl;
return false;
}
s = new LinkNode;
s->data = e;
s->next = p->next; //将新插入的节点的指针域指向下一个节点
p->next = s; //将上一个节点的指针域指向自己
return true;
}
void Linkprint(Linklist*& L) {
Linklist* p = NULL;
if (!L) { cout << "链表中没有数据!"; return; }
p = L->next;
while (p) {
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
bool Link_GetElem(Linklist*& L, int i, int& e) {//单链表的取值
int j = NULL;
Linklist* p = NULL;
p = L->next; //将第一个节点赋值到p
j = 1;
while (j < i && p) {
p = p->next;
j++;
}
if (!p || j > i) { return false; }
e = p->data;
return true;
}
bool Link_FindElem(Linklist* L, int e) {//按值查找
Linklist* p = NULL;
p = L->next;
while (p && p->data != e) {
p = p->next;
}
if (!p) { return false; }
return true;
}
bool LinkDelete(Linklist*& L, int i) { //单链表的删除
Linklist* p = NULL, * q = NULL;
int j = NULL;
p = L;
/*
*减一是因为要删除节点,只需要删除被删除节点的前一个节点的指针域
*因为被删除节点的前一个节点的指针域存储的就是下一个节点的地址
*只需要把被删除节点的前一个节点的指针域重新链接到不需要删除的节点就可以了
*/
while ((p->next) && (j < i - 1)) {
p = p->next;
j++;
}
if (!(p->next) || (j > i - 1)) { return false; }
/*
* q = p->next;解析
*p是被删除节点的前一个节点,p->next就是当前要删除的节点
*把当前要删除的节点暂时赋值给q;
*/
q = p->next; //临时保存被删结点的地址以备释放空间
/*
* p->next = q->next;解析
*q现在是被删除的节点,q->next是被删除节点的下一个节点
*把被删除节点的下一个节点,赋值给被删除的前一个节点
*/
p->next = q->next; //改变删除结点前驱结点的指针域
delete q; //释放被删除结点的空间
return true;
}
void LinkDestroy(Linklist*& L) {//单链表的销毁
Linklist* p = L;
cout << "销毁链表!!" << endl;
while (p) {
L = L->next; //把第一个节点的地址赋值到L
cout << "删除节点!!" << p->data << endl;
delete p; //释放节点
p = L; //把第一个节L点赋值给P
}
}
bool ListAmend(Linklist*& L, int i, int j) {//i 节点的位置, j 修改的数据
Linklist* p = NULL;
int a = NULL;
p = L;
//遍历节点
while (p && a < i) {
p = p->next;
a++;
}
if (!p || a > i) { return false; }
p->data = j;
return true;
}
void ListInstrt_back1(Linklist*& L) {
int e = NULL;
Linklist* s2 = NULL;
cout << "请输入需要插入的个数(尾插法):";
cin >> e;
while (e > 0) {
s2 = new LinkNode;
cout << "请输入数据:";
cin >> s2->data;
if (ListInstrt_back(L, s2)) {
cout << "插入成功!!" << endl;
e--;
}
else {
cout << "插入失败!!" << endl;
return;
}
}
Linkprint(L);
}
void ListInstrt_front1(Linklist*& L) {
Linklist* s2 = NULL;
int e = NULL;
cout << "请输入需要插入的个数(前插法):";
cin >> e;
while (e > 0) {
s2 = new LinkNode;
cout << "请输入数据:";
cin >> s2->data;
if (ListInstrt_front(L, s2)) {
cout << "插入成功!!" << endl;
e--;
}
else {
cout << "插入失败!!" << endl;
return;
}
}
Linkprint(L);
}
void LinkInsert1(Linklist*& L) {
int e = NULL;
int b = NULL;
cout << "请输入插入的个数:";
cin >> b;
while (b > 0) {
int a = NULL;
e = NULL;
cout << "当前数据:";
Linkprint(L);
cout << "请输插入的位置和数据(空格隔开):";
cin >> a >> e;
if (LinkInsert(L, a, e)) {
cout << "插入成功!!" << endl;
Linkprint(L);
b--;
}
else {
cout << "插入失败!!" << endl;
return;
}
}
}
void Link_GetElem1(Linklist*& L) {
int i = NULL;
int e1 = NULL;
while (true) {
cout << "请输入需要查询的节点(按0退出):";
cin >> i;
if (i == 0) { break; }
if (Link_GetElem(L, i, e1)) {
cout << "节点的数据域值是:" << e1 << endl;
}
else {
cout << "该值不存在" << endl;
}
}
}
void Link_FindElem1(Linklist*& L) {
while (true) {
int i = NULL;
cout << "请输入需要查询的值(输入0结束):";
cin >> i;
if (i == 0) { break; }
if (Link_FindElem(L, i)) {
cout << "查找的:" << i << "存在!" << endl;
}
else {
cout << "查找的:" << i << "不存在!" << endl;
}
}
}
void ListAmend(Linklist*& L) {
while (true) {
int x = NULL;
int y = NULL;
cout << "请输入需要修改数据的节点,以及修改的数据(空格隔开,按0结束):";
cin >> x >> y;
if (x == 0) { break; }
if (ListAmend(L, x, y)) {
cout << "修改成功!!" << endl;
Linkprint(L);
}
else {
cout << "修改失败!!" << endl;
return;
}
}
}
void LinkDelete1(Linklist*& L) {
while (true) {
int a = NULL;
cout << "请输入需要删除的节点(按0结束):";
cin >> a;
if (a == 0) { break; }
if (LinkDelete(L, a)) {
cout << "删除成功!!" << endl;
Linkprint(L);
}
else {
cout << "删除失败!!" << endl;
}
}
}
void function() {
Linklist* s1; //头结点
InitList(s1); //初始化一个空的单链表,也就是初始化头节点
while (true) {
int x = NULL;
string str[]{
" 单链表 \n"
"1.插入数据(尾插法) \n"
"2.插入数据(前插法) \n"
"3.任意位置插入数据 \n"
"4.按节点查询数据 \n"
"5.查询数据是否存在 \n"
"6.修改任意节点的数据 \n"
"7.查看链表中的数据 \n"
"8.删除任意节点 \n"
"9.销毁链表 \n"
"10.退出 \n"
};
cout << *str << endl;
cout << "请输入需要执行的操作:";
cin >> x;
if (x <= 0 || x > 11) { cout << "条件不成立!!" << endl; return; }
switch (x) {
case 1:
ListInstrt_back1(s1);
system("pause");
break;
case 2:
ListInstrt_front1(s1);
system("pause");
break;
case 3:
LinkInsert1(s1);
system("pause");
break;
case 4:
Link_GetElem1(s1);
system("pause");
break;
case 5:
Link_FindElem1(s1);
system("pause");
break;
case 6:
ListAmend(s1);
system("pause");
break;
case 7:
cout << "链表中的所有数据:";
Linkprint(s1);
system("pause");
break;
case 8:
LinkDelete1(s1);
system("pause");
break;
case 9:
cout << "销毁链表后,就无法进行任何对链表的操作!!" << endl;
LinkDestroy(s1);
system("pause");
break;
case 10:
exit(0);
break;
default:
break;
}
system("cls");
}
}
int main(void) {
function();
system("pause");
return 0;
}