IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 《数据结构》严蔚敏第二版 2.53 循环链表,双向链表 -> 正文阅读

[数据结构与算法]《数据结构》严蔚敏第二版 2.53 循环链表,双向链表

ps:我现在是大二上,这个学期修数据结构,知识点是我上课,下课在书上,网上各种地方找到理解了之后写出来的这些东西,可能会有错误(请C友们指正),这个学期会把数据结构更新完,一些比较简单的增删改查我第一篇博客讲了之后,后面不会花费篇幅讲增删改查了,简单的东西我很快就会更完,以后大部分篇幅会讲算法哈哈哈。

来啦,兄弟们中午好啊! 废话不多缩,come with me ,baby.

循环链表:

**
昨天的单向链表不知道有没有兄弟姐妹(顺序不分先后)注意到,链表的最后一个指针指向的是NULL呢? 正是通过单向链表的最后一个指针指向的是NULL,我们才得以完成链表的遍历,完成链表的遍历是增删查改的重中之重。今天呢,我们来康康循环链表,同学们不用担心,循环链表肥肠的简单。
单向链表的最后一个指针指向NULL,循环链表的最后一个指针指向头结点。就是这么一个简单的改变,让整个链表由一条链变成了一个环,由此,遍历方式也有不同,接下来上代码,

初始化循环链表:

typedef struct list{
int data;//数据域
list *next;//指针域
};
list CreatHead()//创建头节点
{
list head=(list)malloc(sizeof(list));
head->next=head;//头指针指向头节点,没毛病奥,铁子,从头节点就已经变成一个环了
return head;
}
void CreatList(list
head){ //初始化整个链表,咱们今天来一手尾插法嗷
list *p=head; //这个是尾结点
for(int i=0;i<5;i++)
{
list newnode=(list)malloc(sizeof(list)); //给新鲜的节点开辟地址空间
newnode->data=i; //赋值,跟昨天一样滴,
newnode->next=p->next;
p->next=newnode;//这两行代码没问题吧,跟昨天也是一样的
p=newnode;//让尾部节点一直跟着最新进来的节点走
}

}
写好了,我们看看输出链表函数怎么写:
这是单链表的输出方式,只要指针指向的下一个不为空,则输出内容

printfList(list *p)
{
	list *head=p;
	printf("循环链表数据如下:\n");
	while(p->next!=NULL)
	{
		p=p->next;
		printf("%d ",p->data);
		 
	}printf("\n"); 
 } 

这个代码我们拉进主函数康康会怎么输出:

#Include<stdio.h>
#include<stdlib.h>
typedef struct list{
	int data;//数据域 
     list *next;//指针域 
}; 
list *CreatHead()//创建头节点
{
	list *head=(list*)malloc(sizeof(list));
    head->next=head;//头指针指向头节点,没毛病奥,铁子,从头节点就已经变成一个环了
    return head;
}
void CreatList(list* head){   //初始化整个链表,咱们今天来一手尾插法嗷
	list *p=head;   //这个是尾结点
	for(int i=0;i<5;i++)
	{
		list *newnode=(list*)malloc(sizeof(list));   //给新鲜的节点开辟地址空间
		newnode->data=i;                                //赋值,跟昨天一样滴,
		newnode->next=p->next;
		p->next=newnode;//这两行代码没问题吧,跟昨天也是一样的
		p=newnode;//让尾部节点一直跟着最新进来的节点走
	}
	
}
printfList(list *p)
{
	list *head=p;
	printf("循环链表数据如下:\n");
	while(p->next!=NULL)
	{
		p=p->next;
		printf("%d ",p->data);
		 
	}printf("\n"); 
 } 
int main()
{
	list *p=CreatHead();
	CreatList(p); 
	printfList(p); 
}

贴上代码:

在这里插入图片描述
嘿嘿,是不是感觉看麻了,为什么会酱紫输出呢?0 1 2 3 4 然后一个乱七八糟的数字,正常的输出应该是0 1 2 3 4 然后完事儿,这是因为我们输出的循环条件是while(p->next!=NULL),因为是循环链表,指针永远都不会为空且最后一个指针指向头节点,而且头节点是没有初始化数据域的,所以酱紫弄就循环输出(0 1 2 3 4 乱码)了接下来改善一下输出函数:

printfList(list *p)
{
	list *head=p;
	printf("循环链表数据如下:\n");
	while(p->next!=head)
	{
		p=p->next;
		printf("%d ",p->data);
		 
	}printf("\n"); 
 } 

