【数据结构】带头双向循环链表

目录:

  • 链表的分类
  • 什么是带头双向循环链表
  • 带头双向循环链表的实现
  • 链表的尾插
  • 链表的尾删
  • 链表的头插
  • 链表的头删
  • 链表的中间插入(pos之前)
  • 链表的中间删除

什么是带头双向循环链表:

概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链

次序实现的 。
链表的分类:
  1. 单向或者双向:

【数据结构】带头双向循环链表_第1张图片

     2.带头或者不带头:

【数据结构】带头双向循环链表_第2张图片

    3. 循环或者不循环:

【数据结构】带头双向循环链表_第3张图片

实际中我们常用的链表有两种:

                                          无头单向非循环链表

                                       带头双向循环链表

【数据结构】带头双向循环链表_第4张图片

1. 无头单向非循环链表: 结构简单 ,一般不会单独用来存数据。实际中更多是作为 其他数据结构的子结
,如哈希桶、图的邻接表等等。另外这种结构在 笔试面试 中出现很多。
2. 带头双向循环链表: 结构最复杂 ,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向
循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而
简单了,后面我们代码实现了就知道了。

双向链表的实现

因为该链表属于双向循环链表,故需要使用两个指针,一个指针next来存放该节点的下一个节点并使用prev指针来存放该节点的上一个节点

带头双向循环链表是链表中带头(哨兵位)、双向、循环三种属性的结合体;
带头即带哨兵位,哨兵位只负责存储第一个具有有效数据的节点,本身不存放数据,该处因为为双向循环链表,代表也可访问该链表的尾节点;
双向即表示,每个节点不仅能访问该节点的后一个节点,同时也可访问本节点的前一个节点;
循环即表示,第一个节点的prev指向尾节点;

【数据结构】带头双向循环链表_第5张图片
结构体的声明:
#pragma once


#include 
#include 
#include 
#include 


typedef int LTDatatype;  
typedef struct ListNode

{
    struct ListNode* next;
    struct ListNode* prev;
    LTDatatype data;
}LTNode;

 首先我把链表大概声明都写在头文件里,然后一个一个讲他的实现:

#pragma once


#include 
#include 
#include 
#include 


typedef int LTDatatype;  
typedef struct ListNode

{
    struct ListNode* next;
    struct ListNode* prev;
    LTDatatype data;
}LTNode;



LTNode* LTInit(); //初始化
void LTPushBack(LTNode* phead,LTDatatype x); //尾插
void LTPushFront(LTNode* phead,LTDatatype x); //头插
void LTPopBack(LTNode* phead); //尾删
void LTPopFront(LTNode* phead); //头删
void LTInsert(LTNode* pos,LTDatatype x); //在pos之前插入
void LTErase(LTNode* pos); //删除pos位置的值

下面用画图方式讲解链表的尾插尾删,头插头删。

【数据结构】带头双向循环链表_第6张图片

 

【数据结构】带头双向循环链表_第7张图片 

【数据结构】带头双向循环链表_第8张图片

【数据结构】带头双向循环链表_第9张图片 


 根据上面图,整理代码写一下实现:

#include "List.h"


LTNode* BuyLTNode(LTDatatype x)
{
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if(newnode == NULL)
 {
   perror(malloc fail);
   return NULL;
 }
   newnode->data = x;
   newnode->next = NULL;
   newnode->prev = NULL;
   return newnode;
}


LTNode* LTInit()
{
    LTNode* phead = BuylTNode(-1);
    phead->next = phead;
    phead->prev = phead;
    return phead;
}


void LTPrint(LTNode* phead)  //打印
{
    printf("guard<==>");
    LTNode* cur = phead->next;
    
    while(cur != phead)
    {    
     printf("%d<==>",cur->data);
     cur = cur->next;
    }
    
    printf("\n");

}


void LTPushBack(LTNode* phead, LTDatatype x) /尾插
{
     LTInsert(phead, x)

    //LTNode* tail = phead->prev;
    //LTNode* newnode = BuyLTNode(x);
    //tail->next = newnode;
    //newnode->prev = tail;
    //newnode->next = phead;
    //phead->prev = newnode;
}


void LTPushFront(LTNode* phead,LTDatatype x) //头插
{
    LTInsert(phead->next ,x);
    
    //LTNode* mewnode = BuyLTNode(x);
    //LTNode* first = phead->next;
    
    //phead->next =newnode;
    //newnode->prev = phead;
    
    //newnode->next = first;
    //first->prev = newnode;

}


void PopBack(LTNode* phead) //尾删
{
      LTErase(phead->prev);

    //LTNode* tail = phead-prev;
    
    //free(tail);
    //tailPrev->next = phead;
    //phead->prev = tailPrev;

}


void PopFront(LTNode* phead) //头删
{
     
      LTErase(phead->next);
    //LTNode* first = phead->next;
    //LTNode* second = first->next;

    //phead->next = second;
    //seconf->prev = phead;
    //free(first);

}

测试部分:

#include "List.h"


void TestList1()
{
    LTNode* plist = LTInit();

    LTPushBack(plist,1);  //尾插
    LTPushBack(plist,2);
    LTPushBack(plist,3);
    LTPushBack(plist,4);
    

    LTPrint(plist);

    LTPopBack(plist); 尾删
    LTPopBack(plist);
    LTPrint(plist);




}


void TestList2()
{
     LTNode* plist = LTInit();

    LTPushFront(plist,1);  //头插
    LTPushFront(plist,2);
    LTPushFront(plist,3);
    LTPushFront(plist,4);
    

    LTPrint(plist);

    LTPopFront(plist); 头删
    LTPopFront(plist);
    LTPrint(plist);

}





int main()
{
    //TestList1();
    TestList2();

return 0;
}

你可能感兴趣的:(链表,数据结构)