数据结构——带头双向循环链表下

简介: 数据结构——带头双向循环链表下

插入函数


在pos位置前插入,这个pos的地址是由LTFind函数返回的


如果我们直接就将新的节点newnode插入到pos前面位置,它们之间的链接操作有一定的顺序,如果随意改变链接关系是会出问题的


所以我们可以用一个指针posprev去保存pos->prev的地址,然后再链接posprev、newnode和 pos间的链接关系,这时的链接关系的改变不需要按照一定的顺序,按照逻辑随意修改


void LTInsert(LTNode* pos, LTDataType x)
{
  assert(pos);
  LTNode* posprev = pos->prev;
  LTNode* newnode = BuyNewNode(x);
  posprev->next = newnode;
  newnode->prev = posprev;
  newnode->next = pos;
  pos->prev = newnode;
}


我们可以用这个删除函数与实现头插和尾插


尾插:因为在pos前插入,头节点的前一个结点就是尾结点,所以调用LTInsert函数时传的地址是phead


void LTPushBack(LTNode* phead, LTDataType x)
{
  assert(phead);
  LTInsert(phead, x); 
  //调用LTInsert函数尾插
}



头插:phead->next的前插入就是头插,所以传参为phead->next

void LTPushFront(LTNode* phead, LTDataType x)
{
  assert(phead);
  LTInsert(phead->next, x); 
  //调用LTInsert函数头插
}


删除函数


这里的操作也如上个函数一样,用一个指针posprev保存pos->prev的地址,用指针posnext保存pos->next的地址,然后链接posprev和posnext


随后free掉pos即可


void LTErase(LTNode* pos)
{
  assert(pos);
  LTNode* posprev = pos->prev;
  LTNode* posnext = pos->next;
  posprev->next = posnext;
  posnext->prev = posprev;
  free(pos);
  pos = NULL;
}


这个函数还有个瑕疵就是:

如果pos传的是哨兵位头节点的地址,那么删除操作就会出错

这里如果想检查,就需要传一个参数,用来比较pos和头节点地址是否相同,但是没有必要

在后面C++中会有更好的写法


同样,可以调用LTErase去实现头删和尾删


头删:


void LTPopFront(LTNode* phead)
{
  assert(phead);
  assert(!LTEmpty(phead));
  LTErase(phead->next);
}


尾删:

void LTPopBack(LTNode* phead)
{
  assert(phead);
  assert(!LTEmpty(phead));
  LTErase(phead->prev);
}


销毁函数

void LTDestroy(LTNode* phead)
{
  assert(phead);
  LTNode* del = phead->next;
  LTNode* nex = del->next;
  while (del!= phead)
  {
  free(del);
  del = nex;
  nex = nex->next;
  }
  free(phead);
  phead = NULL;
}

1

带头双向循环链表的特点

在前面实现的过程中可以发现:


以往单链表的尾删、删除和插入操作的时间复杂度是 O(n),因为需要找尾或找前一个结点,但是带头双向循环链表完美得解决了这个问题,我们可以通过phead->prev找到尾,通过某一结点的prev找到前一个结点,所以在带头双向循环链表中,尾删和插入的时间复杂度为O(1)

在单链表的头插、尾插、头删、尾删等函数中,传的参数有二级指针,不容易理解,但是带头双向循环链表有头节点,传参是头节点的地址,因为在函数中是不会改变这个地址的指向,所以不用传二级指针

链表和顺序表的对比

这两个结构各有优势,很难说谁更优,这两个结构相辅相成


顺序表:


物理上存储空间连续

支持随机访问

任意位置插入或者删除元素可能需要搬移元素,效率低O(N)

连续物理空间,空间不够后需要增容。增容有一定程度的消耗

链表:


物理上存储空间不连续,但是逻辑上连续

不支持随机访问

任意位置插入删除效率高

按需申请释放空间


目录
相关文章
|
18天前
|
缓存
数据结构之 - 链表数据结构详解: 从基础到实现
数据结构之 - 链表数据结构详解: 从基础到实现
54 6
|
18天前
|
存储 算法 搜索推荐
探索常见数据结构:数组、链表、栈、队列、树和图
探索常见数据结构:数组、链表、栈、队列、树和图
84 64
|
13天前
|
存储 Java
数据结构第三篇【链表的相关知识点一及在线OJ习题】
数据结构第三篇【链表的相关知识点一及在线OJ习题】
21 7
|
13天前
|
存储 安全 Java
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
18 3
|
11天前
|
算法 Java
数据结构与算法学习五:双链表的增、删、改、查
双链表的增、删、改、查操作及其Java实现,并通过实例演示了双向链表的优势和应用。
10 0
数据结构与算法学习五:双链表的增、删、改、查
【数据结构】——双向链表详细理解和实现
【数据结构】——双向链表详细理解和实现
|
16天前
|
存储 Java
【数据结构】链表
【数据结构】链表
14 1
|
17天前
|
存储 缓存
数据结构3——双向链表
数据结构3——双向链表
73 1
|
5天前
|
存储
[数据结构] -- 双向循环链表
[数据结构] -- 双向循环链表
12 0
|
11天前
|
存储
探索数据结构:便捷的双向链表
探索数据结构:便捷的双向链表