数据结构学习记录DAY4:双向链表
双向链表
双向链表简介:
如果认识单向链表,那么双向链表的定义其实非常之简单,只需要在单向链表的基础上,增加一个指向前结点的指针,即——对于任意一个结点,都有一个指向前一个结点和后一个结点的指针。以下为一个基础双向链表的定义。
struct Dnode{
int elem;
struct Dnode *prev;
struct Dnode *next;
}
对于单纯的双向链表来说,头结点不存储数据,头结点的前驱指针(prev)指向NULL,后置指针(next)指向下一个结点,如果没有则指向空。
那么对于不单纯的双向链表来说又如何呢?
所谓不单纯的双向链表,其实就是指的双向循环链表。对其我是这样理解的:对于任意一个拥有头结点以外结点的双向链表,令其最后一个元素的尾指针指向头结点,而头结点的前驱指针指向尾结点,如此就形成了一个循环。
这样做有何益处呢?首先,对于单向链表来说,访问尾结点的时间复杂度为O(n),但由于双向循环链表有指向尾结点的指针,因此访问的时间复杂度变为O(1),可以缩减对于元素的访问时间,尤其是头尾两个结点。其次,双向链表可以方便地通过任意一个结点的位置访问到其他的结点,不必受方向的限制。
弊端自然是增加了指针域,内存利用率再次降低,当然空间换时间的买卖由使用者决定值不值。
双向循环链表
头结点 的prev指向最后一个结点,最后一个结点的next指向头结点。
- 在头部和尾部进行插入和删除的时间复杂度都为O(1)
- 能直接访问链表的最后一个结点
双向循环链表的创建
#define SUCCESS 0//此处注意后面也要用
#define FAILURE -1
typedef struct Dnode * DL;
#define SIZE_DNODE sizeof(*DL);
DL create_dlinklist(void)
{
DL list = (DL)malloc(SIZE_DNODE);
if(NULL != list)
{
list->prev = list->next = list;
}
return list;
}
双向循环链表的插入
static struct Dnode* create_ndoe(struct Dnode *prev, struct Dnode *next, int elem)
{
struct Dnode *node = (struct Dnode*)malloc(SIZE_DNODE);
if(NULL != node)
{
node->elem = elem;
node->prev = prev;
node->next = next;
}
return node;
}
//插入到pos后面的位置
static int insert_after(struct Dnode* node, ElemType elem)
{
struct Dnode* insnode = create_node(node, node->next, elem);
if(NULL == insnode)