数据结构|双向链表|带头结点|头插|尾插|尾删|头删

简介: 数据结构|双向链表|带头结点|头插|尾插|尾删|头删

双向链表的介绍

       双向链表是一种链表,它的每个节点都有两个链接,一个指向前一个节点,另一个指向下一个节点。相比于单向链表,双向链表在插入和删除操作时更加灵活,因为它们可以从两个方向进行操作。但是,双向链表的实现比单向链表更复杂,因为需要额外的指针来维护前一个和下一个节点的链接。

尾插

       在链表的尾部插入新的结点,要插入新的结点,首先得定义一个新的结点,接这找到链表尾部结点,最后通过改变指针指向进行插入。

       先定义一个新的结点(newnode),令他的next指向NULL;

       找链表的尾部结点,定义一个移动结点tail,通过next指针进行移动,不难看出tail的next指向NULL就是链表的尾部结点

要将新结点链接到双向链表上,只需要:

将最后一个链表的结点的next指针指向newnode上,

将newnode的prev指针指向双向链表的最后一个指针上。

这样尾插就完成了,下面是代码

// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
//定义新结点
  ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
  if (newnode) {
    newnode->_data = x;
    newnode->_next = NULL;
  }
//找到最后一个结点
  ListNode* tail = pHead;
  while (tail->_next != NULL)
  {
    tail = tail->_next;
  }
//改变指针指向
  tail->_next = newnode;
  newnode->_prev=tail;
}

尾删

很简单,尾删就是删除最后一个节点将最后一个结点的位置置空:

首先应找到,最后一个结点

接着,最后一个结点的prev指向最后一个结点的前一个结点,

将前一个结点的next指向NULL((将最后一个结点的位置置空)

// 双向链表尾删
void ListPopBack(ListNode* pHead)
{
//找到最后一个结点
  ListNode* tail = pHead;
  while (tail->_next!=NULL)
  {
    tail = tail->_next;
  }
  tail->_prev ->_next = NULL;
}

头插

       头插是在头结点的后边直接插入所以还是定一个新节点(newnode),通过改变头节点的指向,和头节点下一个结点的指向以及new结点的指向来完成头插。

       第一步先将newnode连接到链表上

       newnode->prev=pHead;

       newnode->next=pHead->next;

       因为头结点的下一个结点要通过pHead的next指针来访问,所以先不要改pHead的next的指向,否则就访问不到pHead的下一个结点了;

       要先将头结点的下一个结点的前驱结点指向newnode(pHead->next->prev=newnode)

       接着改pHead->next指针指向newnode(pHead->next=Newnode)

这样头插就完成了

// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x) 
{
  ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
  if (newnode)
  {
    newnode->_data = x;
    newnode->_next = pHead->_next;
    newnode->_prev = pHead;
        pHead->_next->_prev=newnode;
    pHead->_next = newnode;
  }
}

头删

       头删就是删除头节点的下一个结点,还是同样的原因,因为要通过next指针找下一个结点,所以应该先改蓝色的指针,(pHead->next->next->prev=pHead)

接着pHead->next=pHead->next->next;

// 双向链表头删
void ListPopFront(ListNode* pHead)
{
  pHead->_next->_next->_prev = pHead;
  pHead->_next = pHead->_next->_next;
  
}

实现:

void test3()
{
  ListNode* Dhead = ListCreate();
  ListPushBack(Dhead, 1);
  ListPushBack(Dhead, 2);
  ListPushBack(Dhead, 3);
  ListPushBack(Dhead, 4);
  printf("1到4尾插:");
  ListPrint(Dhead);
  printf("\n");
  printf("尾删一次:");
  ListPopBack(Dhead);
  ListPrint(Dhead);
  printf("\n");
  printf("尾删两次:");
  ListPopBack(Dhead);
  ListPrint(Dhead);
  printf("\n");
  printf("\n");
  ListPushFront(Dhead, 7);
  ListPushFront(Dhead, 8);
  ListPushFront(Dhead, 9);
  printf("7到9头插:");
  ListPrint(Dhead);
  printf("\n");
  printf("头删一次:");
  ListPopFront(Dhead);
  ListPrint(Dhead);
  printf("\n");
  printf("头删两次:");
  ListPopFront(Dhead);
  ListPrint(Dhead);
  printf("\n"); 
}
int main()
{
  test3();
  return 0;
}

运行结果:

相关文章
|
18小时前
|
算法 C语言
【数据结构与算法 经典例题】相交链表求交点
【数据结构与算法 经典例题】相交链表求交点
|
19小时前
|
存储 缓存 前端开发
【数据结构/C语言】深入理解 双向链表
【数据结构/C语言】深入理解 双向链表
|
20小时前
|
存储
【数据结构】详解链表结构
【数据结构】详解链表结构
3 0
|
20小时前
【数据结构】链表经典OJ题,常见几类题型(二)
【数据结构】链表经典OJ题,常见几类题型(二)
5 0
|
20小时前
【数据结构】链表经典OJ题,常见几类题型(一)
【数据结构】链表经典OJ题,常见几类题型(一)
6 0
|
1天前
|
存储 测试技术
【数据结构】操作受限的线性表,栈的具体实现
【数据结构】操作受限的线性表,栈的具体实现
12 5
|
1天前
|
算法
【C/数据结构和算法】:栈和队列
【C/数据结构和算法】:栈和队列
6 1
|
5天前
|
C++
【洛谷 P1044】[NOIP2003 普及组] 栈 题解(递归+记忆化搜索)
**NOIP2003普及组栈问题**:给定操作数序列1到n,仅允许push(进栈)和pop(出栈)操作。目标是计算所有可能的输出序列总数。输入包含一个整数n(1≤n≤18)。示例输入3,输出5。当队列空时返回1,栈空则只能入栈,栈非空时可入栈或出栈。AC C++代码利用记忆化搜索求解。
9 1
|
7天前
|
算法
$停车场管理系统 栈与队列
$停车场管理系统 栈与队列
8 1
|
11天前
|
存储 算法 程序员
【C++进阶】深入STL之 栈与队列:数据结构探索之旅
【C++进阶】深入STL之 栈与队列:数据结构探索之旅
18 4