单链表、循环链表、双向链表复习—增删改查

一、单链表
1、定义一个struct型变量Linklist
struct Linklist{
	int data;
	struct Linklist *next; 
} ;
2、创建单链表
(1)尾插法

思路如下:

  1. malloc生成一个单元head,end节点指向head
  2. 循环malloc生成新节点node,node数据域赋值
  3. end->next指向新节点node
  4. end指向当前最后的节点node,也就是刚加入的新节点node
  5. end->next赋值为NULL
Linklist *init_wei(int n){
	Linklist *head,*node,*end;
	head = (Linklist*)malloc(sizeof(Linklist));
	end = head;
	for(int i=0;i<n;i++){
		node =  (Linklist*)malloc(sizeof(Linklist));
		//printf("输入new节点的data值:\n");
		//scanf("%d",&node->data);
		node->data = i;
		end->next = node;
		end = node;
	} 
	end->next = NULL;
	//循环链表将尾部的next指向第一个元素形成环 
	//end->next = head->next;
	return head;
}

(2)头插法

通过头插法,可以实现单链表的逆序创建

思路如下:

  1. malloc生成一个单元head,end赋值为NULL
  2. head->next指向end,先形成一个head和end的链,然后在其中插入新node。
  3. malloc生成新node,node数据域赋值
  4. node->next指向head->next
  5. head->next指向新节点node
Linklist *init_tou(int n){
	Linklist *head,*end,*node;
	head = (Linklist*)malloc(sizeof(Linklist));
	end = NULL;
	head->next = end;
	for(int i=0;i<n;i++){
		node = (Linklist*)malloc(sizeof(Linklist));
		node->data = i;
		node->next = head->next;
		head->next = node; 
	}
	return head;
}
3、输出链表

因为上面创建的链表,head节点是没有数据域的,故从head->next开始判

void shuchu(Linklist *list){
	Linklist *h = list;
	while(h->next != NULL){
		h = h->next;
		printf("%d ",h->data);
	}
	printf("\n");
}
4、增加新节点node

给一个Linklist的链表(Linklist *list)及新节点所在位置(int n)

思路如下:

  1. 先到达n位置的前一个节点t,如下
while(i<n-1 && t != NULL){
	t = t->next;
	i++;
}
  1. malloc一个新节点node,node的数据域赋值
  2. 将新节点node和t后面的节点形成连接,node->next = t->next
  3. t节点再指向新node,t->next = node

    此处要注意要先保住t和t后方节点的链,先把node和t后面节点连接后,再断开t和t->next的链,最后再更新t->next = node

void addNode(Linklist *list,int n){
	Linklist *t = list,*node;
	int i = 0;
	while(i<n-1 && t != NULL){
		t = t->next;
		i++;
	}
	if(t!=NULL){
		Linklist *node = (Linklist*)malloc(sizeof(Linklist));
		printf("输入add节点的data值:");
		scanf("%d",&node->data);
		node->next = t->next;
		t->next = node;
	}	 
} 
5、删除节点node

思路如下:

  1. 老规矩,先到达要删除节点的前一节点t,和上述addNode的操作一样
  2. 新建一个节点q指向t后方节点t->next,也就是要删除的节点
  3. t的next直接指向q的next,t->next = q->next
  4. 已经形成链了,free掉q即可
void deleteNode(Linklist *list,int n){
	Linklist *t = list ,*q;
	int i=0;
	//此时t变为要删除的前一个节点,下面的q代表当前节点。 
	while(i<n-1 && t!=NULL){
		t = t->next;
		i++;
	}
	if(t!=NULL){
		q = t->next;
		t->next = q->next;
		free(q);
	}else{
		printf("节点不存在\n"); 
	}
}
6、修改node的数据域

传入Linklist的list、修改节点的位置。直接先while到达这个node,修改它的的数据域即可。

void *modify(Linklist *list, int n){
	Linklist *t = list;
	int i = 0; 
	//先到这个点 
	while(i<n && t != NULL){
		t = t->next;
		i++; 
	}
	if(t != NULL){
		printf("输入要修改的值!\n");
		scanf("%d",&t->data);
	}else{
		printf("节点不存在!"); 
	}
} 
7、查询某一个node的数据域

传入Linklist的list、节点的位置。跟modify操作一样,返回数据域即可。

int queryNode(Linklist *list,int n){
	Linklist *t = list;
	int i = 0;
	while(i<n && t!=NULL){
		t = t->next;
		i++;
	} 
	if(t!=NULL){
		return t->data;
	}else{
		printf("节点不存在\n");
	}
} 
二、循环链表
1、循环链表的创建
  • 循环链表将尾部的next指向第一个元素形成环
  • 即end->next = head->next;

此处以尾插法为例,如下:

Linklist *init_wei(int n){
	Linklist *head,*node,*end;
	head = (Linklist*)malloc(sizeof(Linklist));
	end = head;
	for(int i=0;i<n;i++){
		node =  (Linklist*)malloc(sizeof(Linklist));
		//printf("输入new节点的data值:\n");
		//scanf("%d",&node->data);
		node->data = i;
		end->next = node;
		end = node;
	} 
	//循环链表将尾部的next指向第一个元素形成环  
	end->next = head->next;
	return head;
}
2、两个循环链表的合并

步骤如下:

  1. 先根据L1、L2的长度分别解链
  2. 两个单链表L1、L2合并形成一个大长链表L
  3. 只留一个头head,将L2的head删除
  4. 将L的首尾相连成循环链表,合并完毕
三、双向链表
  • 双向链表解决了单链表找直接前驱的O(n)的时间复杂度。
  • 它有三个域,分别是prior、data、next,结构如下:
typedef struct DListNode {
    struct DListNode* prior;
    struct DListNode* next;
    int data;
}DListNode;
1、addNode操作

输入有头结点,插入的位置和数据,找到要插入的位置p(在p之前插入),创建新的结点s。

图示如下:
在这里插入图片描述

  1. s的next指向p,s->next = p;
  2. s的prior指向p的prior,s->prior = p->prior;
  3. p的prior的next指向s,p>prior->next = s;
  4. p的prior指向s,p->prior = s;

    老规矩,先不要断开p->prior和p的链。先把新节点s的next和prior指好,然后在p->prior的next指向s,最后再p的prior指向s。

2、deleteNode操作

输入有头结点和位置,p为找到的要删除的结点。

图示如下:
在这里插入图片描述

  1. p的prior的next指向p的next,p->prior->next = p->next;
  2. p的next的prior指向p的prior,p->next->prior = p->prior;
  3. free掉p节点;

    先吧prior的next指向p后面的节点,再把后面节点的prior的指向p前面的节点,注意顺序。

四、总结

    链表的addNode和deleteNode是操作的重点。
    在增加操作的时候,先保留原链,t和t后方的节点先不要断开。 即先操作完新节点后再处理t的next域的指向。
    在删除操作的时候,先用一个临时的节点p指向要删除的节点t,保留原链的状态。 然后再把t前方的next域直接指向p后方节点,最后free掉p即可。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值