什么是链表???
链表是由一系列节点组成,每个节点包含两个域,一个是数据域,一个是节点域。数据域是用来保存用户数据,另外一个是指针域。链表在内存是非连续的。
拿到链表的第一个节点,就相当于拿到整个链表。
带头结点的好处就是对链表操作完成后,第一个节点永远是头结点。
一、静态链表
不带头结点的静态链表:!!!
#include<stdio.h>
#include<stdlib.h>
//不带头结点的静态链表
//链表结点类型定义
typedef struct Linknode
{
int data;
struct Linknode *next;
}Linknode;
void text()
{
Linknode node1 = { 10, NULL };
Linknode node2 = { 20, NULL };
Linknode node3 = { 30, NULL };
Linknode node4 = { 40, NULL };
Linknode node5 = { 50, NULL };
node1.next = &node2;
node2.next = &node3;
node3.next = &node4;
node4.next = &node5;
//如何遍历整个链表?先设置一个指针指向头结点,然后移动指针到下一个结点
Linknode *pcurrent=&node1;//为了让这个指针指向链表的每个结点
while (pcurrent!=NULL)
{
printf("%d\n", pcurrent->data);
pcurrent = pcurrent->next;
}
}
int main()
{
text();
system("pause");
return 0;
}
二、动态链表
初始化链表
1.尾插法建立链表
//初始化链表
struct Linknode *Init_Linklist()
{
Linknode *header = malloc(sizeof(Linknode));//这里是创建了一个头结点,并为其分配内存空间
header->data = 1;//这里的数据随便,因为头结点的数据是不会被使用的
header->next = NULL;//相当于以及创建了一个空的链表
int val = -1;
Linknode *rear = header;//这里定义一个指向尾结点的指针方便插入后续结点
while (true)
{
printf("请输入插入的数据:\n");
scanf_s("%d", &val);
if (val == -1)
break;
//先创建新结点
Linknode *newnode = malloc(sizeof(Linknode));
//这里创建新结点和静态链表不同的地方在于结构体指针指向,我自己是这么理解的
newnode->data = val;
newnode->next = NULL;
rear->next = newnode;//在尾部插入结点
rear = newnode;//更新尾部结点
}
return header;
}
2.头插法建立链表
!!!之所以叫头插法是因为每次插入的结点都跟在头结点的后面,L就相当于头结点
如果要插入1,2,3,4,5那么使用头插法插入后的顺序就如图所示:
void Create_Linklist(Linknode *header,int a[],int n)
{
//头插法创建链表
//核心代码
struct Linknode *header = malloc(sizeof(Linknode));
struct Linknode *p;
header->next = NULL;
for (int i = 0; i < n; i++)
{
struct Linknode *p = malloc(sizeof(Linknode));
p->data = a[i];
p->data = header->next;
header->next = p;
}
}
三、动态链表的基本操作
1.遍历
//遍历结点
void print_Linklist(Linknode *header)
{
Linknode *pcurrent = header->next;
if (header == NULL)
return;
while (pcurrent != NULL)
{
printf("%d\n", pcurrent->data);
pcurrent = pcurrent->next;//让定义的结点指向要打印的结点
}
}
2.查找
struct Linknode* Find_Linklist(header)
{
struct Linknode *pRev = header;
struct Linknode *pCurrent = pRev->next;//指向当前位置的结点
while (pCurrent!=NULL)
{
if (pCurrent->data == old)
break;
pRev = pCurrent;
pCurrent = pCurrent->next;
}
if (pCurrent == NULL)//如果pCurrent为空,说明根本就没有找到old
{
return;
}
return pCurrent;
}
3.插入
需要用两个指针,一个pRev指向前一个结点,一个pCurrent指向要插入位置的结点
!!!在这里一定要先连接路线1,在连接路线2,。因为如果先连接路线2那么pCurrent结点的地址就会丢失
核心代码:
newnode->next=pRev->next;
pRev->next=newnode;
//在链表中值为old的后面插入数据new
void Insert_Linklist(Linknode *header, int old, int new)
{
if (header == NULL)//先判断一下是不是空链表
return;
//定义两个辅助指针变量
struct Linknode *pRev = header;
struct Linknode *pCurrent = pRev->next;//指向当前位置的结点
while (pCurrent!=NULL)
{
if (pCurrent->data == old)
break;
pRev = pCurrent;
pCurrent = pCurrent->next;
}
if (pCurrent == NULL)//如果pCurrent为空,说明根本就没有找到old
{
return;
}
//如果没有找到数据,把新结点插入到尾部就不要上述if语句的内容即可
//先创建新结点
struct Linknode *newnode = malloc(sizeof(Linknode));
newnode->data = new;
newnode->next = NULL;
//新结点插入链表
newnode->next = pRev->next;
pRev->next = newnode;
}
4.清空
清空链表的意思就是链表只剩一个头结点!!!
void Remove_Linklist(Linknode *header, int val)
{
if (header == NULL)
return;
//辅助指针变量
struct Linknode *pCurrent = header->next;
while (pCurrent->next != NULL)
{
//先保存一下当前结点的下一个结点地址
struct Linknode *pnext = pCurrent->next;
//释放当前结点的内存
free(pCurrent);
//pCurrent指向下一结点
pCurrent = pnext;
}
header->next = NULL;
}
5.删除
删除值为val的结点,就是把值为val结点的前驱结点和后继节点连接起来。
//删除值为val的结点
void Remove_Linklist(Linknode *header, int val)
{
if (header == NULL)
return;
struct Linknode *pRev = header;
struct Linknode *pCurrent =pRev->next;
//!!!如果pCurrent为空的话说明没有找到,返回即可
while (pCurrent != NULL)
{
if (pCurrent->data == val)
break;
pRev = pCurrent;
pCurrent = pCurrent->next;
}
if (pCurrent == NULL)
return;
pRev->next = pCurrent->next;
free(pCurrent);
}
6.销毁
void Destory_Linklist(Linknode *header)
{
struct Linknode *pCurrent = header->next;
while (pCurrent != NULL)
{
//先保存一下当前结点的下一个结点地址
struct Linknode *pnext = pCurrent->next;
//释放当前结点的内存
printf("%d该节点被销毁\n", pCurrent->data);
free(pCurrent);
//指针向后推移
pCurrent = pnext;
}
}
四、链表的综合应用
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
//不带头结点的静态链表
//链表结点类型定义
typedef struct Linknode
{
int data;
struct Linknode *next;
}Linknode;
//初始化链表
struct Linknode *Init_Linklist()
{
Linknode *header = malloc(sizeof(Linknode));//这里是创建了一个头结点,并为其分配内存空间
header->data = 1;//这里的数据随便,因为头结点的数据是不会被使用的
header->next = NULL;//相当于以及创建了一个空的链表
int val = -1;
Linknode *rear = header;//这里定义一个指向尾结点的指针方便插入后续结点
while (true)
{
printf("请输入插入的数据:\n");
scanf_s("%d", &val);
if (val == -1)
break;
//先创建新结点
Linknode *newnode = malloc(sizeof(Linknode));
//这里创建新结点和静态链表不同的地方在于结构体指针指向,我自己是这么理解的
newnode->data = val;
newnode->next = NULL;
rear->next = newnode;//在尾部插入结点
rear = newnode;//更新尾部结点
}
return header;
}
//在链表中值为old的后面插入数据new
void Insert_Linklist(Linknode *header, int old, int new)
{
if (header == NULL)//先判断一下是不是空链表
return;
//定义两个辅助指针变量
struct Linknode *pRev = header;
struct Linknode *pCurrent = pRev->next;//指向当前位置的结点
while (pCurrent!=NULL)
{
if (pCurrent->data == old)
break;
pRev = pCurrent;
pCurrent = pCurrent->next;
}
//if (pCurrent == NULL)//如果pCurrent为空,说明根本就没有找到old
//{
// return;
//}
//先创建新结点
struct Linknode *newnode = malloc(sizeof(Linknode));
newnode->data = new;
newnode->next = NULL;
//新结点插入链表
newnode->next = pRev->next;
pRev->next = newnode;
}
//删除值为val的结点
void Remove_Linklist(Linknode *header, int val)
{
if (header == NULL)
return;
struct Linknode *pRev = header;
struct Linknode *pCurrent =pRev->next;
//!!!如果pCurrent为空的话说明没有找到,返回即可
while (pCurrent != NULL)
{
if (pCurrent->data == val)
break;
pRev = pCurrent;
pCurrent = pCurrent->next;
}
if (pCurrent == NULL)
return;
pRev->next = pCurrent->next;
free(pCurrent);
}
//遍历结点
void print_Linklist(Linknode *header)
{
Linknode *pcurrent = header->next;
if (header == NULL)
return;
while (pcurrent != NULL)
{
printf("%d\n", pcurrent->data);
pcurrent = pcurrent->next;
}
}
//销毁链表
void Destory_Linklist(Linknode *header)
{
struct Linknode *pCurrent = header->next;
while (pCurrent != NULL)
{
//先保存一下当前结点的下一个结点地址
struct Linknode *pnext = pCurrent->next;
//释放当前结点的内存
printf("%d该节点被销毁\n", pCurrent->data);
free(pCurrent);
//指针向后推移
pCurrent = pnext;
}
}
//清空链表
void Clear_Linklist(Linknode *header)
{
if (header == NULL)
return;
//辅助指针变量
struct Linknode *pCurrent = header->next;
while (pCurrent->next != NULL)
{
//先保存一下当前结点的下一个结点地址
struct Linknode *pnext = pCurrent->next;
//释放当前结点的内存
free(pCurrent);
//pCurrent指向下一结点
pCurrent = pnext;
}
header->next = NULL;
}
int main()
{
//初始化链表 100 200 666 300 400 500 600
Linknode *header = Init_Linklist();
//打印链表
print_Linklist(header);
printf("-----------------------------\n");
//插入数据
Insert_Linklist(header, 1000, 666);
print_Linklist(header);
printf("-----------------------------\n");
//清空链表
Clear_Linklist(header);
print_Linklist(header);
Insert_Linklist(header, 1000, 111);
Insert_Linklist(header, 1000, 211);
Insert_Linklist(header, 1000, 311);
Insert_Linklist(header, 1000, 411);
print_Linklist(header);
printf("-----------------------------\n");
Remove_Linklist(header, 311);
print_Linklist(header);
system("pause");
return 0;
}
初级链表的学习到这里就结束了,接下来还会深入学习链表会更新双向链表,循环链表等知识!!!!