1.链表基本概念
链式存储的线性表,简称链表
链表其实是由一个或者多个结构体通过指针指向的关系构成
我们把每个结构体的变量称为节点,节点里面由两个成员组成
一个是数据域,另外一个是指针域,指针域是用于存放下一个节点的地址
以此类推,我们把这种存储方式称为链式存储
2.链表与顺序表差异
既然顺序存储中的数据因为挤在一起而导致需要成片移动,那很容易想到的解决方案是将数据离散地存储在不同内存块中,然后在用来指针将它们串起来。这种朴素的思路所形成的链式线性表,就是所谓的链表。
顺序表和链表在内存中基本状态如图所示:
3.链表的分类
根据链表中各个节点之间使用指针的个数,以及首尾节点是否相连,可以将链表细分为如下种类:
- 无头节点单向链表(LinkedList.c)
- 有头节点单向链表(LinkedListWithHead.c)
- 双向链表(BothwayLinkedList.c)
- 循环链表(LoopLinkedList.c)
这些不同的链表的操作都是差不多的,只是指针数目的异同。以最简单的单向链表为例,其基本示意图如下所示:
上图中,所有的节点均保存一个指针,指向其逻辑上相邻的下一个节点(末尾节点指向空)。另外注意到,整条链表用一个所谓的头指针 head 来指向,由 head 开始可以找到链表中的任意一个节点。head 通常被称为头指针。
链表的基本操作,一般包括:
- 节点设计
- 初始化空链表
- 增删节点
- 链表遍历
- 销毁链表
4.无头节点单链表节点设计
// 节点
struct node
{
int data; //数据域
// 指针域,指向下一个节点(存放下一个节点的地址)
struct node *next;
};
5.节点的空间分配
1.栈空间 : 过了生命周期自动释放
2.堆空间: malloc只需要保存地址即可,生命周期与程序保持一致
6.创建链表步骤
**1. 从无到有:**第一个节点的诞生,此时的首节点和尾节点都是它本身
2 .从少到多(添加节点过程):
1. 在原来链表的后面添加新节点(尾插法)
新节点接在尾节点后面,即尾节点指向新节点,原来的尾节点被新节点替代
特点 : 新接入的节点在前面,后接入的节点在后面
2.在原来的链表的前面添加新节点(头插法)
新节点接在原来链表的首节点前面,即新的节点指向原来的首节点,然后首节点被新节点替代
特点:后接入的节点在前面,先接入的节点在后面
7.学习链表方法:
一定要自己学会画图分析,再把思路转为代码,其实写代码要逻辑清晰才能写的快,切记你是怎么思考的就怎么写,没思考清除前别着急写。
demo:
1.创建新节点
// 创建新节点
struct node *create_newNode(dataType data)
{
struct node *pnew = malloc(sizeof(struct node));
if(pnew == NULL)
return NULL;
// 将新数据写入到新节点
pnew->data = data;
pnew->next = NULL;
return pnew;
}
2.创建新链表
// 创建新链表
struct node *create_list()
{
dataType data;
// 新节点指针,用于指向新节点
struct node *pnew = NULL;
// 指向首节点指针
struct node *head = NULL;
// 指向尾节点指针
struct node *tail = NULL;
while(1)
{
scanf("%d",&data);
if(data == 0)
break;
// 创建新节点
pnew = create_newNode(data);
if(pnew == NULL)
{
perror("create newNode failed:");
return NULL;
}
// 将新节点插入到链表
if(head == NULL)// 从无到有,此时首节点和尾节点都是pnew
{
head = pnew;
tail = pnew;
}
else // 从少到多
{
tail->next = pnew;
tail = pnew;// 更新尾节点
}
}
return head;
}
3.打印信息
// 打印信息
void showList(struct node *head)
{
for(struct node *p = head; p != NULL; p = p->next)
printf("%d ",p->data);
printf("\n");
}
练习:
1.实现头插法
2.实现链表的修改节点和删除节点
3.实现链表数据在任意位置添加
8.带头节点的单向链表
1.图解
// 定义数据节点
struct node
{
dataType data; // 数据域
struct node *next; // 指针域,存放(指向)下一个节点的地址
};
//-----------------------------------
// 定义头节点
struct headNode
{
struct node *first; // 指向第一个数据节点
struct node *last; // 指向最后一个数据节点
int nodeNumber; // 记录链表节点数
};
demo:
创建头节点
struct headNode* create_new_headNode()
{
struct headNode* head = malloc(sizeof(struct headNode));
if(head == NULL)
return NULL;
head->first = NULL;
head->last = NULL;
head->nodeNumber = 0;
return head;
}
创建数据节点
// 创建新节点
struct node* create_new_node(dataType data)
{
struct node* pnew = malloc(sizeof(struct node));
if(pnew == NULL)
return NULL;
pnew->data = data;
pnew->next = NULL;
return pnew;
}
尾插法
// 尾插法
void addTail(struct headNode *head,struct node* pnew)
{
head->last->next = pnew;
head->last = pnew;
}
创建链表
struct headNode* create_list()
{
// 创建头节点
struct headNode* head = create_new_headNode();
if(head == NULL)
return NULL;
dataType data = -1;
while(1)
{
scanf("%d",&data);
if(data == 0)
break;
// 创建新节点
struct node* pnew = create_new_node(data);
if(pnew == NULL)
return NULL;
// 从无到有
if(head->first == NULL)
{
head->first = pnew;
head->last = pnew;
}
else // 从少到多
{
// 尾插法
addTail(head,pnew);
}
// 更新节点
head->nodeNumber++;
}
return head;
}
显示链表
void showList(struct headNode* head)
{
if(head->first == NULL)
{
printf("链表为空\n");
return;
}
for(struct node* p = head->first;p != head->last->next;p = p->next)
{
printf("%d\t",p->data);
}
printf("\n");
printf("链表节点数为:%d\n",head->nodeNumber);
}
demo——带头结点单链表——汇总
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef int dataType;
// 节点结构体
struct node
{
dataType data;
struct node *next;
};
// 链表管理结构体
struct headNode
{
struct node *first; // 指向有效的首节点
struct node *last; // 指向有效的尾节点
int nodeNumber; // 记录链表节点数
};
// 初始化链表管理结构体
struct headNode *init_headNode(void)
{
struct headNode *head = malloc(sizeof(struct headNode));
if (head == NULL)
return NULL;
head->first = NULL;
head->last = NULL;
head->nodeNumber = 0;
return head;
}
struct node *create_newNode(dataType data)
{
struct node *pnew = malloc(sizeof(struct node));
if (pnew == NULL)
return NULL;
pnew->data = data;
pnew->next = NULL;
return pnew;
}
void addTail(struct headNode *head, struct node *pnew)
{
head->last->next = pnew;
head->last = pnew;
}
void addHead(struct headNode *head, struct node *pnew)
{
pnew->next = head->first;
head->first = pnew;
}
/*
* create_list : 创建链表
* 参数:
* 无
* 返回值:
* 成功: head
* 失败: NULL
*/
struct headNode *create_list(void)
{
// 初始化头节点
struct headNode *head = init_headNode();
if (head == NULL)
return NULL;
while (1)
{
dataType data;
if (scanf("%d", &data) == 0)
{
break;
}
// 创建新节点
struct node *pnew = create_newNode(data);
if (pnew == NULL)
return NULL;
if (head->first == NULL) // 从无到有
{
head->first = pnew;
head->last = pnew;
}
else // 从少到多
{
#if 1
addTail(head, pnew); // 尾插法
#else
add_node_head(head,pnew); //头插法
#endif
}
head->nodeNumber++;
}
return head;
}
// 判断链表为空
bool isEmpty(struct headNode *head)
{
return head->nodeNumber == 0;
}
void show_list(struct headNode *head)
{
if (isEmpty(head))
{
printf("此表为空\n");
return;
}
for (struct node *p = head->first; p != NULL; p = p->next)
{
printf("%d\t", p->data);
}
printf("\n");
}
/*
* add_node_head : 头插法添加节点
* 参数:
* head :链表管理结构体
* data : 插入的数据
* 返回值:
* 无
*/
void add_node_head(struct headNode *head, dataType data)
{
struct node *pnew = create_newNode(data);
if (head->last == NULL) // 链表为空时
{
head->first = pnew;
head->last = pnew;
}
else
{
pnew->next = head->first;
head->first = pnew;
}
head->nodeNumber++;
}
/*
* renew_node : 更新节点
* 参数:
* head : 链表管理结构体
* OldDate : 待更新旧数据
* newData : 新数据
* 返回值:
* 无
*/
void renew_node(struct headNode *head, dataType OldDate, dataType NewDate)
{
if (isEmpty(head))
{
printf("此表为空\n");
return;
}
struct node *p = head->first;
while (p)
{
if (p->data == OldDate)
{
p->data = NewDate;
}
else
p = p->next;
}
}
/*
* add_node : 插入节点
* 参数:
* head : 链表管理结构体
* data : 待插入数据
* 返回值:
* 无
*/
void renew_node(struct headNode *head, dataType data)
{
//创建新节点
struct node *pnew = create_newNode(data);
if (pnew==NULL)
{
return NULL;
}
//找位置
struct node *pre = head->first;
struct node *p = head->first;
while (p)
{
if (p->data == data)
{
break;
}
else
{
pre = p;
p = p->next;
}
}
if (p==NULL)
{
addTail(head,pnew);
}
else if (p->data == head->first->data)
{
addHead(head,pnew);
}
else
{
pnew->next = p;
pre->next = pnew;
}
return head;
}
/*
* delete_node : 删除节点
* 参数:
* head : 链表管理结构体
* OldDate : 待删除数据
* 返回值:
* 无
*/
void delete_node(struct headNode *head,dataType data)
{
if (isEmpty(head))
{
printf("此表为空\n");
return;
}
struct node *pre = NULL;
struct node *p = head->first;
// 找节点
while (p)
{
if (p->data == data)
{
break;
}
else
{
pre = p;
p = p->next;
}
}
if (p == NULL)
{
printf("无删除节点\n");
return ;
}
else if(p->data == head->first->data)
{
head->first = p->next;
p->next = NULL;
free(p);
}
else if(p->next == NULL && p->data == data)
{
pre->next = NULL;
free(p);
}
else // 删除中间节点
{
pre->next = p->next;
p->next = NULL;
free(p);
}
head->nodeNumber--;
}
/*
* destroy_list : 销毁链表
* 参数:
* head : 链表管理结构体
* 返回值:
* 无
*/
void destroy_list(struct headNode *head)
{
if (isEmpty(head))
{
printf("此表为空\n");
return;
}
struct node *tmp = NULL;
struct node *p = head->first;
while (p != NULL)
{
tmp = p;
p = p->next;
free(tmp);
}
// 将链表头节点的指针设置为NULL,表示链表已被销毁
head->first = NULL;
head->last = NULL;
head->nodeNumber = 0;
free(head);
}
int main(int argc, char const *argv[])
{
// 创建链表
struct headNode *head = create_list();
if (head == NULL)
{
perror("create list failed:");
return -1;
}
printf("原始数据:\n");
show_list(head);
// 更新节点-将3更新为999
printf("更新节点-将3更新为999\n");
renew_node(head,3,999);
show_list(head);
// 添加节点-将888头插
printf("添加节点-将888头插\n");
add_node_head(head,888);
show_list(head);
// 删除节点-将为1的节点删除
printf("删除节点-将为1的节点删除\n");
delete_node(head,1);
// 显示链表节点
show_list(head);
// 销毁链表
destroy_list(head);
return 0;
}
标签:node,head,struct,最全,pnew,链表,数据结构,节点
From: https://blog.csdn.net/qq_58204972/article/details/140666614