【Linux 完整测试代码】数据结构之双向链表

本文详细介绍了C++中的双向链表和双向循环链表的创建、插入、删除和遍历操作,包括代码示例,适合初学者学习和进阶理解。
摘要由CSDN通过智能技术生成

别摸鱼啦,说的就是你,学习编程从入门到放弃。掌握编程思维方式,远胜于死记硬背编程语法,不能再迷路了。

双向链表                                           

图一 双向链表结构示意图

图二 双向链表创建流程示意图

为了清晰的理解双向链表的创建操作,请参考链表创建流程示意图。以下为双向链表创建步骤解析

/* 
  1. 当前节点的nextNode指向newNode 
  2. newNode的previoueNode指向currentNode
  3. newNode的nextNode指向nullptr防止出现野指针
  4. currentNode指向新创建的节点(newNode)
*/
currentNode->nextNode = staffInfo;
newNode->previousNode = currentNode;
newNode->nextNode = nullptr;
currentNode = newNode;

双向链表的操作比较常见,肯定难不倒机智的小伙伴,咱们就直接进阶到双向循环链表一探究竟啦


双向循环链表

图三 双向链表结构示意图


双向循环链表创建操作

双向循环链表的核心思想是 双向、循环,也就是说要能够双向操作并且形成闭环,图文详解双向循环链表创建过程:


1. 新建节点


2. 头节点的previousNode 指向newNode


3. currentNode和newNode互相指向


4. newNode的previousNode指向头节点


第五步 currentNode指向newNode, 至此 双向、循环 完成闭环

/* 
  1. 头节点previousNode指向newNode 
  2. 当前节点的nextNode指向newNode 
  3. newNode的previoueNode指向currentNode
  3. newNode的nextNode指向头节点
  4. currentNode指向新创建的节点(newNode)
*/

headerNode->previousNode = newNode;
currentNode->nextNode = newNode;
newNode->previousNode = currentNode;
newNode->nextNode = headerNode;
currentNode = newNode;

双向循环链表创建核心代码  

为防止出现野指针需要将尾部node的nextNode指向nullptr

myData* headerNode, *currentNode;
                 
void DoubleLinkedList::createLinkedList()
{
    myData* newNode = new myData{0};

    if (!headerNode && !currentNode) {
        headerNode = currentNode = newNode;
    } else {
        headerNode->previousNode = newNode;
        currentNode->nextNode = newNode;
        newNode->previousNode = currentNode;
        newNode->nextNode = headerNode;
        currentNode = newNode;
    }
}

双向链表的插入操作也是个技术活,下面开始图文并茂, 注意有细节哦

1.  找到要插入的节点位置myNode

2. 注意点来了,划重点要考的 

  • 先是 newNode的nextNode 指向 myNode的nextNode

  • 然后 myNode的nextNode 记作myNode_1

  • 之后 myNode_1的previousNode 指向newNode

3.  最后一步 myNode的nextNode指向newNode


双向循环链表的插入操作

图四 双向链表插入流程示意图

myData *newNode = new myData;
newNode->nextNode = myNode->nextNode;
myNode_1 = myNode->nexNode;
myNode_1->previousNode = newNode;
myNode->nextNode = newNode;

双向循环链表的遍历操作

双向循环链表可以从正 反两个方向进行数据遍历,咱们就直接开始双向遍历了哈

主要是先找到headerNode,  每次遍历需要先判断currentNode是不是尾部节点(currentNode的nextNode 是不是 指向了头节点)如果不是尾部节点,直接将currentNode指向currentNode的下一个节点,如果是尾部节点,就开始反向遍历

bool isBackwardsEcho = false;

/* 是否遍历到了尾部节点 */
if (currentNode->nextNode == headerNode &&
  headerNode->previousNode == currentNode)
    isBackwardsEcho = true;

/* 反向遍历 */
if (isBackwardsEcho) {
  /* 是否反向遍历到了头部节点 */
    (currentNode == headerNode) ?
    (currentNode = nullptr)     :
    (currentNode = currentNode->previousNode);
} else /* 正向遍历 */
  currentNode = currentNode->nextNode;


双向循环链表的删除操作

双向循环链表的删除操作,也有细节点需要注意,可以参考下面的代码逻辑

myData::~myData() {
/* 析构函数 进行一些内存释放等操作 */
}

myData * p = headerNode;
this->currentNode = headerNode;

while (currentNode) {
  /* 是否只有一个节点 */
  if (currentNode->nextNode == nullptr) { 
    delete currentNode;
    currentNode = headerNode = nullptr;
    /* 不是尾部节点*/
  } else if (currentNode->nextNode != p) {
    currentNode = currentNode->nextNode;
    delete headerNode;
    headerNode = currentNode;
    /* 是尾部节点 */
  } else if (currentNode->nextNode == p) {
    delete currentNode;
    currentNode = headerNode = nullptr;
  }
}

呈上双向链表的完整示例代码,供给小伙伴学习交流,赶紧 ctrl-c ctrl-v 测试一下吧

/********************************************************
* Description: simply C++ linked demo
* Author: jiangxiaoyu
* Data: Fir Apr 28 2023
*********************************************************/

#include <iostream>
#include <string>
#include <regex>
#include <limits>
#include <ctype.h>


