链表的基本思想
通过指针将数据连接起来
整个数据结构中,很重要的一点是,初始化和销毁对应,插入和删除对应,有malloc(new)有free(delete),一定要对应。
插入的基本思想:
链表的各项操作,最关键的,其实就是找到被操作元素的上一个元素,插入位置的上一个元素,或者要删除元素的上一个元素,这都是非常关键的,同时也要注意,
链表有个最大的特点,就是头指针所指向的位置,不放任何元素
删除的基本思想
静态链表和动态链表中,都是手动插入元素,而且编程人员是知道要插入数据的数据类型的,静态链表可操作性较差,动态链表比较灵活,但是二者总体上都无法完成封装,总归还是面对过程变成
关于链表更加具有适应性和更加详细的说明见:
数据结构:单向链表:https://blog.csdn.net/qq_41605114/article/details/104396149
其中对各个部分的讲解比较详细,以下程序都比较简单,整个链表的基本思想也如上图所示。
静态链表:(在无指针的编程语言中实现链表)
大小固定,插入元素是固定的。一般会设置一个元素为用户自定义类型的数组,大小是固定的。
例如:
#define MAX 1000
typedef struct StaticList
{
int data;存放数据
int cur;//用下标来代替指针
}SL;
SL Test[MAX];
下面的程序显然没有这么做,只是在思想上重现了静态链表
(图源:《大话数据结构》)
.h
//静态链表
struct LinkContentStatic
{
int data;
struct LinkContentStatic * next;
};
.cpp
LinkContentStatic node1 = {10,nullptr};
LinkContentStatic node2 = {20,nullptr};
LinkContentStatic node3 = {30,nullptr};
LinkContentStatic node4 = {40,nullptr};
LinkContentStatic node5 = {50,nullptr};
LinkContentStatic node6 = {60,nullptr};
node1.next = &node2;
node2.next = &node3;
node3.next = &node4;
node4.next = &node5;
node5.next = &node6;
//如何遍历这个链表
LinkContentStatic * PCurrent = &node1;
while(PCurrent!=nullptr)
{
qDebug()<<"Item:"<<PCurrent->data;
PCurrent = PCurrent->next;
}
输出:
动态链表:
元素也是提前插入的,操作过程中也可以选择插入元素,删除元素等操作
链表有个最大的特点,就是头指针所指向的位置,不放任何元素
.h
struct LinkNode
{
int data;
LinkNode * next;
};
//初始化
LinkNode * init_dynamic();
//在oldval后面插入一个newval
void InsertByValue_dynamic(LinkNode * header,int oldval,LinkNode * newval);
//删除val的链表
void remove_dynamic(LinkNode * header,int delValue);
//遍历
void Foreach_dynamic(LinkNode * header);
//销毁
void destroy_dynamic(LinkNode * header);
//清空
void clear_dynamic(LinkNode * header);
//大小
int size_dynamic(LinkNode * header);
.cpp
//初始化
LinkNode * init_dynamic()
{
LinkNode * mydynamci = new LinkNode;//注意,在此处new了,那么就要在销毁的部分delete
mydynamci->data = 0;
mydynamci->next = nullptr;
return mydynamci;
}
//在oldval的位置插入一个newval,old数据在new后面
void InsertByValue_dynamic(LinkNode * header,int oldval,LinkNode * newval)
{
if(nullptr == header)
return;
LinkNode * pfind= header;
LinkNode * PCurrent = header;
int place = 0;
bool flag = true;//找到元素的标志位
while (pfind->next!=nullptr)
{
if(oldval == pfind->next->data)
{
flag = false;
break;
}
pfind = pfind->next;
place++;//old 的 前一个元素的位置
}
//如果找到了要找的元素,则进行插入操作
if(flag == false)
{
for(int i = 0;i<place;++i)
{
PCurrent = PCurrent->next;
}
LinkNode * temp= PCurrent->next;//old所在的位置
PCurrent->next = newval;
newval->next = temp;
}
else
{
qDebug()<<"未找到要插入的位置";
}
}
//删除值为val的链表
void remove_dynamic(LinkNode * header,int delValue)
{
if(nullptr == header)
return;
int place = 0;
bool flag = true;
LinkNode * pCurrent = header;
LinkNode * pfind= header;
//while循环中,找要删除的数val
while (pfind->next!=nullptr)
{
if(delValue == pfind->next->data)
{
flag = false;
break;
}
pfind = pfind->next;
place++;//最后值就是要删除元素前一个元素的位置
}
if(flag == false)//确保有找到这要删除的变量
{
LinkNode * del =nullptr;
for(int i = 0;i<2;++i)
{
pCurrent = pCurrent->next;
}
del = pCurrent->next;
pCurrent->next = del->next;
del->next = nullptr;
}
else
{
qDebug()<<"未找到该元素";
}
}
//遍历
void Foreach_dynamic(LinkNode * header)
{
if(nullptr == header)
return;
while (header->next!=nullptr)
{
qDebug()<<"输出:"<<header->next->data;
header = header->next;
}
}
//清空
void clear_dynamic(LinkNode * header)//接触链表的所有next指针指向即可,从头向尾解除
{
if(nullptr == header)
return;
LinkNode * pCurrent = header;
LinkNode * delitem = nullptr;
int size = size_dynamic(header);
if(size == 0)
{
qDebug()<<"大小为0,不用清空";
return;
}
else
{
while(pCurrent->next!=nullptr)
{
delitem = pCurrent->next;
pCurrent->next = nullptr;
pCurrent = delitem;
}
}
}
//大小
int size_dynamic(LinkNode * header)
{
if(nullptr == header)
return 0;
int size = 0;
LinkNode * pCurrent = header;
while(pCurrent->next!=nullptr)
{
++size;
pCurrent = pCurrent->next;
}
return size;
}
//销毁
void destroy_dynamic(LinkNode * header)
{
if(nullptr == header)
return;
delete header;
}
具体执行内容:
//动态链表
qDebug()<<"动态链表";
LinkNode td1 = {10,nullptr};
LinkNode td2 = {20,nullptr};
LinkNode td3 = {30,nullptr};
LinkNode td4 = {40,nullptr};
LinkNode td5 = {50,nullptr};
LinkNode td6 = {60,nullptr};
LinkNode * dynamic = init_dynamic();
dynamic->next = &td1;
td1.next = &td2;
td2.next = &td3;
td3.next = &td4;
td4.next = &td5;
td5.next = &td6;
qDebug()<<"遍历";
Foreach_dynamic(dynamic);
qDebug()<<"链表大小:"<<size_dynamic(dynamic);
qDebug()<<"删除30";
remove_dynamic(dynamic,30);
qDebug()<<"遍历";
Foreach_dynamic(dynamic);
qDebug()<<"链表大小:"<<size_dynamic(dynamic);
qDebug()<<"删除90(链表中没有的元素)";
remove_dynamic(dynamic,30);
//插入元素
qDebug()<<"插入元素400,在50的前面";
LinkNode td7 = {400,nullptr};
InsertByValue_dynamic(dynamic,50,&td7);
qDebug()<<"遍历";
Foreach_dynamic(dynamic);
qDebug()<<"链表大小:"<<size_dynamic(dynamic);
qDebug()<<"清空";
clear_dynamic(dynamic);
qDebug()<<"链表大小:"<<size_dynamic(dynamic);
qDebug()<<"验证:td1"<<td1.next<<endl
<<"验证:td2"<<td2.next<<endl
<<"验证:td3"<<td3.next<<endl
<<"验证:td4"<<td4.next<<endl
<<"验证:td5"<<td5.next<<endl
<<"验证:td6"<<td6.next<<endl;
qDebug()<<"销毁";
destroy_dynamic(dynamic);
输出:
大小插入都是灵活的