【数据结构】手搓链表

一、定义

cpp 复制代码
typedef struct node_s
{
    int _data;
    struct node_s *_next;
} node_t;

typedef struct list_s
{
    node_t *_head;
    node_t *_tail;
} list_t;
  1. 节点结构体(node_s)

    • int _data;存储节点中的数据
    • struct node_s *_next;:指向 node_s 类型的指针,用来指向链表中的下一个节点
  2. 链表结构体(list_s)

    • node_t *_head;:这是一个指向 node_s 类型的指针,用来指向链表的第一个节点,即头节点。如果链表为空,那么 _head 应该指向 NULL
    • node_t *_tail;:这是一个指向 node_s 类型的指针,用来指向链表的最后一个节点,即尾节点。如果链表为空,那么 _tail 也应该指向 NULL

链表的结构图如下:

初始化:

头尾结点指针均置为空

cpp 复制代码
void init(list_t *l)
{
    l->_head = NULL;
    l->_tail = NULL;
}

二、插入

1、头插法

由于函数需要更改pHead的指向,而pHead是指向Head结点的指针类型为node_t *,所以函数需要传入pHead的地址即:node_t **二级指针,如图所示传入ppHead和ppTail

  • 若链表为空,则头尾指针均指向新节点
  • 若不为空,则新结点与pHead指向相同,即指向Head,再将pHead前移
cpp 复制代码
void headInsert(node_t **ppHead, node_t **ppTail, int data)
{
    node_t *pNew = (node_t *)malloc(sizeof(node_t));
    bzero(pNew, sizeof(node_t));
    pNew->_data = data;
    if (*ppHead == NULL)
    {
        *ppHead = pNew;
        *ppTail = pNew;
    }
    else
    {
        pNew->_next = *ppHead;
        *ppHead = pNew;
    }
}

2、尾插法

参数与头插法相同

  • 若链表为空,则头尾指针均指向新节点
  • 若不为空,则pTail指向的Tail结点的_next指向新节点,再将pTail后移
cpp 复制代码
void tailInsert(node_t **ppHead, node_t **ppTail, int data)
{
    node_t *pNew = (node_t *)malloc(sizeof(node_t));
    bzero(pNew, sizeof(node_t));
    pNew->_data = data;
    if (*ppHead == NULL)
    {
        *ppHead = pNew;
        *ppTail = pNew;
    }
    else
    {
        (*ppTail)->_next = pNew;
        *ppTail = pNew;
    }
}

三、遍历

cpp 复制代码
void visit(node_t *pHead)
{
    node_t *pCur = pHead;
    while (pCur)
    {
        printf("%d ", (*pCur)._data);
        pCur = pCur->_next;
    }
    printf("\n");
}

四、测试

1、头插法

cpp 复制代码
list_t list;
init(&list);
for (int i = 0; i < 10; i++)
{
    headInsert(&list._head, &list._tail, i);
    visit(list._head);
}

运行结果:

2、尾插法

cpp 复制代码
list_t list;
init(&list);
for (int i = 0; i < 10; i++)
{
    tailInsert(&list._head, &list._tail, i);
    visit(list._head);
}
return 0;

运行结果:

五、使用C++对其封装

cpp 复制代码
class List
{
public:
    List();
    ~List();
    void push_back(int data);
    void push_front(int data);
    void visit();

private:
    typedef struct node_s
    {
        int _data;
        struct node_s *_next;
    } node_t;

    node_t *_pHead;
    node_t *_pTail;
};
List::List()
{
    _pHead = nullptr;
    _pTail = nullptr;
}
List::~List()
{
    node_t *pCur = _pHead;
    node_t *temp = nullptr;
    while (pCur)
    {
        temp = pCur;
        pCur = pCur->_next;
        delete temp;
        temp = nullptr;
    }
}
void List::push_back(int data)
{
    node_t *pNew = new node_t();
    pNew->_data = data;
    pNew->_next = nullptr;
    if (_pHead == nullptr)
    {
        _pHead = pNew;
        _pTail = pNew;
    }
    else
    {
        pNew->_next = _pHead;
        _pHead = pNew;
    }
}
void List::push_front(int data)
{
    node_t *pNew = new node_t();
    pNew->_data = data;
    pNew->_next = nullptr;
    if (_pHead == nullptr)
    {
        _pHead = pNew;
        _pTail = pNew;
    }
    else
    {
        _pTail->_next = pNew;
        _pTail = pNew;
    }
}
void List::visit()
{
    node_t *pCur = _pHead;
    while (pCur)
    {
        std::cout << (*pCur)._data << " ";
        pCur = pCur->_next;
    }
    std::cout << "\n";
}
相关推荐
CSharp精选营5 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
刘马想放假8 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠9 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦16 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠17 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾17 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres82117 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q17 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒17 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
疯狂成瘾者17 天前
Java 集合 LinkedList 详解:链表结构、常用方法和队列使用
java·开发语言·链表