这里我把循环输出的条件改成了只要指针指向的结点不为头结点,则进行输出,酱紫就是正常输出了:
在这里插入图片描述
正常了奥,兄弟们,接下来就是遍历链表完成增删改查这一类操作了,真的太简单洛,我把代码放到最后面,要的兄弟姐妹去拿就OK洛。

双向链表:

兄弟姐妹们,我们还是对比学习,之前学习的单链表的遍历方法是从头指针指向后继,
这就有一种局限性,头指针只能从前往后,不能从后往前,单一节点也只能找到后继结点,不能找到它的前驱结点,正是因为这种局限性,辣么双向链表就应运而生咯,双向链表一点也不难,大家往下看嘛。
既然要实现双向遍历,那么一个节点肯定要放两个指针,一个指向前驱节点,一个指向后继节点,数据保持不变。
双向链表节点代码如下:

typedef struct list()
{
	int data;
	list *next;// 后继指针,
	list *prior;//前驱指针
}

初始化双向链表:

list *CreatHead()//搞一个头结点出来
{
	list *head=(list*)malloc(sizeof(list));
	head->prior=NULL;//前继指针置空
	head->next=NULL;//后驱指针置空
}
void CreatList(list *head){
	list *p=head;//这里咱们用尾插法所以先搞一个尾指针p出来
	for(int i=1;i<6;i++)
	{
		list *newnode=(list*)malloc(sizeof(list));
		newnode->data=i;//给新鲜的结点数据域赋值
	    newnode->next=p->next;//这里就是老样子喽
	    p->next=newnode;
	    newnode->prior=p;
	    p=newnode;//尾结点一直跟着新鲜的结点跑
	 }
}

双向链表的增删改查和单向链表的增删改查没有不一样的地方,兄弟姐妹们,如果是从尾部结点开始遍历整个链表的话,咱们就把指向前驱结点的指针想像成从头结点往后遍历就OK了,不难的,敲一遍代码就懂是什么意思了。

删除结点

void DeleteNode(list *head,int add)//add为删除结点的位置 
{
	list *p=head;
	for(int i=0;i<5;i++)
	{

		p=p->next;
		if(i==add-1)
		{
			p->prior->next=p->next;//删除节点的前驱节点指向的节点变为删除节点指向的节点
			p->next->prior=p->prior;//删除节点的后继节点的前驱指针指向删除节点的前驱节点
			free(p);//咱们要把删除了的节点空间给释放了,做一个负责任的男人,从你我做起!
			break;
		 } 
		
	}
}

插入节点:

void insertNode(list *head,int q,int add)//add为要插入数据的位置,q为数据 
{
   for(int i=0;i<5;i++) 
  {
   head=head->next; 
   if(i==add-1)
   {
   list *p=(list*)malloc(sizeof(list));
   p->data=q;
   p->next=head->next;
   head->next->prior=p;
   head->next=p;
   p->prior=head;
   }
  }
}

查找:

void query(list *p,int q)//p为所要查找结点的数据域,
{
	//由尾部指针往前查找和由头指针往后查找是一模一样的原理,咱们就外甥打灯笼--照舅了.
	int i=0; 
    while(p->next!=NULL)
	{
		
		p=p->next;
		i++;
		if(p->data==q)
		{
			printf("您所查找的数据位于第%d位\n",i);
			break;
		}
	 }
}

放进主函数试试效果:

