数据结构-单向链表,单向循环链表,双向链表,双向循环链表的增删改查逻辑和代码实现

一,单向链表

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$

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鱼驭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值