链表原理详解及其实现

什么是链表?

链表,顾名思义,是一条相互链接的数据节点表。每个节点由两部分组成:数据和指向下一个节点的指针。链表的基本结构如下图所示:
链表结构图
一般来说,链表的头结点不存放具体的数据,所以也被称为哑节点(dummy node)。原因在于这样可以比较好地区分链表的头结点,而且可以大大简化链表的各种操作,避免很多不必要的边界讨论。

链表的种类

单向链表 双向链表 循环链表 多向表(网状表)

链表的优缺点

这里的优缺点主要是和链表对应的另一个数据结构:数组相比得出的。
链表的优点在于:
1.物理存储单元上非连续,而且采用动态内存分配,能够有效的分配和利用内存资源;
2.节点删除和插入简单,不需要内存空间的重组。
作为一种数据结构,链表必然也有让人诟病的地方。链表的缺点在于:
1.不能进行索引访问,只能从头结点开始顺序查找;
2.数据结构较为复杂,需要大量的指针操作,容易出错。

单向链表的模板类实现

笔者实现了一个单向链表模板类,支持了绝大部分链表操作。
(笔者坚信好的代码不必写过多的注释,代码本身即具有良好的可阅读性)
首先需要定义链表节点类:

template <class T>
class Node
{
public:
    Node();
    ~Node();

    T val;
    Node *next;
};

链表类的定义如下:

template <class T>
class List
{
public:
    List();
    ~List();

    void isEmpty();
    void isHead(Node<T> *node);
    void isTail(Node<T> *node);

    Node<T> *getHead();
    Node<T> *getTail();

    Node<T> *find(T val);
    Node<T> *findPrevious(T val);

    void insert(Node<T> *node, T val);
    void append(T val);
    void remove(T val);
    void reverse();

    int size();
    void clear();
    void print();

private:
    Node<T> *_head;
};

下面是具体的链表操作实现:
1.链表是否为空

template <class T>
void List<T>::isEmpty()
{
    return _head->next == NULL;
}

2.判断节点是否为头结点

template <class T>
void List<T>::isHead(Node<T> *node)
{
    return node == _head;
}

3.判断节点是否为尾节点

template <class T>
void List<T>::isTail(Node<T> *node)
{
    return node->next == NULL;
}

4.获取链表的头结点

template <class T>
Node<T> *List<T>::getHead()
{
    return _head;
}

5.获取节点的尾节点

template <class T>
Node<T> *List<T>::getTail()
{
    Node<T> *tmpNode = _head;
    while(tmpNode->next)
    {
        tmpNode = tmpNode->next;
    }
    return tmpNode;
}

6.查找节点

template <class T>
Node<T> *List<T>::find(T val)
{
    Node<T> *tmpNode = _head->next;
    while(tmpNode)
    {
        if (tmpNode->val == val)
        {
            return tmpNode;
        }
        tmpNode = tmpNode->next;
    }
    return NULL;
}

7.查找上一个节点

template <class T>
Node<T> *List<T>::findPrevious(T val)
{
    Node<T> *tmpNode = _head;
    while(tmpNode->next)
    {
        if (tmpNode->next->val == val)
        {
            return tmpNode;
        }
        tmpNode = tmpNode->next;
    }
    return NULL;
}

8.在指定节点之后插入新节点

template <class T>
void List<T>::insert(Node<T> *node, T val)
{
    Node<T> *tmpNode = _head->next;
    while(tmpNode)
    {
        if (tmpNode == node)
        {
            Node<T> *newNode = new Node<T>();
            newNode->val = val;
            newNode->next = tmpNode->next;
            tmpNode->next = newNode;
            return;
        }
        tmpNode = tmpNode->next;
    }
}

9.在链表尾部插入节点

template <class T>
void List<T>::append(T val)
{
    Node<T> *newNode = new Node<T>();
    newNode->val = val;
    Node<T> *tail = getTail();
    tail->next = newNode;
}

10.删除节点

template <class T>
void List<T>::remove(T val)
{
    Node<T> *prevNode = findPrevious(val);

    if (prevNode)
    {
        Node<T> *tmpNode = prevNode->next;
        prevNode->next = prevNode->next->next;
        delete tmpNode;
    }
}

11.反转链表

template <class T>
void List<T>::reverse()
{
    Node<T> *tmpNode = _head->next;
    Node<T> *prevNode = NULL;
    while(tmpNode)
    {
        Node<T> *nextNode = tmpNode->next;
        tmpNode->next = prevNode;
        prevNode = tmpNode;
        tmpNode = nextNode;
    }
    _head->next = prevNode;
}

12.获取链表的节点数

template <class T>
int List<T>::size()
{
    Node<T> *tmpNode = _head->next;
    int n = 0;
    while(tmpNode)
    {
        tmpNode = tmpNode->next;
        n++;
    }
    return n;
}

13.删除整个链表

template <class T>
void List<T>::clear()
{
    Node<T> *tmpNode = _head->next;
    while(tmpNode)
    {
        Node<T> *node = tmpNode;
        tmpNode = tmpNode->next;
        delete node;
    }
    _head->next = NULL;
}

14.打印链表的所有节点

template <class T>
void List<T>::print()
{
    Node<T> *tmpNode = _head->next;
    while(tmpNode)
    {
        std::cout << tmpNode->val;//类型T需要重载输出流操作符
        <<
        tmpNode = tmpNode->next;
        if (tmpNode)
        {
            std::cout << " ";
        }
    }
    std::cout << std::endl;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值