#include<stdio.h>
#include<stdlib.h>
typedef struct list
{
	int data;
	list *next;
	list *prior;
}list; 
list *CreatHead()
{
	list *head=(list*)malloc(sizeof(list));
	head->prior=NULL;
	head->next=NULL;
	return head;
}
void CreatList(list *head){
	list *p=head;
	for(int i=1;i<6;i++)
	{
		list *newnode=(list*)malloc(sizeof(list));
		newnode->data=i;
	    newnode->next=p->next;
	    p->next=newnode;
	    newnode->prior=p;
	    p=newnode;
	}
	
}
void printfList(list *p)
{
	printf("从头节点开始遍历输出数据:\n"); 
	while(p->next!=NULL)
	{
		p=p->next;
		printf("%d ",p->data);
	}
	printf("%\n");
	printf("从尾节点开始遍历输出数据:\n");
	while(p->prior!=NULL)
	{
		//p=p->prior;
		printf("%d ",p->data);
		p=p->prior;
	}
	printf("\n");
}
void insertNode(list *head,int q,int add)//add为要插入数据的位置,q为数据 
{
   for(int i=0;i<5;i++) 
  {
   head=head->next; 
   if(i==add-1)
   {
   list *p=(list*)malloc(sizeof(list));
   p->data=q;
   p->next=head->next;
   head->next->prior=p;
   head->next=p;
   p->prior=head;
   }
  }
	
}
void DeleteNode(list *head,int add)//add为删除结点的位置 
{
	list *p=head;
	for(int i=0;i<5;i++)
	{

		p=p->next;
		if(i==add-1)
		{
		//	printf("%d",i);
			p->prior->next=p->next;
			p->next->prior=p->prior;
			free(p);
			break;
		 } 
		
	}
}
void query(list *p,int q)//p为所要查找结点的数据域,
{
	//由尾部指针往前查找和由头指针往后查找是一模一样的原理,咱们就外甥打灯笼--照舅了.
	int i=0; 
    while(p->next!=NULL)
	{
		
		p=p->next;
		i++;
		if(p->data==q)
		{
			printf("您所查找的数据位于第%d位\n",i);
			break;
		}
	 }
}
int main()
{
	list *p=CreatHead();
	CreatList(p);
	printf("在第一位数据之后插入3\n");
	insertNode(p,3,1);
	printf("删除第二位结点\n");
	DeleteNode(p,2);
	printf("查找数据域为3的数据所在位置\n");
	query(p,3);
	printfList(p);
 } 

测试打印链表:
在这里插入图片描述

测试删除第二位节点:
在这里插入图片描述
测试增加节点在这里插入图片描述
测试查找节点:
在这里插入图片描述
双向链表的操作完了,觉得怎么样呢?是不是很简单?,我写得不是很全,欢迎有疑惑的同学私信我或者在评论区讨论,我们一起学习。
下面我贴上循环链表的代码,需要的兄弟姐妹自取,记得给我点个关注点个赞,让我感受一下手机响不停的感觉好吗?(QAQ)

#include<stdio.h>
#include<stdlib.h>
/* 
循环链表
*/ 
typedef struct list{
	int data;//数据域 
     list *next;//指针域 
}; 
list *CreatHead()
{
	list *head=(list*)malloc(sizeof(list));
    head->next=head;
    return head;
}
void CreatList(list* head){
	list *p=head;
	for(int i=0;i<5;i++)
	{
		list *newnode=(list*)malloc(sizeof(list));
		newnode->data=i;
		newnode->next=p->next;
		p->next=newnode;
		p=newnode;
	}
	
}
printfList(list *p)
{
	list *head=p;
	printf("循环链表数据如下:\n");
	while(p->next!=head)
	{
		p=p->next;
		printf("%d ",p->data);
		 
	}printf("\n"); 
 } 
 void insert(list *p,int q,int add)
 {
 	for(int i=0;i<5;i++)
 	{
 		p=p->next;
 		if(i==add-1)
 		{
 			list *newnode=(list*)malloc(sizeof(list));
 			newnode->data=q;
 			newnode->next=p->next;
 			p->next=newnode;
		 }
	 }
 }
 void DeleteNode(list *head,int add){
 	 list *p;
 	 for(int i=0;i<5;i++)
 	 {
 	 	p=head;
 	 	head=head->next;
 	 	if(i==add-1){
 	 		p->next=head->next;
 	 		free(head);
 	 		break;
		  }
	  }
 }
 void query(list *head,int q)
 {
 	int i=0;
 	while(head->next!=head)
	 {  
	    i++;
	 	head=head->next;
	 	if(head->data==q)
	 	{
	 		printf("查找数据位于第%d位置\n",i);
	 		break;
		 }
	  } 
 }
int main()
{
	list *p=CreatHead();
	CreatList(p); 
	printf("在第一位数据之后插入3\n");
    insert(p,3,1);
    printf("删除第二位结点\n");
    DeleteNode(p,2);
    printf("查找数据域为3的数据所在位置\n");
	query(p,3);
	printfList(p); 
}

上面这段代码根据你的需求打上注释就可以用了,今天的分享到这里就结束了,希望能收获大家的好评,记得给我点赞关注嗷,兄弟姐妹们!再见!

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-09-24 10:50:25  更:2021-09-24 10:50:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 13:47:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码