typedef struct StaffInfo {
    int             ages;
    int             salary;
    int             seniority;
    std::string     name;
    std::string     post;
    std::string     education;
    void *          previousNode;
    void *          nextNode;
    ~StaffInfo();
} StaffInfomation;

StaffInfo::~StaffInfo() {
  ages = salary = seniority = 0;
  name = post = education = "";
  previousNode = nextNode = nullptr;
}


class DoubleLinkedList {
public:
    DoubleLinkedList();
    void helper();
    bool isRegexInput(std::string str);
    std::string regexDigit(std::string str, std::string msg);
    void createLinkedList();
    void collectStaffInfomation(StaffInfomation *);
    void printStaffInfomation();
    void destoryStaffInfomation();
    void exitSystem();
private:
    StaffInfomation* headerNode,
                   * currentNode;
};

/* initialize member */
DoubleLinkedList::DoubleLinkedList():
    headerNode(nullptr),
    currentNode(nullptr) {
}

void DoubleLinkedList::helper()
{
  std::cout << "\n\n" << std::endl;
  std::cout << "Simply staff information manager syatem" << std::endl;
  std::cout << "1) Create New Staff Information" << std::endl;
  std::cout << "2) Printf All Staff Information" << std::endl;
  std::cout << "3) Destory All Staff Information" << std::endl;
  std::cout << "4) Helper Manual" << std::endl;
  std::cout << "5) Exit" << std::endl;
}

void DoubleLinkedList::collectStaffInfomation(StaffInfomation * staffInfo)
{
  std::cout << "-------------------------------" << std::endl;
  std::cout << "staff information system" << std::endl;
  std::cout << "\nstaff name:"; std::cin >> staffInfo->name;
  std::cout << "\nstaff ages:"; std::cin >> staffInfo->ages;
  std::cout << "\nstaff education:"; std::cin >> staffInfo->education;
  std::cout << "\nstaff post:"; std::cin >> staffInfo->post;
  std::cout << "\nstaff seniority:"; std::cin >> staffInfo->seniority;
  std::cout << "\nstaff salary:"; std::cin >> staffInfo->salary;
}

void DoubleLinkedList::printStaffInfomation()
{
  StaffInfomation * LinkedHeader = headerNode;

  bool isBackwardsEcho = false;

    while (LinkedHeader) {
        std::cout << "-------------------------------" << std::endl;
        std::cout << "\tstaff information system" << std::endl;
        printf("\tstaff name:%s\n",         LinkedHeader->name.data());
        printf("\tstaff ages:%d\n",         LinkedHeader->ages);
        printf("\tstaff education:%s\n",    LinkedHeader->education.data());
        printf("\tstaff post:%s\n",         LinkedHeader->post.data());
        printf("\tstaff seniority:%d\n",    LinkedHeader->seniority);
        printf("\tstaff salary:%d\n",       LinkedHeader->salary);
        std::cout << "-------------------------------" << std::endl;

        if (LinkedHeader->nextNode == headerNode && headerNode->previousNode == LinkedHeader) {

          isBackwardsEcho = true;
          std::cout << "=========== already traverse list =============" << std::endl;
        }


        /* backwards traverse */
        if (isBackwardsEcho) {
          /* backwards traverse all list or not */
          (LinkedHeader == headerNode) ?
          (LinkedHeader = nullptr)         :
          (LinkedHeader = (StaffInfomation*)LinkedHeader->previousNode);
        } else 
          LinkedHeader = (StaffInfomation *)LinkedHeader->nextNode;
        }
}

void DoubleLinkedList::createLinkedList()
{
    StaffInfomation * staffInfo = new StaffInfomation{0};

    if (!headerNode && !currentNode) {
      headerNode = currentNode = staffInfo;
    } else {
      headerNode->previousNode = staffInfo;
      currentNode->nextNode = staffInfo;
      staffInfo->previousNode = currentNode;
      staffInfo->nextNode = headerNode;
      currentNode = staffInfo;
    }

    collectStaffInfomation(staffInfo);
}

void DoubleLinkedList::destoryStaffInfomation()
{
    StaffInfomation * p = headerNode;
    this->currentNode = headerNode;

    while (currentNode) {
      if (currentNode->nextNode == nullptr) { /* if only one node */
      delete currentNode;
      currentNode = headerNode = nullptr;
    } else if (currentNode->nextNode != (StaffInfomation*)p) {
      currentNode = (StaffInfomation*)currentNode->nextNode;
      delete headerNode;
      headerNode = currentNode;
    } else if ((StaffInfomation*)currentNode->nextNode == (StaffInfomation*)p) { /* if travse */
      delete currentNode;
      currentNode = headerNode = nullptr;
    }
  }
}

int main(int argc, char ** argv)
{
    DoubleLinkedList test;

    do {
        test.helper();

        int cmd = 0; std::cout << "please input flag:"; std::cin >> cmd;

        switch (cmd) {
        case 1: test.createLinkedList(); break;
        case 2: test.printStaffInfomation(); break;
        case 3: test.destoryStaffInfomation(); break;
        case 4: test.helper(); break;
        default: std::cout << "input invalid!" << std::endl;

        }
    } while(true);

    return 0;
}

创作不易,动动发财的小手点个关注再走呗

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值