C++单向链表之二

单向链表

在 单向链表中引入 虚头结点,虚头结点不存储数据,在虚头结点之后的节点才开始存储数据;在增删 操作时,就不用将 头结点 单独考虑,统一实现逻辑。
含有 虚头结点 的链表, 如下图:
单向链表
代码:
以模板类的形式实现的,只有一个头文件: linkedList.h

#ifndef SIMPLY_LINKEDLIST_LINKEDLIST_H
#define SIMPLY_LINKEDLIST_LINKEDLIST_H
#include <iostream>

template <class T>
class LinkedList{
private:
    template <class >
    class Node{
        public:
            T element;
            Node<T>* next;

            Node(){
                element = T();
                next = nullptr;
            }

            Node(T element, Node<T>* next):element(element){
//                this->element = element;
                this->next = next;
            }

            ~Node()=default;

    };

    const int ELEMENT_NOT_FOUND = -1;
    int Size;
    Node<T>* first;

    Node<T>* node(int index) const{
        Node<T>* node = first->next;
        for(int i=0; i < index; ++i){
            node = node->next;
        }
        return node;
    }


public:
    LinkedList();
    LinkedList(T element, Node<T>* next);

    ~LinkedList();

    int size() const;
    void clear();
    bool contains(T element);
    void add(T element);
    void add(T element, int index);
    T get(int index) const;
    T set(T element, int index);
    T remove(int index) ;
    int getPos(T element);
    void display() const;

};

    template <class T>
    LinkedList<T>::LinkedList():Size(0){
//        Node<T>();
        first = new Node<T>();
    }

    template <class T>
    LinkedList<T>::LinkedList(T element, Node<T>* next):Size(0){
//        Node<T>(element, next);
        first = new Node<T>(element, next);
    }

    template <class T>
    LinkedList<T>::~LinkedList() {
        Node<T>* ptr = first;
        int cnt = 0;
        while(ptr != nullptr){
            auto q = ptr->next;
            delete ptr;
            ptr = q;
            ++cnt;
        }
        first = nullptr;
        std::cout << "...Finally, calling destructor...cnt-->: " << cnt << std::endl;

    }

    template <class T>
    int LinkedList<T>::size() const {
        return Size;
    }

    template <class T>
    void LinkedList<T>::clear() {
        Node<T>* node = first->next;
        int cnt = 0;
        for (int i=0; i < Size; ++i){
            auto q = node->next;
            delete node;
            node = q;
            ++cnt;
        }
        Size = 0;
        first->next = nullptr;
        std::cout << "clear--->cnt: " << cnt << std::endl;
    }

    template <class T>
    bool LinkedList<T>::contains(T element) {
        return getPos(element) != ELEMENT_NOT_FOUND;
    }

    template <class T>
    void LinkedList<T>::add(T element) {
        add(element, Size);
    }

    template <class T>
    void LinkedList<T>::add(T element, int index) {

        Node<T>* prev = index == 0 ? first:node(index-1);
        prev->next = new Node<T>(element, prev->next);
        ++Size;
    }

    template <class T>
    T LinkedList<T>::get(int index) const{
        return node(index)->element;
    }

    template <class T>
    T LinkedList<T>::set(T element, int index) {
        Node<T>* ptr = node(index);
        T old = ptr->element;
        ptr->element = element;
        return old;
    }

    template <class T>
    T LinkedList<T>::remove(int index) {
        Node<T>* prev = index == 0 ? first:node(index-1);
        auto oldPtr = prev->next;
        prev->next = prev->next->next;

        T old = oldPtr->element;
        --Size;
        delete oldPtr;          // 删除节点后,释放 new 出来的 内存;
        return old;
    }

    template <class T>
    int LinkedList<T>::getPos(T element) {
        int position = ELEMENT_NOT_FOUND;
        Node<T>* ptr = first->next;
        for (int i=0; i < Size; ++i){
            if(element == ptr->element){
                position = i;
                break;
            }
            ptr = ptr->next;
        }
        return position;
    }

    template <class T>
    void LinkedList<T>::display() const {
        for(int i=0; i < Size; ++i){
            std::cout << get(i) << "   ";
        }
        std::cout << std::endl;
    }

