C++单向链表之一

链表

单向链表

链表是链式存储的,非顺序存储的,与顺序存储的数组不同;数组存储必须先申请足够的内存的空间,然后再存储数据,这可能导致内存空间浪费,链表则不同,链表是需要多少存储空间,则向内存空间申请多少内存,不会导致内存浪费。
链表:
优点:存储数据灵活,节省内存空间,增删查改数据方便等;
缺点:访问速度不如数组快
链表的存储机制,如图:

单向链表

代码:

以 类模板 的形式写的代码,所以只有一个头文件:linkedList.h
Node 模板类 以嵌套类的方式定义在类内部,以实现数据隐藏和封装

#ifndef SIMPLY_LINKEDLIST_LINKEDLIST_H
#define SIMPLY_LINKEDLIST_LINKEDLIST_H
#include <iostream>

template <class T>
class LinkedList{
private:
    // 嵌套类模板: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;

    };

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

    Node<T>* node(int index) const{
        Node<T>* node = first;
        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 = nullptr;
    }

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

    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 << std::endl;

    }

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

    template <class T>
    void LinkedList<T>::clear() {
        Node<T>* node = first;
        int cnt = 0;
        for (int i=0; i < Size; ++i){
            auto q = node->next;
            delete node;
            node = q;
            ++cnt;
        }
        Size = 0;
        first = 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) {
        if (index == 0){
            first = new Node<T>(element, first);
        }else{
            Node<T>* prev = 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>* oldPtr = first;
        if (index == 0){
            first = first->next;    // 删除 第一个节点;
        }else{
            /* 这里容易错:假如要删除 node(1), 则要获取指向 node(0) 处的指针,并将 node(0)->next = node(0)->next->next */
            Node<T>* prev = node(index-1);
            oldPtr = prev->next;
            prev->next = prev->next->next;
        }
        T old = oldPtr->element;
        --Size;
        delete oldPtr;          // 删除节点后,释放 add 时 new 出来的节点内存;
        return old;
    }

    template <class T>
    int LinkedList<T>::getPos(T element) {
        int position = ELEMENT_NOT_FOUND;
        Node<T>* ptr = first;
        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

注意:

  1. C++ 内存的使用和释放需注意:向堆申请内存,程序退出后应释放多少内存。
  2. 删除节点时(即:remove() ):记得释放被删除节点的内存。
  3. 清空节点时(即:clear() ):要释放所有 节点 的内存,这和析构函数的作用有点像。
  4. 析构函数: 释放所有 节点 占用的堆内存空间,并将 first(即:头结点)指向 nullptr。

测试函数
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...0

Process finished with exit code 0
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值