双向循环链表,定义了前后指针,而且链表形成一个闭环,实现了从每一个节点都可以遍历到所有节点,并且可以两个方向遍历,我的代码不完善,缺少了遍历方向的选择,怎么判断哪一个方向更加方便等
1.双向链表的头文件,先定义要实现的功能,规范好函数的返回值,形参
/*===============================================
* 文件名称:linklist.h
* 创 建 者:
* 创建日期:2022年07月28日
* 描 述:
================================================*/
#ifndef __LINKLIST__
#define __LINKLIST__
typedef int data_t;
typedef struct node
{
data_t data;//数据域
struct node *next;//指针域
struct node *prior;
}LinkList;
//1.创建头结点;
LinkList *Create_Linklist();
//2.判空
int Linklist_Empty(LinkList *link);
//3.计算表长
int Linklist_Length(LinkList *link);
//4.从表头插入节点(头插法/尾插法)
void Linklist_Insert_Head(LinkList *link,data_t data);
void Linklist_Insert_Front(LinkList *link,data_t data);
//5.按位置插入数据
void Linklist_Insert_Pos(LinkList *link,int pos,data_t data);
//6.按位置删除数据
void Linklist_Delete_Pos(LinkList *link,int pos);
//7.按数据删除
void Linklist_Delete_Data(LinkList *link,data_t data);
//8.按位置查找元素
int Linklist_Find_Pos(LinkList *link,int pos);
//9.按数据查找元素
int Linklist_Find_Data(LinkList *link,data_t data);
//10.按值修改元素
void Linklist_Change_Data(LinkList *link,data_t data,data_t new_data);
//11.清空链表
void Linklist_Setnull(LinkList *link);
//12.删除链表//形参改变实参的值要用二级指针,闯入实参的地址
void Linklist_free(LinkList **link);
//13.显示链表
void Linklist_Show(LinkList *link);
//14.链表的逆序
LinkList *Order_Linklist(LinkList *link);
void Order_Linklist_1(LinkList *link);
void Order_Linklist_2(LinkList *link);
void Order_Linklist_3(LinkList *link);
#endif
2.功能函数,把每一个功能都封装成函数,由主函数来调用
/*===============================================
* 文件名称:linklist.c
* 创 建 者:
* 创建日期:2022年07月28日
* 描 述:
================================================*/
#include <stdio.h>
#include <stdlib.h>
#include "linklist.h"
//1.创建头结点;
LinkList *Create_Linklist()
{
LinkList *head=(LinkList *)malloc(sizeof(LinkList));
if(NULL==head)
{
printf("malloc error\n");
return NULL;
}
head->data=-1;
head->next=head;
head->prior=head;
printf("链表创建成功");
return head;
}
//2.判空
int Linklist_Empty(LinkList *link)
{
if(link->next==link)
{
return 1;
}
else
{
return 0;
}
}
//3.计算表长
int Linklist_Length(LinkList *link)
{
int i=0;
LinkList *head=link;
while(link->next!=head)
{
link=link->next;
i++;
}
return i;
}
//4.从表头插入节点(头插法/尾插法)
void Linklist_Insert_Head(LinkList *link,data_t data)
{
LinkList *new=(LinkList *)malloc(sizeof(LinkList));
if(NULL==new)
{
printf("malloc error\n");
return ;
}
new->data=data;
new->next=NULL;
new->prior=NULL;
//2不能在3,4前面,先要把后面的两条线连上
new->next=link->next; //4
link->next->prior=new; //3
new->prior=link; //1
link->next=new; //2
return ;
}
void Linklist_Insert_Front(LinkList *link,data_t data)
{
return ;
}
//5.按位置插入数据
void Linklist_Insert_Pos(LinkList *link,int pos,data_t data)
{
int i=Linklist_Length(link);
if(pos<0 || pos>i+1)
{
printf("pos error\n");
return ;
}
for(i=0;i<pos;i++)
{
link=link->next;
}
LinkList *new=(LinkList *)malloc(sizeof(LinkList));
new->data=data;
//2不能在3,4前面,先要把后面的两条线连上
new->next=link->next; //4
link->next->prior=new; //3
new->prior=link; //1
link->next=new; //2
return ;
}
//6.按位置删除数据
void Linklist_Delete_Pos(LinkList *link,int pos)
{
if(Linklist_Empty(link))
{
printf("链表为空");
return ;
}
int i=Linklist_Length(link);
if(pos<0 || pos>i+1)
{
printf("pos error\n");
return ;
}
for(i=0;i<pos;i++)
{
link=link->next;
}
LinkList *p=link->next;
p->prior->next=p->next;
p->next->prior=p->prior;
free(p);
p=NULL;
return ;
}
//7.按数据删除
void Linklist_Delete_Data(LinkList *link,data_t data)
{
if(Linklist_Empty(link))
{
printf("链表为空");
return ;
}
int i=Linklist_Find_Data(link,data);
if(i==-1) return ;
Linklist_Delete_Pos(link,i);
return ;
}
//8.按位置查找元素
int Linklist_Find_Pos(LinkList *link,int pos)
{
int i=Linklist_Length(link);
if(pos<0 || pos>i+1)
{
printf("pos error\n");
return -1;
}
for(i=0;i<pos+1;i++)
{
link=link->next;
}
printf("\nlink->data[%d]=%d\n",pos,link->data);
return i;
}
//9.按数据查找元素
int Linklist_Find_Data(LinkList *link,data_t data)
{
int i=-1,j=Linklist_Length(link);
while(link->data!=data && i++<j-1)
{
link=link->next;
}
if(i==j)
{
printf("\n表中无这个元素\n");
return -1;
}
printf("\n[%d]=%d\n",i,data);
return i;
}
//10.按值修改元素
void Linklist_Change_Data(LinkList *link,data_t data,data_t new_data)
{
int i=Linklist_Find_Data(link,data),j;
for(j=0;j<=i;j++)
{
link=link->next;
}
link->data=new_data;
return ;
}
//11.清空链表
void Linklist_Setnull(LinkList *link)
{
LinkList *p=link->next;
while( p->next != link )
{
//printf("\np->data=%d\n",p->data);
Linklist_Delete_Pos(link,0);
p=link->next;
}
printf("\np->data=%d\n",p->data);
Linklist_Delete_Pos(link,0);
link->next=link;
link->prior=link;
printf("链表已清空\n");
return ;
}
//12.删除链表
void Linklist_free(LinkList **link)//形参改变实参的值要用二级指针,传入实参的地址
{
if((*link)->next!=*link)
{
Linklist_Setnull(*link);
}
free(*link);
*link=NULL;
return ;
}
//13.显示链表
void Linklist_Show(LinkList *link)
{
LinkList *head=link;
if(Linklist_Empty(link))
{
printf("\n链表为空\n");
return;
}
while(link->next!=head)
{
link=link->next;
printf("%4d",link->data);
}
puts("");
}
LinkList *Order_Linklist(LinkList *link)
{
LinkList *head=(LinkList *)malloc(sizeof(LinkList));
if(NULL==head)
{
printf("malloc error\n");
return NULL;
}
head->data=-1;
head->next=NULL;
while(link->next!=NULL)
{
link=link->next;
Linklist_Insert_Head(head,link->data);
}
Linklist_Show(head);
return head;
}
void Order_Linklist_1(LinkList *link)
{
LinkList *head=link->next->next;//指向第二个
link->next->next=NULL;//第一个作为结尾,指向NULL
while(head->next!=NULL)//保存数据要保存下一个地址,不能采用q=p,这样来保存,对p操作也相当于对q操作了,应该是q=p->next;
{
Linklist_Insert_Head(link,head->data);
head=head->next;
}
Linklist_Insert_Head(link,head->data);
Linklist_Show(link);
return ;
}
void Order_Linklist_2(LinkList *link)
{
LinkList *cur,*pre,*next;
cur=link->next;//cur指向第一个
next=cur->next;//next指向第二个
cur->next=NULL;//最后一个指向空
pre=cur; //pre指向前一个
cur=next; //cur指向当前
while(cur->next!=NULL)
{
next=cur->next;//next指向前一个
cur->next=pre;//链接后一个
pre=cur; //pre前移,为下次链接做准备
cur=next; //cur指向下一次要更改连接的目标
}
cur->next=pre;//最后一个链接上之前的
link->next=cur;//再把头指针指向更改后的第一个元素
Linklist_Show(link);
}
void Order_Linklist_3(LinkList *link)
{
LinkList *p=link->next;
LinkList *q=NULL;
link->next=NULL;
while(p!=NULL)
{
q=p->next;
p->next=link->next;
link->next=p;
p=q;
}
Linklist_Show(link);
}
3.主函数,封装成一个选择页面,根据用户的键盘输入,来执行不同的函数
/*===============================================
* 文件名称:main.c
* 创 建 者:
* 创建日期:2022年07月28日
* 描 述:
================================================*/
#include <stdio.h>
#include <stdlib.h>
#include "linklist.h"
int main(int argc, char *argv[])
{
int i,pos;
data_t data,new_data;
LinkList *head,*link;
link=head;//调用link,不改变head的值
while(1)
{
printf("\n\n\t\t\t欢迎使用链表\n\n");
printf("------------------------\n");
printf("\t\t1.创建链表 \n");
printf("\t\t2.插入元素(头插法) \n");
printf("\t\t3.按位置插入元素 \n");
printf("\t\t4.删除元素(按序号) \n");
printf("\t\t5.删除元素(按值) \n");
printf("\t\t6.查询元素(按序号) \n");
printf("\t\t7.查询元素(按值) \n");
printf("\t\t8.更改元素(按值) \n");
printf("\t\t9.显示表中元素\n");
printf("\t\t10.置空表 \n");
printf("\t\t11.删除链表 \n");
// printf("\t\t12.链表逆序 \n");
printf("\t\t12.约瑟夫问题 \n");
printf("\t\t0.退出 \n");
printf("请输入[0~10]\n");
scanf("%d",&i);
switch(i)
{
case 1:
{
head=Create_Linklist();
link=head;
break;
}
case 2:
{
printf("请输入要插入的值:\n");
scanf("%d",&data);
Linklist_Insert_Head(link,data);
break;
}
case 3:
{
printf("请输入要插入的位置与要插入的值(以空格隔开)\n");
scanf("%d %d",&pos,&data);
Linklist_Insert_Pos(link,pos,data);
break;
}
case 4:
{
printf("请输入要删除的位置\n");
scanf("%d",&pos);
Linklist_Delete_Pos(link,pos);
break;
}
case 5:
{
printf("请输入要删除的值\n");
scanf("%d",&data);
Linklist_Delete_Data(link,data);
break;
}
case 6:
{
printf("请输入要查询的位置\n");
scanf("%d",&pos);
Linklist_Find_Pos(link,pos);
break;
}
case 7:
{
printf("请输入要查找的值\n");
scanf("%d",&data);
Linklist_Find_Data(link,data);
break;
}
case 8:
{
printf("请输入被替换的值与新值(以空格隔开)\n");
scanf("%d %d",&data,&new_data);
Linklist_Change_Data(link,data,new_data);
break;
}
case 9:Linklist_Show(head);break;
case 10:Linklist_Setnull(link);break;
case 11:Linklist_free(&head);break;//形参改变实参的值要用二级指针,闯入实参的地址
// case 12:Order_Linklist_3(link);break;
case 12:Josephus();break;
case 0:exit(0);
}
}
return 0;
}