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