学习链表之前需要先将指针弄懂,指针不懂的话理解链表难如登天。
1.创建链表:
创建链表的首要条件就是必须先创建一个结构体,结构体中存放你所需要的参数以及用于下一节的指针。
#include<iostream>
using namespace std;
struct link
{
int num;
float sore;
link* next;
};
如图中的代码所示,链表中的每个节点就像是一个高级数组,但是数组中可以指定不同的数据类型,且必须要有一个指向下一个节点的地址。
link* creatlink()//因为返回值要返回一个link类型的地址
{
link* now = new link, * head, * pend; //申请一个一个头内存,并且创建头尾link指针
cin >> now->num >> now->sore;//给头内存输入内容
head = nullptr;//给头尾指针一个初始值
pend = nullptr;
while (now->num!=0)//输入0结束输入
{
if (head == nullptr)//如果这是第一个内存则成为头
{
head = now;
}
else
{
pend->next = now;//不是第一个则是目前最后一个所以要之前结尾内存的下一个指向这个新内存的地址
}
pend = now;//将当前内存作为最后一个
now = new link;//重新申请内存空间
cin >> now->num >> now->sore;
}
pend->next = nullptr;
delete now;
return head;
}
如图所示,链表中有两个特殊的节点,即头节点和尾节点,其余的节点都具有一个前驱节点和后续节点,头节点没有前驱,尾节点没有后续节点,在进行链表操作时头尾节点是非常重要的。
2.增加新节点
增加新节点有许多种方法,这篇作为入门篇仅介绍一个头插法
头插法顾名思义即开辟一个新节点作为头,将新的头下一节点的指针指向老的头节点即可将新节点加入链表当中,这也是增删改查中唯一不需要遍历链表的操作。
link* addlink(link* head, int num, float sore)//头插法与尾插法相似
{
link* p1=new link;//开辟新内存
p1->num = num;//赋值
p1->sore = sore;
p1->next = head;//将下一个节点指向老头
return p1;//返回新头节点的地址
}
3.删除节点
删除节点只需将要删除的节点断开,再将断开的两端连接起来即可。
link* deletelink(link* delcontent,int delnum)
{
link* p1, *p2=nullptr;//定义link类型指针,p1用于遍历,p2用于记录上一个内存
p1 = delcontent;//p1先记录头节点
while (p1->num!=NULL)
{
if (p1->num==delnum&&p1==delcontent)//如果要删除的是头节点那么只需要让头节点等于下一个节点即可
{
delcontent = p1->next;
break;
}
else if (p1->num == delnum)
{
p2->next = p1->next; //将上一个内存的下一个地址指向当前的下一个内存地址
break;
}
else //没找到则p2记录下次遍历的前一个节点,p1往后遍历
{
p2 = p1;
p1 = p1->next;
}
}
return delcontent;//返回头节点
}
4.更改节点
更改节点与数组查找类似,遍历查找即可
link* changelink(link *head,int changenum,float changesore)//遍历找到之后更改内存中的值
{
link* p1 = head;//存储头节点
while (head!=NULL)//遍历链表
{
if (head->num == changenum)
{
head->sore = changesore;
break;
}
else
{
head = head->next;
}
}
return p1;
}
5.查询链表中的元素
操作思路与更改类似并且更要简单
void findlink(link *head,int findnum)//查找与删除类似,找到之后直接输出,找不到继续遍历
{
while (head!=NULL)
{
if (head->num != findnum)
{
head = head->next;
}
else
{
cout <<"序号: " << head->num <<"成绩: " << head->sore<<"\n";
break;
}
}
}
6.链表的输出
与数组输出类似遍历输出
void printlink(link* content)
{
while (content!=nullptr)
{
cout << "序号: " << content->num << " 成绩: " << content->sore<<"\n";
content = content->next;
}
}
7.完整测试代码
#include<iostream>
using namespace std;
struct link
{
int num;
float sore;
link* next;
};
link* creatlink()//因为返回值要返回一个link类型的地址
{
link* now = new link, * head, * pend; //申请一个一个头内存,并且创建头尾link指针
cin >> now->num >> now->sore;//给头内存输入内容
head = nullptr;//给头尾指针一个初始值
pend = nullptr;
while (now->num!=0)//输入0结束输入
{
if (head == nullptr)//如果这是第一个内存则成为头
{
head = now;
}
else
{
pend->next = now;//不是第一个则是目前最后一个所以要之前结尾内存的下一个指向这个新内存的地址
}
pend = now;//将当前内存作为最后一个
now = new link;//重新申请内存空间
cin >> now->num >> now->sore;
}
pend->next = nullptr;
delete now;
return head;
}
void printlink(link* content)
{
while (content!=nullptr)
{
cout << "序号: " << content->num << " 成绩: " << content->sore<<"\n";
content = content->next;
}
}
//单链表的删除遍历一遍链表如果查找到要删除的内容则上一个内存的下一个地址指向当前的下一个内存地址
link* deletelink(link* delcontent,int delnum)
{
link* p1, *p2=nullptr;//定义link类型指针,p1用于遍历,p2用于记录上一个内存
p1 = delcontent;//p1先记录头节点
while (p1->num!=NULL)
{
if (p1->num==delnum&&p1==delcontent)//如果要删除的是头节点那么只需要让头节点等于下一个节点即可
{
delcontent = p1->next;
break;
}
else if (p1->num == delnum)
{
p2->next = p1->next; //将上一个内存的下一个地址指向当前的下一个内存地址
break;
}
else //没找到则p2记录下次遍历的前一个节点,p1往后遍历
{
p2 = p1;
p1 = p1->next;
}
}
return delcontent;//返回头节点
}
void findlink(link *head,int findnum)//查找与删除类似,找到之后直接输出,找不到继续遍历
{
while (head!=NULL)
{
if (head->num != findnum)
{
head = head->next;
}
else
{
cout <<"序号: " << head->num <<"成绩: " << head->sore<<"\n";
break;
}
}
}
link* changelink(link *head,int changenum,float changesore)//遍历找到之后更改内存中的值
{
link* p1 = head;
while (head!=NULL)
{
if (head->num == changenum)
{
head->sore = changesore;
break;
}
else
{
head = head->next;
}
}
return p1;
}
link* addlink(link* head, int num, float sore)//头插法与尾插法相似
{
link* p1=new link;
p1->num = num;
p1->sore = sore;
p1->next = head;
return p1;
}
void main()
{
link* creatlink();
void printlink(link * head);
link* deletelink(link * delcontent, int delnum);
link* changelink(link * head, int changenum, float changesore);
link* addlink(link * head, int num, float sore);
cout << "请输入链表内容:" << "\n";
link* p1= creatlink();
printlink(p1);
int num;
cout << "输入0结束程序,1删除,2查找,3修改,4添加\n";
while (true)
{
cin >> num;
switch (num)
{
case 1:
{
int del;
cin >> del;
p1 = deletelink(p1, del);
printlink(p1);
continue;
}
case 2:
{
int find;
cin >> find;
findlink(p1, find);
continue;
}
case 3:
{
int num;
float sore;
cin >> num >> sore;
printlink(changelink(p1,num,sore));
continue;
}
case 4:
{
int num;
float sore;
cin >> num >> sore;
p1 = addlink(p1, num, sore);
printlink(p1);
continue;
}
}
}
}
总结:单链表操作中最重要的莫过于对指针的理解,如果觉得此文章难以理解应先学习指针