#endif //SIMPLY_LINKEDLIST_LINKEDLIST_H

测试代码
main.cpp

#include <iostream>
#include <utility>
#include "linkedList.h"

int main(){
//    auto listPtr = new LinkedList_struct<T>();
    auto listPtr = new LinkedList<T>(0, nullptr);

    // function---->add()
    listPtr->add(100, 0);
    listPtr->add(10000, listPtr->size());
    listPtr->add(20);
    listPtr->add(500);
    for (int i = 0; i < 10; ++i){
        listPtr->add(i*100, i+2);
    }
    listPtr->display();
    cout << "---------------------------------------------------------------------" << endl;

    // function---->remove()
    listPtr->remove(0);

    T a = listPtr->remove(3);
    cout << "a<--remove: " << a << endl;

    listPtr->remove(listPtr->size()-1);
    listPtr->display();
    cout << "---------------------------------------------------------------------" << endl;

    // function---->set()
    a = listPtr->set(10, 0);
    cout << "a<--set: " << a << endl;

    a = listPtr->set(20000, listPtr->size()-1);
    cout << "a<--set: " << a << endl;

    a = listPtr->set(30000, 3);
    cout << "a<--set: " << a << endl;
    listPtr->display();
    cout << "---------------------------------------------------------------------" << endl;

    // function---->get()
    a = listPtr->get(0);
    cout << "a<--get: " << a << endl;

    a = listPtr->get(listPtr->size()-1);
    cout << "a<--get: " << a << endl;

    a = listPtr->get(3);
    cout << "a<--get: " << a << endl;
    cout << "---------------------------------------------------------------------" << endl;

    // function---->getPos()
    int pos = listPtr->getPos(10);
    cout << "pos(element->10): " << pos << endl;

    pos = listPtr->getPos(20000);
    cout << "pos(element->20000): " << pos << endl;

    pos = listPtr->getPos(30000);
    cout << "pos(element->30000): " << pos << endl;
    cout << "---------------------------------------------------------------------" << endl;

    // function---->contains()
    bool tr = listPtr->contains(10);
    cout << "true(1) or false(0): " << tr << endl;
    tr = listPtr->contains(20000);
    cout << "true(1) or false(0): " << tr << endl;
    tr = listPtr->contains(-10);
    cout << "true(1) or false(0): " << tr << endl;
    cout << "---------------------------------------------------------------------" << endl;

    // function---->clear()
    listPtr->clear();
    listPtr->display();
    cout << "listPtr---->size: " << listPtr->size() << endl;
    cout << "---------------------------------------------------------------------" << endl;

    delete listPtr;
    return 0;
}

运行结果:

E:\programme\C_C++\CLion\C++\algorithm\LinkedList\simply_LinkedList\cmake-build-debug\simply_LinkedList.exe
100   10000   0   100   200   300   400   500   600   700   800   900   20   500
---------------------------------------------------------------------
a<--remove: 200
10000   0   100   300   400   500   600   700   800   900   20
---------------------------------------------------------------------
a<--set: 10000
a<--set: 20
a<--set: 300
10   0   100   30000   400   500   600   700   800   900   20000
---------------------------------------------------------------------
a<--get: 10
a<--get: 20000
a<--get: 30000
---------------------------------------------------------------------
pos(element->10): 0
pos(element->20000): 10
pos(element->30000): 3
---------------------------------------------------------------------
true(1) or false(0): 1
true(1) or false(0): 1
true(1) or false(0): 0
---------------------------------------------------------------------
clear--->cnt: 11

listPtr---->size: 0
---------------------------------------------------------------------
...Finally, calling destructor...cnt-->: 1

Process finished with exit code 0

注意:

  1. 总共 14 个数据节点,删除 3 个,剩余 11 个节点,所以在清空节点时,释放了 11 个节点的堆内存。
  2. 最后1 个虚头结点,通过 析构函数 释放的,在 clear () 函数中,只是释放了剩余 11 个节点的申请的内存,当然也可以修改代码,在 clear() 释放所有节点。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值