C++數據結構: 鏈表

我用Java寫的鏈表是帶頭尾節點的雙向鏈表,這次用C++透徹一點,不帶頭尾節點的單向鏈表。
實現了一些常用方法,沒順序表詳細。

鏈表的查找、插入、刪除的時間複雜度都是O(N)。因爲它要遍歷到指定位置,如果在原地進行上述操作的話,時間複雜度爲O(1)。

但總歸是比不過順序表,這大概就是爲什麼我們總是被教導:大部分時間都只需要vector(ArrayList)!

但鏈表還是有它自己的優勢的,以它爲基礎的高級數據結構能有更好地性能。

#include <iostream>
#include <Windows.h>
#include <sstream>
#include "ArrayListException.h"
using namespace std;

template <typename T>
class LNode
{
public:
    T element;//存放數據
    LNode<T> *next;//指向下一個節點

    LNode(const T &e, LNode<T> *nxt=nullptr)
        :element(e),next(nxt) {}
};

template <typename T>
class CppLinkedList //不帶頭結點的單項鍊表
{
private:
    unsigned list_size;//鏈表長度
    LNode<T> *firstNode;//第一個節點
    void checkIndex(unsigned idx) const;
public:
    CppLinkedList() :list_size(0), firstNode(nullptr) {}//初始化鏈表
    CppLinkedList(const CppLinkedList<T> &c);//拷貝複製
    ~CppLinkedList();

    //返回表是否爲空
    bool isEmpty() { return list_size == 0; }
    //返回表中元素數
    unsigned size() const { return list_size; }
    //在末端插入元素e
    void add_back(const T &e);
    //在索引出插入元素e
    void insert(unsigned idx, const T &e);
    //獲取索引出元素的引用
    T get(unsigned idx) const;
    //將索引出元素值改爲e
    void set(unsigned idx, const T &e);
    //刪除索引出元素
    void erase(unsigned idx);
    //返回元素的索引
    int indexOf(const T &e) const;
    //刪除一個範圍內的元素,[s , r)
    void removeRange(int s, int r);
    //打印
    void print_list() const;

    //forward iterator
    class iterator;
    iterator begin() { return iterator(firstNode); }
    iterator end() { return iterator(NULL); }

    class iterator
    {
    public:
        // 類定義
        typedef forward_iterator_tag iterator_category;
        typedef T value_type;
        typedef ptrdiff_t difference_type;
        typedef T* pointer;
        typedef T& reference;

        // 構造器
        iterator(LNode<T>* theNode = NULL)
        {
            node = theNode;
        }

        // 解引用
        T& operator*() const { return node->element; }
        T* operator->() const { return &node->element; }

        iterator& operator++()   // 前置++
        {
            node = node->next;
            return *this;
        }
        iterator operator++(int) // 後置++
        {
            iterator old = *this;
            node = node->next;
            return old;
        }


        bool operator!=(const iterator right) const
        {
            return node != right.node;
        }
        bool operator==(const iterator right) const
        {
            return node == right.node;
        }
    protected:
        LNode<T>* node;
    }; 
};


template <typename T>
CppLinkedList<T>::CppLinkedList(const CppLinkedList<T> &c)
    :list_size(c.list_size),firstNode(nullptr)
{
    if (list_size == 0)
        return;

    LNode<T> *srcNode = c.firstNode;
    firstNode = new LNode<T>(srcNode->element,nullptr);
    LNode<T> *currentNode = firstNode;

    while (srcNode->next != nullptr)
    {
        currentNode->next = new LNode<T>(srcNode->next->element, nullptr);
        srcNode = srcNode->next;
        currentNode = currentNode->next;
    }
}

template <typename T>
CppLinkedList<T>::~CppLinkedList()
{
    while (firstNode != nullptr)
    {
        LNode<T> *currentNode = firstNode;
        cout << currentNode->element << " ";
        firstNode = firstNode->next;
        delete currentNode;
        currentNode = firstNode;
    }
}

template <typename T>//O(1) 檢查get、erase、操作符[]的索引
void CppLinkedList<T>::checkIndex(unsigned idx) const
{
    if (idx < 0 || idx >= list_size)
        throw invalidIndex("index out of range");
}

