接着上一次的单向链表,今天说一下双向链表
给个传送门:
单向链表
3.双向不循环链表
双向不循环链表模型如下:
和单向链表一样,双向链表的一个节点也是由数据域和指针域组成,只不过,双向链表的指针域有两个指针,一个指针prev指向上一个节点(prev保存的上一个节点的地址),一个指针next指向下一个节点(next保存的是下一个节点的地址)。其他概念和之前的一样。
对双向链表的操作,也是增删改查,我们直接看程序:
#include <stdio.h>
#include <stdlib.h>
#define SYSERR(x,option,y,a,k) if((x)option(y))\
{\
printf("%s:%s:%d:%s\n",__FILE__,__func__,__LINE__,a);\
return (k);\
}
#define Malloc(types,size) (types)malloc(size)
struct Node
{
int m_Data;
int m_length;
struct Node *next,*prev;
};
typedef struct Node node_t;
void displayList(node_t* head);
/*
*链表初始化
*参数:void
*返回值:初始化成功返回链表头节点地址,失败返回NULL
*/
node_t* listInit(void)
{
node_t* head = Malloc(node_t*,sizeof(node_t));
SYSERR(head,==,NULL,"[malloc error]",NULL);
head->m_length = 0;
head->next = NULL;
head->prev = NULL;
return head;
}
/*
*头插
*参数:head:要插入的链表 dat:要插入的数据
*返回值:成功返回插入成功后的链表头节点地址,失败返回NULL
*/
node_t* insertHead(node_t* head,int dat)
{
SYSERR(head,==,NULL,"[list empty]",NULL);
node_t* temp = Malloc(node_t*,sizeof(node_t));
SYSERR(temp,==,NULL,"[malloc error]",NULL);
temp->m_Data = dat;
head->m_length++;
temp->next = head->next;
temp->prev = head;
head->next = temp;
temp->next->prev = temp;
return head;
}
/*
*尾插
*参数:head:要插入的链表 dat:要插入的数据
*返回值:成功返回插入成功后的链表头节点地址,失败返回NULL
*/
node_t* insertTall(node_t* head,int dat)
{
SYSERR(head,==,NULL,"[list empty]",NULL);
node_t* temp = head;
for(; temp->next != NULL; temp = temp->next);
node_t* node = Malloc(node_t*,sizeof(node_t));
SYSERR(node,==,NULL,"[malloc error]",NULL);
node->m_Data = dat;
head->m_length++;
temp->next = node;
node->next = NULL;
node->prev = temp;
return head;
}
/*
*删除
*参数:head:要删除节点的链表 dat:要删除的数据
*返回值:成功返回删除成功后的链表头节点地址,失败返回NULL
*/
node_t* deleteNode(node_t* head,int dat)
{
int num = 0;
SYSERR(head,==,NULL,"[list empty]",NULL);
node_t* temp = head->next;
if(temp->m_Data == dat)
{
head->next = temp->next;
temp->next->prev = head;
head->m_length--;
free(temp);
}
else
{
for(; temp != NULL ; temp = temp->next)
{
num++;
if(temp->m_Data == dat)
{
num++;
break;
}
}
//printf("num == %d\n",num);
//printf("head->m_length == %d\n",head->m_length);
if(num-1 == head->m_length)
{
temp->prev->next = NULL;
head->m_length--;
free(temp);
}
else if(num != head->m_length)
{
temp->next->prev = temp->prev;
temp->prev->next = temp->next;
head->m_length--;
free(temp);
}
else
{
printf("%d,查无此数!\n",dat);
}
}
return head;
}
void displayList(node_t* head)
{
node_t* temp = head;
for(temp = temp->next; temp != NULL; temp = temp->next)
{
printf("%d\t",temp->m_Data);
}
putchar(10);
}
int main(void)
{
node_t* head = listInit();
#if 1
head = insertTall(head,4);
head = insertTall(head,2);
head = insertTall(head,19);
head = insertTall(head,54);
head = insertTall(head,3);
head = insertTall(head,19);
head = insertTall(head,67);
//(void)displayList(head);
//printf("链表的长度为:%d\n\n",head->m_length);
#endif
#if 1
head = insertHead(head,4);
head = insertHead(head,2);
head = insertHead(head,19);
head = insertHead(head,54);
head = insertHead(head,3);
//head = insertHead(head,67);
(void)displayList(head);
printf("链表的长度为:%d\n\n",head->m_length);
#endif
#if 0
head = deleteNode(head,67);
(void)displayList(head);
printf("链表的长度为:%d\n\n",head->m_length);
#endif
#if 1
head = deleteNode(head,19);
head = deleteNode(head,4);
(void)displayList(head);
printf("链表的长度为:%d\n",head->m_length);
#endif
return 0;
}
运行结果如下:
4.双向循环链表
双向循环链表是我们要掌握的重点,其模型如下:
所谓的循环,顾名思义,就是一个环,示例代码如下:
#include <stdio.h>
#include <stdlib.h>
#define SYSERR(x,option,y,a,k) if((x)option(y))\
{\
printf("%s:%s:%d:%s\n",__FILE__,__func__,__LINE__,a);\
return (k);\
}
#define Malloc(types,size) (types)malloc(size)
struct Node
{
int m_Data;
int m_length;
struct Node *next,*prev;
};
typedef struct Node node_t;
void displayList(node_t* head);
/*
*链表初始化
*参数:void
*返回值:初始化成功返回链表头节点地址,失败返回NULL
*/
node_t* listInit(void)
{
node_t* head = Malloc(node_t*,sizeof(node_t));
SYSERR(head,==,NULL,"[malloc error]",NULL);
head->m_length = 0;
head->next = head;
head->prev = head;
return head;
}
/*
*头插
*参数:head:要插入的链表 dat:要插入的数据
*返回值:成功返回插入成功后的链表头节点地址,失败返回NULL
*/
node_t* insertHead(node_t* head,int dat)
{
SYSERR(head,==,NULL,"[list empty]",NULL);
node_t* temp = Malloc(node_t*,sizeof(node_t));
SYSERR(temp,==,NULL,"[malloc error]",NULL);
temp->m_Data = dat;
head->m_length++;
temp->next = head->next;
temp->prev = head;
head->next = temp;
temp->next->prev = temp;
return head;
}
/*
*尾插
*参数:head:要插入的链表 dat:要插入的数据
*返回值:成功返回插入成功后的链表头节点地址,失败返回NULL
*/
node_t* insertTall(node_t* head,int dat)
{
SYSERR(head,==,NULL,"[list empty]",NULL);
node_t* temp = head;
for(; temp->next != head; temp = temp->next);
node_t* node = Malloc(node_t*,sizeof(node_t));
SYSERR(node,==,NULL,"[malloc error]",NULL);
node->m_Data = dat;
head->m_length++;
temp->next = node;
node->next = head;
node->prev = temp;
return head;
}
/*
*删除
*参数:head:要删除节点的链表 dat:要删除的数据
*返回值:成功返回删除成功后的链表头节点地址,失败返回NULL
*/
node_t* deleteNode(node_t* head,int dat)
{
int num = 0,flag = 0;
SYSERR(head,==,NULL,"[list empty]",NULL);
node_t* temp = head->next;
for(; temp != head; temp = temp->next)
{
num++;
if(temp->m_Data == dat)
{
flag = 1;
break;
}
}
if(num == head->m_length && flag != 1){printf("没有数据:%d\n",dat);}
else
{
temp->next->prev = temp->prev;
temp->prev->next = temp->next;
head->m_length--;
free(temp);
}
return head;
}
void displayList(node_t* head)
{
node_t* temp = head;
for(temp = temp->next; temp != head; temp = temp->next)
{
printf("%d\t",temp->m_Data);
}
putchar(10);
}
int main(void)
{
node_t* head = listInit();
#if 1
head = insertTall(head,4);
head = insertTall(head,2);
head = insertTall(head,19);
head = insertTall(head,54);
head = insertTall(head,3);
head = insertTall(head,19);
head = insertTall(head,67);
(void)displayList(head);
printf("链表的长度为:%d\n\n",head->m_length);
#endif
#if 1
head = insertHead(head,4);
head = insertHead(head,2);
head = insertHead(head,19);
head = insertHead(head,54);
head = insertHead(head,3);
//head = insertHead(head,67);
(void)displayList(head);
printf("链表的长度为:%d\n\n",head->m_length);
#endif
#if 0
head = deleteNode(head,67);
(void)displayList(head);
printf("链表的长度为:%d\n\n",head->m_length);
#endif
#if 1
head = deleteNode(head,3);
head = deleteNode(head,4);
head = deleteNode(head,15);
(void)displayList(head);
printf("链表的长度为:%d\n",head->m_length);
#endif
return 0;
}
运行结果:
通过对比前面三个例子,双向循环链表的优势明显,对于数据的操作更加方便快速。
我们总结一下单向链表和双向链表:
单向链表每个节点只能通过他的前驱next指针访问,操作数据只能由前往后,单向查找,这样就不太方便。
而双向链表的每个节点可直接访问他的直接前驱(prev)和后继(next)节点,显然,这样的特点对于数据的操作就比单向链表更加方便快捷。
更多了解,请看一位前辈的总结:
单链表与双链表
继续学习,请看:
数据结构03----C语言栈
数据结构04----队列