一,单向链表
1.插入逻辑
2.删除逻辑
3.更改逻辑
4.查询逻辑
5.代码实现
1. list.h
#ifndef __LIST_H
#define __LIST_H
#include <stdio.h>
#include <stdlib.h>
typedef struct link{
int data; //数据域
struct link *next; //指针域:保存下一个节点地址
}link_t,*plink_t;
plink_t create_node(int d);//函数逻辑:创建节点
plink_t link_init(void);//函数操作:节点初始化
void node_insert(plink_t new,plink_t node);//插入逻辑
void del_node(plink_t p);//删除逻辑
void update(plink_t p,plink_t new);//替换逻辑
void link_insert_head(plink_t head,int d);//函数操作:头插,将节点插在头结点后面
void link_insert_tail(plink_t p,int d); //函数操作:尾插,将节点插在整个链表的最后面
void link_del(plink_t p,int d);//函数操作:删除,将p节点后面的节点删除
void link_update(plink_t p,int old,int new);//函数操作:替换节点
void display(plink_t p);//遍历操作
#endif
2. list.c
#include "list.h"
//链表操作:两大类:1>函数逻辑 2>函数操作
//增 删 改 查
//1>函数逻辑:
//1.1>创建一个节点 :通过键盘入的数据域,创建节点
plink_t create_node(int d)
{
plink_t p=(plink_t)malloc(sizeof(link_t));
if(p==NULL){
perror("malloc error\n");
return NULL;
}
//修饰节点
p->data=d;//将传进来的整型值,作为该节点的数据域
p->next=NULL;//新节点的next,都需要等于NULL为了进行初始化;
return p;
}
//1.2>添加逻辑:插入逻辑:将节点new插在节点node的后面 >>>头插法
void node_insert(plink_t new,plink_t node)
{
new->next=node->next;//新节点,继承旧节点保存的地址
node->next=new;//新节点,插在旧节点的后面
}
//1.3>删除逻辑: 知道某一个节点p后,删除p后面的节点
void del_node(plink_t p)
{
plink_t node=p->next;//为了找到要删除的节点node
p->next=node->next;//将node孤立
node->next=NULL;//为了安全起见,让node指向NULL
free(node);
}
//1.4>修改逻辑:知道节点p后,将节点p后一个节点作为old,然后用new替换old
void update(plink_t p,plink_t new)
{
plink_t old=p->next;
new->next=old->next;
p->next=new;
old->next=NULL;
free(old);
}
//2函数操作:
//2.1>创建头结点初始化操作
plink_t link_init(void)
{
return create_node(-1); //头结点的数据域为-1
}
//2.2>头插:将新的节点,插在旧的节点后面,因为我们目前只知道头结点的地址,所以插入新节点永远在头节点的后面
void link_insert_head(plink_t head,int d)
{//d=data=我们scanf的值
//1>传入数据,并以该数据创建节点
plink_t new=create_node(d);
if(new==NULL){
perror("create_node\n");
return;
}
//2>调用插入逻辑,将new节点 插在头结点的后面 :头插操作
node_insert(new,head);
}
//2.3>尾插:将新节点插在整个队伍的最后面
void link_insert_tail(plink_t p,int d)
{
//1>传入数据,并以该数据创建节点
plink_t new=create_node(d);
if(new==NULL){
perror("create_node\n");
return;
}
//2>如何插在整个队伍的最后面? 要将p的位置遍历到 链表最后位置
while(p->next!=NULL){
p=p->next;//一个一个往后
}//经过该循环后,p就为整个链表的最后一个节点
//3>调用插入逻辑
node_insert(new,p);
}
//2.4>删除操作:在链表中找到要删除的数据的节点,并将其删除
void link_del(plink_t p,int d)
{
//1>遍历:查找数据是否存在于链表之中
while(p->next!=NULL){
if(p->next->data==d){
del_node(p);
return;
}
p=p->next;//往后一个一个找
}
printf("没有找到该数据\n");
}
//2.5>函数操作:修改数据---替换节点:old旧数据 new新数据
void link_update(plink_t p,int old,int new)
{
//1>寻找old数据是否存在
while(p->next!=NULL){
if(p->next->data==old){//说明找到旧数据
//创建一个新节点
plink_t new_node=create_node(new);
if(new_node==NULL){
perror("newnode\n");
return;
}
//用新节点,替换旧节点
update(p,new_node);
}
p=p->next;
}
printf("没有找到数据:%d\n",old);
}
//2.6>遍历操作:已知头结点:从头开始遍历 ,位置一直发生改变
void display(plink_t p)
{
//从头节点开始遍历:需要知道停下来的特征:最终为NULL
printf("遍历结果为:");
while(p->next!=NULL){
p=p->next;//随着循环,一直往后走
printf("%d ",p->data);
}
printf("\n");
}
3. main.c
#include "list.h"
int main(){
//初始化头结点操作
plink_t head=link_init();//head=create_node(-1); head = p;
printf("初始化成功\n");
printf("头结点的地址为:%p\n",head);
//2>添加数据:通过数据建立节点,并插在头结点的后面
//头插操作
int data,temp;
printf("开始头插操作\n");
while(1){
temp=scanf("%d",&data);
if(temp==0){
break;
}
//调用头插函数
link_insert_head(head,data);//通过data创建节点,并插在head的后面
display(head);
}
//尾插操作
getchar();
printf("开始尾插操作\n");
while(1){
temp=scanf("%d",&data);
if(temp==0){
break;
}
//调用尾插函数
link_insert_tail(head,data);//通过data创建节点,并插在head的后面
display(head);
}
//删除操作
getchar();
printf("删除操作\n");
while(1){
temp=scanf("%d",&data);
if(temp==0){
break;
}
//调用删除函数
link_del(head,data);
display(head);
}
//替换操作
getchar();
printf("替换操作\n");
int new;//用来接受新数据的
while(1){
printf("请输入旧数据:");
temp=scanf("%d",&data);
if(temp==0){
break;
}
printf("请输入新数据:");
temp=scanf("%d",&new);
if(temp==0){
break;
}
link_update(head,data,new);
display(head);
}
return 0;
}
4. 运行结果
yu@ubuntu:~/C_program/data_struct/single_link_list$ ./a.out
初始化成功
头结点的地址为:0x561e891bb260
开始头插操作
29
遍历结果为:29
34
遍历结果为:34 29
67
遍历结果为:67 34 29
89
遍历结果为:89 67 34 29
34
遍历结果为:34 89 67 34 29
90
遍历结果为:90 34 89 67 34 29
78
遍历结果为:78 90 34 89 67 34 29
66
遍历结果为:66 78 90 34 89 67 34 29
88
遍历结果为:88 66 78 90 34 89 67 34 29
99
遍历结果为:99 88 66 78 90 34 89 67 34 29
a
开始尾插操作
44
遍历结果为:99 88 66 78 90 34 89 67 34 29 44
55
遍历结果为:99 88 66 78 90 34 89 67 34 29 44 55
66
遍历结果为:99 88 66 78 90 34 89 67 34 29 44 55 66
77
遍历结果为:99 88 66 78 90 34 89 67 34 29 44 55 66 77
q
删除操作
77
遍历结果为:99 88 66 78 90 34 89 67 34 29 44 55 66
99
遍历结果为:88 66 78 90 34 89 67 34 29 44 55 66
88
遍历结果为:66 78 90 34 89 67 34 29 44 55 66
66
遍历结果为:78 90 34 89 67 34 29 44 55 66
67
遍历结果为:78 90 34 89 34 29 44 55 66
29
遍历结果为:78 90 34 89 34 44 55 66
44
遍历结果为:78 90 34 89 34 55 66
e
替换操作
请输入旧数据:78
请输入新数据:88
没有找到数据:78
遍历结果为:88 90 34 89 34 55 66
请输入旧数据:55
请输入新数据:99
没有找到数据:55
遍历结果为:88 90 34 89 34 99 66
请输入旧数据:w
yu@ubuntu:~/C_program/data_struct/single_link_list$
二,双向链表
1.插入逻辑
2.删除逻辑
3.更改逻辑
4.查询逻辑
//遍历操作
void display(plink_t p)
{
//从头节点开始遍历:需要知道停下来的特征:最终为NULL
printf("遍历结果为:");
while(p->next!=NULL){
p=p->next;//随着循环,一直往后走
printf("%d ",p->data);
}
printf("\n");
}
5.代码实现
1. link.h
#ifndef __LINK_H
#define __LINK_H
#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct link{
datatype data; //数据域
struct link *prev; //指针域: 保存上一个节点地址
struct link *next; //指针域:保存下一个节点地址
}link_t,*plink_t;
plink_t create_node(datatype d);
void insert_tail(plink_t p,plink_t node);
void delete(plink_t node);
void update(plink_t new,plink_t node);
plink_t link_init();
void link_delete(plink_t p,datatype d);
void link_insert_head(plink_t p,datatype d);
void link_insert_tail(plink_t p,datatype d);
void link_update(plink_t p,datatype old,datatype new);
void display(plink_t p);
#endif
2. link.c
#include "link.h"
/* 双向链表:
1>新节点的prev和next都指向空
2>在链表进行增删改查
3>操作分两部分:
1>操作逻辑
2> 操作函数
*/
//1>操作逻辑
//1.1>创建节点,接收一个数据,并以这个数据作为数据域创建节点
plink_t create_node(datatype d)
{
//1>申请堆空间
plink_t p=(plink_t)malloc(sizeof(link_t));
if(p==NULL){
perror("malloc");
return NULL;
}
//p节点创建成功,接下来将其初始化
p->data=d;
p->prev=NULL;
p->next=NULL;
return p;
}
//1.2>插入逻辑:在p节点的后面插入一个node节点
void insert_tail(plink_t p,plink_t node)
{
node->next=p->next;
node->prev=p;
if(p->next!=NULL)
p->next->prev=node;
p->next=node;
}
//1.3>删除逻辑:删除node节点
void delete(plink_t node)
{
node->prev->next=node->next;
if(node->next!=NULL)
node->next->prev=node->prev;
node->prev=NULL;
node->next=NULL;
free(node);
}
//1.4>替换逻辑
void update(plink_t new,plink_t node)
{
new->next=node->next;
new->prev=node->prev;
new->prev->next=new;
if(new->next!=NULL)
new->next->prev=new;
node->next=NULL;
node->prev=NULL;
free(node);
}
//----------------------------------------------
//2>操作函数
//2.1>初始化函数
plink_t link_init()
{
return create_node(-1);
}
//2.2头插操作:给头结点后面插入一个节点,该节点根据数据域创建
void link_insert_head(plink_t p,datatype d)
{
//1>根据数据域d创建节点
plink_t node=create_node(d);
if(node==NULL){
return;
}
insert_tail(p,node);
}
//2.3>尾插操作:把新节点插在整个链表的最后位置
void link_insert_tail(plink_t p,datatype d)
{
//通过传进来的数据域,创建节点
plink_t node=create_node(d);
if(node==NULL){
return;
}
//遍历到尾巴
while(p->next!=NULL){
p=p->next;
}
//将节点node插入到尾巴上
insert_tail(p,node);
}
//2.4>删除操作
void link_delete(plink_t p,datatype d)
{
//1>判断数据域d的节点是否在链表中
while(p->next!=NULL){
p=p->next;
if(p->data==d){//条件成立则说明找到要删除的节点了
delete(p);
return;
}
}
printf("没有找到节点\n");
}
//2.5>替换操作:通过接收 数据域节点new 替换 数据域节点old
void link_update(plink_t p,datatype old,datatype new)
{
//1>在整个链表中找到old
while(p->next!=NULL){
p=p->next;
if(p->data==old){//满足条件即为找到old
plink_t new_node=create_node(new);
if(new_node==NULL){
return;
}
update(new_node,p);
return;
}
}
printf("数据没有找到\n");
}
//遍历操作
void display(plink_t p)
{
//从头节点开始遍历:需要知道停下来的特征:最终为NULL
printf("遍历结果为:");
while(p->next!=NULL){
p=p->next;//随着循环,一直往后走
printf("%d ",p->data);
}
printf("\n");
}
3. main.c
#include "link.h"
int main(){
//1>初始化头结点操作
plink_t head=link_init();//head=create_node(-1); head = p;
printf("初始化成功\n");
printf("头结点的地址为:%p\n",head);
//2>添加数据:通过数据建立节点,并插在头结点的后面
//头插操作
int data,temp;
printf("开始头插操作\n");
while(1){
temp=scanf("%d",&data);
if(temp==0){
break;
}
//调用头插函数
link_insert_head(head,data);//通过data创建节点,并插在head的后面
display(head);
}
//尾插操作
getchar();
printf("开始尾插操作\n");
while(1){
temp=scanf("%d",&data);
if(temp==0){
break;
}
//调用尾插函数
link_insert_tail(head,data);
display(head);
}
//删除操作
getchar();
printf("开始删除操作\n");
while(1){
temp=scanf("%d",&data);
if(temp==0){
break;
}
//调用删除函数
link_delete(head,data);
display(head);
}
//替换操作
getchar();
printf("替换操作\n");
int new;//用来接受新数据的
while(1){
printf("请输入旧数据:");
temp=scanf("%d",&data);
if(temp==0){
break;
}
printf("请输入新数据:");
temp=scanf("%d",&new);
if(temp==0){
break;
}
link_update(head,data,new);
display(head);
}
return 0;
}
4. 运行结果
yu@ubuntu:~/C_program/data_struct/doule_linked_list$ ./a.out
初始化成功
头结点的地址为:0x55eff4453260
开始头插操作
11
遍历结果为:11
22
遍历结果为:22 11
33
遍历结果为:33 22 11
44
遍历结果为:44 33 22 11
55
遍历结果为:55 44 33 22 11
66
遍历结果为:66 55 44 33 22 11
99
遍历结果为:99 66 55 44 33 22 11
w
开始尾插操作
21
遍历结果为:99 66 55 44 33 22 11 21
43
遍历结果为:99 66 55 44 33 22 11 21 43
54
遍历结果为:99 66 55 44 33 22 11 21 43 54
65
遍历结果为:99 66 55 44 33 22 11 21 43 54 65
76
遍历结果为:99 66 55 44 33 22 11 21 43 54 65 76
87
遍历结果为:99 66 55 44 33 22 11 21 43 54 65 76 87
98
遍历结果为:99 66 55 44 33 22 11 21 43 54 65 76 87 98
e
开始删除操作
99
遍历结果为:66 55 44 33 22 11 21 43 54 65 76 87 98
98
遍历结果为:66 55 44 33 22 11 21 43 54 65 76 87
11
遍历结果为:66 55 44 33 22 21 43 54 65 76 87
22
遍历结果为:66 55 44 33 21 43 54 65 76 87
76
遍历结果为:66 55 44 33 21 43 54 65 87
87
遍历结果为:66 55 44 33 21 43 54 65
e
替换操作
请输入旧数据:44
请输入新数据:88
遍历结果为:66 55 88 33 21 43 54 65
请输入旧数据:3
请输入新数据:5
数据没有找到
遍历结果为:66 55 88 33 21 43 54 65
请输入旧数据:55
请输入新数据:99
遍历结果为:66 99 88 33 21 43 54 65
请输入旧数据:e
yu@ubuntu:~/C_program/data_struct/doule_linked_list$