template <typename T>//O(N)
void CppLinkedList<T>::add_back(const T &e)
{
    LNode<T> *newNode = new LNode<T>(e, nullptr);
    ++list_size;//在if語句前++,免得寫兩遍
    if (list_size == 1)
    {
        firstNode = newNode;
        return;
    }
    LNode<T> *currentNode = firstNode;
    for (int i = 0; i < list_size - 2; ++i)
        currentNode = currentNode->next;

    currentNode->next = newNode;
}

template <typename T>//O(N)
void CppLinkedList<T>::insert(unsigned idx, const T &e)
{
    if (idx < 0 || idx > list_size)//檢查索引位置
        throw invalidIndex("index out of range!");

    if (idx == 0)//插入第一個位置
        firstNode = new LNode<T>(e, firstNode);
    else {
        LNode<T> *currentNode = firstNode;
        //讓currenetNode跑到索引的前一個位置
        for (int i = 0; i < idx - 1; ++i)
            currentNode = currentNode->next;

        currentNode->next = new LNode<T>(e, currentNode->next);
    }
    ++list_size;
}

template <typename T>//O(N)
T CppLinkedList<T>::get(unsigned idx) const
{
    checkIndex(idx);
    LNode<T> *currentNode = firstNode;
    //遍歷到索引位置
    for (int i = 0; i < idx; ++i)
        currentNode = currentNode->next;

    return currentNode->element;
}

template <typename T>//O(N)
void CppLinkedList<T>::set(unsigned idx, const T &e)
{
    checkIndex(idx);
    LNode<T> *currentNode = firstNode;
    for (int i = 0; i < idx; ++i)
        currentNode = currentNode->next;

    currentNode->element = e;
}

template <typename T>//O(N),因爲要遍歷到索引位置,索引還是會花費線性時間。刪除操作只花費常數時間。
void CppLinkedList<T>::erase(unsigned idx)
{
    checkIndex(idx);
    LNode<T> *currentNode = firstNode;
    if (idx == 0)
    {
        firstNode = firstNode->next;
        delete currentNode;
    }
    else
    {
        for (int i = 0; i < idx - 1; ++i)
            currentNode = currentNode->next;

        LNode<T> *oldNode = currentNode->next;
        currentNode->next = oldNode->next;
        delete oldNode;
    }
    --list_size;
}

template <typename T>
void CppLinkedList<T>::removeRange(int s, int r)
{
    //檢查索引合法性
    if (s > r) {
        ostringstream st;
        st << s << "必須小於等於" << r;
        throw invalidIndex(st.str());
    }
    checkIndex(s);
    checkIndex(r - 1);

    LNode<T> *leftNode = firstNode;
    for (int i = 0; i < s - 1; ++i)//到s的前一個元素
        leftNode = leftNode->next;

    if (s == 0)
        leftNode = new LNode<T>(firstNode->element, firstNode);

    LNode<T> *rightNode = leftNode->next;
    for (int i = 0; i < r - s; ++i)//到索引爲r的元素
    {
        LNode<T> *deleteNode = rightNode;
        rightNode = rightNode->next;
        delete deleteNode;
    }

    leftNode->next = rightNode;
    list_size -= (r - s);

    if (s == 0)
    {
        delete leftNode;
        firstNode = rightNode;
    }
}

template <typename T>//O(N)
int CppLinkedList<T>::indexOf(const T &e) const
{
    LNode<T> *currenetNode = firstNode;

    for (int i = 0; i < list_size; ++i)
    {
        if (currenetNode->element == e)
            return i;
        currenetNode = currenetNode->next;
    }
    return -1;
}

template <typename T>//O(N)
void CppLinkedList<T>::print_list() const
{
    LNode<T> *currentNode = firstNode;
    while (currentNode != nullptr)
    {
        cout << currentNode->element << " ";
        currentNode = currentNode->next;
    }
    cout << endl;
}




int main()
{
    CppLinkedList<int> c;
    for (int i = 0; i < 100; ++i)
        c.add_back(i);
    CppLinkedList<int> d = c;



    d.removeRange(0,100);

    d.print_list();

    cout << d.indexOf(8899) << " " << d.indexOf(55) <<" " << d.size()<< endl;
    system("pause");
    return 0;
}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章