特性
逻辑结构:线性结构
存储结构:链式存储结构
操作:增删改查
双向链表的结构体:
typedef int datatype;
typedef struct node
{
datatype data; //数据域
struct node *next; //指向下一个节点的指针
struct node *prior; //指向前一个节点得指针
} link_node_t, *link_list_t;
//将双向链表的头指针和尾指针封装到一个节点体里
//思想上有点像学的链式队列
typedef struct doublelinklist
{
link_list_t head; //指向双向链表的头指针
link_list_t tail; //指向双向链表得尾指针
} double_t, *double_list_t;
双向链表的相关操作
插入:
需要注意的是,与单链表不同,双链表创建过程中,每创建一个新节点都要与其前驱节点建立两次联系,分别是:
- 将新节点的 prior 指针指向直接前驱节点。
- 将直接前驱节点的 next 指针指向新节点。
结构体
#include<stdio.h>
#include<stdlib.h>
typedef int datatype;
typedef struct node
{
datatype data;//数据域
struct node *next;//指向下一个节点的指针
struct node *prior;//指向前一个节点的指针
}link_node_t,*link_list_t;
typedef struct doublelinklist
{
link_list_t head;//指向双向链表的头指针
link_list_t tail;//指向双向链表的尾指针
int len;//记录链表长度
}double_t,*double_list_t;
1)创建一个空的双向链表
//创建一个空的双向链表
double_list_t createEmptyDoubleLinkList()
{
//1.申请一块空间放头尾指针
double_list_t p = (double_list_t)malloc(sizeof(double_t));
if (NULL == p)
{
perror("createEmptyDoubleLinkList p malloc err");
return NULL;
}
//2.初始化,将头尾指针指向开辟得头节点
p->len = 0;
p->head = p->tail = (link_list_t)malloc(sizeof(link_node_t));
if (NULL == p->head)
{
perror("createEmptyDoubleLinkList p->head malloc err");
return NULL;
}
//3.头节点初始化
p->head->next = NULL;
p->head->prior = NULL;
return p;
}
2)插入数据
//插入数据
int InsertLinklist(double_list_t p,int post,datatype data)
{
if(post<0||post>p->len)//容错
{
printf("post error\n");
return -1;
}
link_list_t pt=NULL;
link_node_t *pnew=(link_node_t *)malloc(sizeof(link_node_t));
if(NULL==pnew)
{
perror("开辟失败\n");
}
pnew->data=data;
pnew->next=NULL;
pnew->prior=NULL;
if(post==p->len)//尾插
{
pnew->prior=p->tail;
p->tail->next=pnew;
p->tail=pnew;
}
else
{
if(post<p->len/2)//前半段
{
pt=p->head;
for(int i=0;i<=post;i++)
{
pt=pt->next;
}
}
else//后半段
{
pt=p->tail;
// for(int i=0;i<=p->len-post-2;i++)
for(int i=p->len-1;i>post;i--)
{
pt=pt->prior;
}
}
pnew->prior=pt->prior;
pt->prior->next=pnew;
pt->prior=pnew;
pnew->next=pt;
// pnew->prior=pt->prior;
// pnew->next=pt;
// pt->prior->next=pnew;
// pt->prior=pnew;
}
p->len++;
return 0;
}
3)遍历双向链表
void Show(double_list_t p)
{
#if 1//正向遍历
link_node_t *pt=p->head;
while(pt->next!=NULL)
{
pt=pt->next;
printf("%d ",pt->data);
}
#else//反向遍历
link_list_t ph=p->tail;
// while(ph->prior!=NULL)
while(ph!=p->head)
{
printf("%d ",ph->data);
ph=ph->prior;
}
#endif
puts(" ");
}
4)删除确定位置数据
//删除确定位置数据
int DelLinklist(double_list_t p,int post)
{
if(post<0||post>=p->len||IsVoidLinklist(p))
{
printf("err\n");
return -1;
}
link_list_t pt=NULL;
if(post==p->len-1)
{
p->tail=p->tail->prior;
free(p->tail->next);
p->tail->next=NULL;
return p->tail->data;
p->len--;
}
else
{
if(post<p->len/2)//前半段
{
pt = p->head;
for(int i=0;i<=post;i++)
{
pt=pt->next;
}
}
else//后半段
{
pt = p->tail;
// for(int i=0;i<=p->len-post-2;i++)
for(int i=p->len-1;i>post;i--)
{
pt=pt->prior;
}
}
link_list_t pdel=pt;
int data=pdel->data;
pt->prior->next=pt->next;
pt->next->prior=pt->prior;
free(pdel);
printf("删除%d\n",data);
}
p->len--;
return 0;
}
5)查询数据位置
//查询数据位置
int SearchLinklist(double_list_t p,datatype data)
{
if(IsVoidLinklist(p))
{
printf("链表为空\n");
return -1;
}
link_list_t ptemp=p->head;
int num=0;
while(ptemp->next!=NULL)
{
ptemp=ptemp->next;
if(ptemp->data==data)
{
printf("该数据位于%d处\n",num);
return num;
}
num++;
}
printf("未找到该数据\n");
return -1;
}
6)更改数据
//更改数据
int ChangeLinklist(double_list_t p,int post,datatype data)
{
if(post<0||post>=p->len||IsVoidLinklist(p))
{
printf("err\n");
return -1;
}
link_list_t pc=NULL;//定义一个新指针用于便利
if(post==p->len-1)
{
p->tail->data=data;
return 0;
}
else
{
if(post<p->len/2)//前半段
{
pc = p->head;
for(int i=0;i<=post;i++)
{
pc=pc->next;
}
}
else//后半段
{
pc = p->tail;
// for(int i=0;i<=p->len-post-2;i++)
for(int i=p->len-1;i>post;i--)
{
pc=pc->prior;
}
}
}
pc->data=data;
return 0;
}
7)按数据删除内容
//按数据删除内容
int DelatedataLinklist(double_list_t p,datatype data)
{
if(IsVoidLinklist(p))
{
printf("链表为空\n");
return -1;
}
link_list_t pdel=NULL;
link_list_t ph=p->head->next;
while(ph!=NULL)
{
if(ph->data==data)
{
if(ph==p->tail)
{
pdel=p->tail;
p->tail=p->tail->prior;
p->tail->next=NULL;
printf("删除:%d\n",pdel->data);
free(pdel);
pdel=NULL;
return 0;
}
else
{
pdel=ph;
ph->prior->next=ph->next;
ph->next->prior=ph->prior;
printf("删除%d\n",pdel->data);
free(pdel);
pdel=NULL;
}
p->len--;
}
ph=ph->next;
}
}
#include<stdio.h>
#include<stdlib.h>
typedef int datatype;
typedef struct node
{
datatype data;//数据域
struct node *next;//指向下一个节点的指针
struct node *prior;//指向前一个节点的指针
}link_node_t,*link_list_t;
typedef struct doublelinklist
{
link_list_t head;//指向双向链表的头指针
link_list_t tail;//指向双向链表的尾指针
int len;//记录链表长度
}double_t,*double_list_t;
//创建一个头节点
double_list_t CreatLinklist()
{
double_list_t p=(double_list_t)malloc(sizeof(double_t));
if(NULL==p)
{
printf("开辟失败\n");
return NULL;
}
p->head=p->tail=(link_list_t)malloc(sizeof(link_node_t));
if(NULL==p->tail)
{
printf("开辟失败\n");
return NULL;
}
p->tail->next=NULL;
p->tail->prior=NULL;
p->len=0;
return p;
}
//插入数据
int InsertLinklist(double_list_t p,int post,datatype data)
{
if(post<0||post>p->len)//容错
{
printf("post error\n");
return -1;
}
link_list_t pt=NULL;
link_node_t *pnew=(link_node_t *)malloc(sizeof(link_node_t));
if(NULL==pnew)
{
perror("开辟失败\n");
}
pnew->data=data;
pnew->next=NULL;
pnew->prior=NULL;
if(post==p->len)//尾插
{
pnew->prior=p->tail;
p->tail->next=pnew;
p->tail=pnew;
}
else
{
if(post<p->len/2)//前半段
{
pt=p->head;
for(int i=0;i<=post;i++)
{
pt=pt->next;
}
}
else//后半段
{
pt=p->tail;
// for(int i=0;i<=p->len-post-2;i++)
for(int i=p->len-1;i>post;i--)
{
pt=pt->prior;
}
}
pnew->prior=pt->prior;
pt->prior->next=pnew;
pt->prior=pnew;
pnew->next=pt;
// pnew->prior=pt->prior;
// pnew->next=pt;
// pt->prior->next=pnew;
// pt->prior=pnew;
}
p->len++;
return 0;
}
void Show(double_list_t p)
{
#if 1
link_node_t *pt=p->head;
while(pt->next!=NULL)
{
pt=pt->next;
printf("%d ",pt->data);
}
#else
link_list_t ph=p->tail;
// while(ph->prior!=NULL)
while(ph!=p->head)
{
printf("%d ",ph->data);
ph=ph->prior;
}
#endif
puts(" ");
}
int IsVoidLinklist(double_list_t p)
{
return p->len==0;
}
//删除确定位置数据
int DelLinklist(double_list_t p,int post)
{
if(post<0||post>=p->len||IsVoidLinklist(p))
{
printf("err\n");
return -1;
}
link_list_t pt=NULL;
if(post==p->len-1)
{
p->tail=p->tail->prior;
free(p->tail->next);
p->tail->next=NULL;
return p->tail->data;
p->len--;
}
else
{
if(post<p->len/2)//前半段
{
pt = p->head;
for(int i=0;i<=post;i++)
{
pt=pt->next;
}
}
else//后半段
{
pt = p->tail;
// for(int i=0;i<=p->len-post-2;i++)
for(int i=p->len-1;i>post;i--)
{
pt=pt->prior;
}
}
link_list_t pdel=pt;
int data=pdel->data;
pt->prior->next=pt->next;
pt->next->prior=pt->prior;
free(pdel);
printf("删除%d\n",data);
}
p->len--;
return 0;
}
//链表长度
int LengthLinklist(double_list_t p)
{
printf("长度为:%d\n",p->len);
return p->len;
}
//查询数据位置
int SearchLinklist(double_list_t p,datatype data)
{
if(IsVoidLinklist(p))
{
printf("链表为空\n");
return -1;
}
link_list_t ptemp=p->head;
int num=0;
while(ptemp->next!=NULL)
{
ptemp=ptemp->next;
if(ptemp->data==data)
{
printf("该数据位于%d处\n",num);
return num;
}
num++;
}
printf("未找到该数据\n");
return -1;
}
//更改数据
int ChangeLinklist(double_list_t p,int post,datatype data)
{
if(post<0||post>=p->len||IsVoidLinklist(p))
{
printf("err\n");
return -1;
}
link_list_t pc=NULL;//定义一个新指针用于便利
if(post==p->len-1)
{
p->tail->data=data;
return 0;
}
else
{
if(post<p->len/2)//前半段
{
pc = p->head;
for(int i=0;i<=post;i++)
{
pc=pc->next;
}
}
else//后半段
{
pc = p->tail;
// for(int i=0;i<=p->len-post-2;i++)
for(int i=p->len-1;i>post;i--)
{
pc=pc->prior;
}
}
}
pc->data=data;
return 0;
}
//按数据删除内容
int DelatedataLinklist(double_list_t p,datatype data)
{
if(IsVoidLinklist(p))
{
printf("链表为空\n");
return -1;
}
link_list_t pdel=NULL;
link_list_t ph=p->head->next;
while(ph!=NULL)
{
if(ph->data==data)
{
if(ph==p->tail)
{
pdel=p->tail;
p->tail=p->tail->prior;
p->tail->next=NULL;
printf("删除:%d\n",pdel->data);
free(pdel);
pdel=NULL;
return 0;
}
else
{
pdel=ph;
ph->prior->next=ph->next;
ph->next->prior=ph->prior;
printf("删除%d\n",pdel->data);
free(pdel);
pdel=NULL;
}
p->len--;
}
ph=ph->next;
}
}
int main(int argc, char const *argv[])
{
double_list_t p=CreatLinklist();
InsertLinklist(p,0,1);
InsertLinklist(p,3,4);
InsertLinklist(p,1,2);
InsertLinklist(p,2,3);
InsertLinklist(p,3,4);
InsertLinklist(p,3,4);
InsertLinklist(p,4,5);
InsertLinklist(p,4,5);
InsertLinklist(p,3,4);
InsertLinklist(p,5,6);
Show(p);
DelLinklist(p,3);
Show(p);
SearchLinklist(p,6);
ChangeLinklist(p,4,999);
DelatedataLinklist(p,4);
Show(p);
return 0;
}
杀猴子
#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct node_t
{
datatype data;
struct node_t * prior;
struct node_t * next;
}link_node_t,*link_list_t;
typedef struct doublelinklist
{
link_list_t head;
link_list_t tail;
}double_node_t,*double_list_t;
int main(int argc, const char *argv[])
{
int i;
int all_num = 8;//猴子总数
int start_num = 3;//从3号猴子开始数
int kill_num = 3;//数到几杀死猴子
link_list_t h = NULL;
link_list_t pdel = NULL;//用来指向被杀死猴子的节点
printf("请您输入猴子的总数,开始号码,出局号码:\n");
scanf("%d%d%d",&all_num,&start_num,&kill_num);
//1.创建一个双向的循环链表
double_list_t p = (double_list_t)malloc(sizeof(double_node_t));//申请头指针和尾指针
if(NULL == p)
{
perror("malloc failed");
return -1;
}
p->head = p->tail = (link_list_t)malloc(sizeof(link_node_t));
if(NULL == p->tail)
{
perror("p->tail malloc failed");
return -1;
}
p->head->data = 1;
p->head->prior = NULL;
p->head->next = NULL;
//将创建n个新的节点,链接到链表的尾
for(i = 2; i <= all_num; i++)
{
link_list_t pnew = (link_list_t)malloc(sizeof(link_node_t));
if(NULL == pnew)
{
perror("pnew malloc failed");
return -1;
}
pnew->data = i;
pnew->prior = NULL;
pnew->next = NULL;
//(1)将新的节点链接到链表的尾
p->tail->next = pnew;
pnew->prior = p->tail;
//(2)尾指针向后移动,指向当前链表的尾
p->tail = pnew;
}
//(3)形成双向循环链表
p->tail->next = p->head;
p->head->prior = p->tail;
//调试程序
#if 0
while(1)
{
printf("%d\n",p->head->data);
p->head = p->head->next;
sleep(1);
}
#endif
//2.循环进行杀死猴子
h = p->head;
//(1)先将h移动到start_num处,也就是开始数数的猴子号码处
for(i = 1; i < start_num; i++)
h = h->next;
printf("start is:%d\n",h->data);
while(h->next != h)//当h->next == h 就剩一个节点了,循环结束
{
//(2)将h移动到即将杀死猴子号码的位置
for(i = 1; i < kill_num; i++)
h = h->next;
//(3)进行杀死猴子,经过上面的循环后,此时的h指向即将杀死的猴子
h->prior->next = h->next;
h->next->prior = h->prior;
pdel = h;//pdel指向被杀死猴子的位置
printf("kill is -------%d\n",pdel->data);
h = h->next;//需要移动,从杀死猴子后的下一个位置开始数
free(pdel);
}
printf("猴王是%d\n",h->data);
return 0;
}