双链表
1、双向链表(Double Linked List)
双(向)链表中有两条方向不同的链,即每个结点中除next域存放后继结点地址外,还增加一个指向其直接前趋的指针域prior。
注意:
①双链表由头指针head惟一确定的。
②带头结点的双链表的某些运算变得方便。
③将头结点和尾结点链接起来,为双(向)循环链表。
2、双向链表的结点结构和形式描述
①结点结构(见上图a)
②形式描述
typedef struct dlistnode{ DataType data; struct dlistnode *prior,*next; }DListNode; typedef DListNode *DLinkList; DLinkList head;
3、双向链表的前插和删除本结点操作
由于双链表的对称性,在双链表能能方便地完成各种插入、删除操作。
①双链表的前插操作
void DInsertBefore(DListNode *p,DataType x)
{//在带头结点的双链表中,将值为x的新结点插入*p之前,设p≠NULL
DListNode *s=malloc(sizeof(DListNode));//①
s->data=x;//②
s->prior=p->prior;//③
s->next=p;//④
p->prior->next=s;//⑤
p->prior=s;//⑥
}
②双链表上删除结点*p自身的操作
void DDeleteNode(DListNode *p)
{//在带头结点的双链表中,删除结点*p,设*p为非终端结点
p->prior->next=p->next;//①
p->next->prior=p->prior;//②
free(p);//③
}
注意:
与单链表上的插入和删除操作不同的是,在双链表中插入和删除必须同时修改两个方向上的指针。
上述两个算法的时间复杂度均为O(1)。
例子:
1.结构和函数原型:
/* * d_linklist.h * * Created on: 2017年10月18日 * Author: simon */ #ifndef D_LINKLIST_H_ #define D_LINKLIST_H_ #include "s_linklist.h" //引用typedef int type; #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct d_node { type data; struct d_node *prev; struct d_node *next; }D_NODE,*D_PNODE; typedef struct d_head { D_PNODE tail; //指向尾节点 D_PNODE head; //指向头结点 int length; //双向链表的长度 }D_ROOT,*D_PROOT; //创建一个节点并且赋值为data D_PNODE d_makenode_linklist(type data); //初始化双向链表 D_PROOT d_init_linklist(void); //改变根节点中记录链表数组大小的标记 void d_resizemark_linklist(D_PROOT d_root,int length); //遍历链表并且打印 void d_printfall_linklist(D_PROOT d_root); //释放node所指的节点 void d_freenode_linklist(D_PNODE node); //摧毁一个双向链表 void d_destory_linklist(D_PROOT d_root); //往双向链表头部添加节点 void d_addhead_linklist(D_PROOT d_root,D_PNODE node); //往双向链表尾部插入节点 void d_addtail_linklist(D_PROOT d_root,D_PNODE node); #endif /* D_LINKLIST_H_ */
2.函数
/* * d_linklist.c * * Created on: 2017年10月18日 * Author: simon */ #include "../include/d_linklist.h" //创建一个节点并且赋值为data D_PNODE d_makenode_linklist(type data) { D_PNODE node = (D_PNODE)malloc(1*(sizeof(D_NODE))); if(node == NULL) { printf("allocation failure\n"); return NULL; } node->data = data; node->next = node->prev = NULL; return node; } //改变根节点中记录链表数组大小的标记 void d_resizemark_linklist(D_PROOT d_root,int length) { d_root->length = length; return ; } //初始化双向链表 D_PROOT d_init_linklist(void) { D_PROOT root = (D_PROOT)malloc(1*sizeof(D_ROOT)); D_PNODE node = d_makenode_linklist(0); if(root == NULL || node == NULL) { printf("allocation failure\n"); exit(EXIT_FAILURE); } d_resizemark_linklist(root,1); root->head = node; root->tail = node; return root; } //遍历链表并且打印 void d_printfall_linklist(D_PROOT d_root) { if(d_root->head == NULL || d_root == NULL) { printf("linklist is empty\n"); return ; } D_PNODE p = d_root->head; printf("%d\t",p->data); while(p->next != d_root->head) { p = p->next; printf("%d\t",p->data); } return ; } //释放node所指的节点 void d_freenode_linklist(D_PNODE node) { free(node); } //摧毁一个双向链表 void d_destory_linklist(D_PROOT d_root) { if(d_root == NULL) { return ; } if(d_root->head == NULL) { free(d_root); d_root = NULL; return ; } D_PNODE node = d_root->head; while(node != NULL) { free(node); node = node->next; } node = NULL; return ; } //往双向链表头部添加节点 void d_addhead_linklist(D_PROOT d_root,D_PNODE node) { if(d_root == NULL) { printf("root is NULL\n"); exit(EXIT_FAILURE); } if(node == NULL) { printf("node is NULL\n"); return ; } if(d_root->head == NULL) { printf("null\n"); d_root->head = node; d_root->tail = node; d_resizemark_linklist(d_root,d_root->length+1); return ; } node->next = d_root->head; node->prev = d_root->tail; d_root->head->prev = node; d_root->tail->next = node; d_root->head = node; d_resizemark_linklist(d_root,d_root->length+1); return ; } //往双向链表尾部插入节点 void d_addtail_linklist(D_PROOT d_root,D_PNODE node) { if(d_root == NULL) { printf("root is NULL\n"); exit(EXIT_FAILURE); } if(node == NULL) { printf("node is NULL\n"); return ; } if(d_root->tail == NULL) { printf("null\n"); d_root->head = node; d_root->tail = node; d_resizemark_linklist(d_root,d_root->length+1); return ; } node->next = d_root->head; node->prev = d_root->tail; d_root->head->prev = node; d_root->tail->next = node; d_root->tail = node; d_resizemark_linklist(d_root,d_root->length+1); }
3.测试函数
//初始化双向链表 D_PROOT d_root = d_init_linklist(); printf("length:%d\n",d_root->length); int i=0; D_PNODE node; for(i=0;i<800;i++) { node = d_makenode_linklist(i+1); d_addhead_linklist(d_root,node); } d_printfall_linklist(d_root); printf("length:%d\n",d_root->length); for(i=0;i<800;i++) { node = d_makenode_linklist(i+1); d_addtail_linklist(d_root,node); } d_printfall_linklist(d_root); printf("length:%d\n",d_root->length); d_destory_linklist(d_root); node = NULL; d_root = NULL;