數據結構-C++實現(二):單向鏈表

和數組不同,鏈表的數據結構內部多了一個指針指針下一個位置,使得在鏈表中插入刪除特定位置的元素效率很高,代碼實現依舊分爲三個部分,抽象類LinearList.h,模板類chain.h以及main函數源文件。

廢話不多說,我們看代碼,這次LinearList.h抽象類裏面多了兩個成員函數一個是push_back(),一個是clear():

//
// Created by djf on 2016/12/18 0018.
//

#ifndef INC_01_ARRAYLIST_LINEARLIST_H
#define INC_01_ARRAYLIST_LINEARLIST_H

#include 
template 
class LinearList {
public:
    virtual ~LinearList() {};
    virtual bool empty() const = 0;
    virtual int size() const = 0;
    virtual T& get(int index) const = 0;
    virtual int indexof(const T& theElement) const = 0;//first pos
    virtual void erase(int index) = 0;
    virtual void insert(int index, const T& theElement) = 0;
    virtual void output(std::ostream& out) const = 0;
    //extend
    virtual void clear() = 0;
    virtual void push_back(const T& theElement)  = 0;
};


#endif //INC_01_ARRAYLIST_LINEARLIST_H
然後是chain.h,單向鏈表的模板類:

//
// Created by djf on 2016/12/20 0020.
//

#ifndef INC_02_CHAIN_CHAIN_H
#define INC_02_CHAIN_CHAIN_H

#include "LinearList.h"
using namespace std;
template 
struct chainNode{
    //data
    T element;
    chainNode *next;
    //method
    chainNode() {}
    chainNode(const T& e) { this->element=e;}
    chainNode(const T& e, chainNode* n) { this->element=e;this->next=n;}
};

template 
class chain: public LinearList {
public:
    //one direction iterator
    class iterator{
    public:
        // typedefs required by C++ for a forward iterator
        typedef forward_iterator_tag iterator_category;
        typedef T value_type;
        typedef ptrdiff_t difference_type;
        typedef T* pointer;
        typedef T& reference;
        //construct
        iterator(chainNode* theNode = nullptr) { node = theNode;}
        //operator
        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 rhl) const { return node == rhl.node;}
        bool operator!=(const iterator rhl) const { return node != rhl.node;}
        //other

    protected:
        chainNode* node;
    };
public:
    //consturct copy destory
    chain(int initCapacity=10);
    chain(const chain&);
    ~chain();
    //ADT method from LinearList.h
    bool empty() const override { return listSize==0;};
    int size() const override { return listSize;}
    T& get(int index) const override;
    int indexof(const T&) const override;
    void erase(int index) override;
    void insert(int index,const T& theElement) override;
    void output(ostream& out) const override;
    void push_back(const T& theElement) override ;
    void clear() override ;
    //other
    void removeRange(int fromIndex,int toIndex);
    int lastIndexOf(const T& theElement);
    T& operator[](int index) const;
    void reverse();
protected:
    void checkIndex(int index) const;
    chainNode* headNode;
    int listSize;

};

template 
void chain::removeRange(int fromIndex, int toIndex)
{
    checkIndex(fromIndex);checkIndex(toIndex);
    if(toIndex* p = headNode;
    if(fromIndex!=0)
    {
        chainNode* q;
        for(int i = 0;inext;
            else
            {
                q = p->next;
                p->next = q->next;
                delete q;
            }
        }
    } else
    {
        for(int i = 0;i<=toIndex;++i)
        {
            headNode = headNode->next;
            delete p;
            p = headNode;
        }
    }
}

template 
chain::chain(int initCapacity)
{
    //chain中無capacity,這麼寫爲了和LinearList兼容
    if(initCapacity<1)
        cerr << "----!initSize must be >=1 !----";
    listSize = 0;
    headNode = nullptr;
}

template 
chain::chain(const chain & theList)
{
    listSize = theList.listSize;
    if(listSize==0)
    {
        headNode = nullptr;
        return;
    }
    chainNode* sourceNode = theList.headNode;
    headNode = new chainNode(sourceNode->element);
    sourceNode = sourceNode->next;
    chainNode* targetNode = headNode;
    while(sourceNode!= nullptr)
    {
        targetNode->next = new chainNode(sourceNode->element);
        sourceNode = sourceNode->next;
        targetNode = targetNode->next;
    }
    targetNode->next = nullptr;
}

template 
chain::~chain()
{
    wsnippet_file_0hile(headNode!= nullptr)
    {
        chainNode* nextNode = headNode->next;
        delete headNode;
        headNode = nextNode;
    }
}

template 
T &chain::get(int index) const
{
    checkIndex(index);
    chainNode* currNode = headNode;
    for(int i=0;inext;
    return currNode->element;
}

template 
void chain::checkIndex(int index) const
{
    if(index<0 || index>=listSize)
    {
        cerr << "----! index outrange !----" << endl;
        return;
    }
}

template 
int chain::indexof(const T & theElement) const
{
    chainNode* currNode = headNode;
    for(int i = 0;ielement==theElement)
            return i;
        currNode = currNode->next;
    }
    return -1;
}

template 
void chain::erase(int index)
{
    checkIndex(index);
    chainNode* deleteNode;
    if(index==0)
    {
        deleteNode = headNode;
        headNode = headNode->next;
    } else
    {
        chainNode *p = headNode;
        for(int i=0;inext;
        deleteNode = p->next;
        p->next = p->next->next;
    }
    --listSize;
    delete deleteNode;
}

template 
void chain::insert(int index, const T &theElement)
{
    if(index<0 || index>listSize)
    {
        cerr << "---! insert index error !----" << endl;
        return;
    }
    if(index ==0)
    {
        headNode = new chainNode(theElement,headNode);
    } else
    {
        chainNode *p = headNode;
        for (int i = 0; i < index - 1; ++i)
            p = p->next;
        p->next = new chainNode(theElement, p->next);
    }
    listSize++;
}

template 
void chain::output(ostream &out) const
{
    for(chainNode* p = headNode;p != nullptr;p=p->next)
        out << p->element << " ";

}

template 
void chain::push_back(const T &theElement)
{
    chainNode* currNode = headNode;
    for(int i=0;inext;
    currNode->next = new chainNode(theElement, nullptr);
    ++listSize;
}

template 
void chain::clear()
{
    chainNode* p;
    while(headNode!= nullptr)
    {
        p = headNode->next;
        delete headNode;
        headNode = p;
    }
    listSize = 0;
}

template 
int chain::lastIndexOf(const T& theElement)
{
    int pos = -1;int i = 0;
    chainNode* p = headNode;
    while (p != nullptr)
    {
        if (p->element == theElement)
            pos = i;
        else
        {
            ++i;
            p = p->next;
        }
    }
}

template 
T& chain::operator[](int index) const
{
    checkIndex(index);
    chainNode* currNode = headNode;
    for(int i = 0;inext;
    return currNode->element;
}

template 
void chain::reverse()
{
    if(listSize==0 || listSize==1)
        return;
    else if(listSize == 2)
    {
        chainNode* p = headNode;
        headNode = headNode->next;
        headNode->next = p;
        p->next = nullptr;
    }
    else
    {
        chainNode* p = headNode;
        chainNode* q = headNode->next;
        chainNode* r = headNode->next->next;
        headNode->next = nullptr;
        while(r->next != nullptr)
        {
            q->next = p;
            p = q;
            q = r;
            r = r->next;
        }
        q->next = p;
        r->next = q;
        headNode = r;
    }

}

template 
ostream& operator<<(ostream& out, const chain &a)
{
    a.output(out);
    return out;
}


#endif //INC_02_CHAIN_CHAIN_H
隨便寫的測試:

#include <iostream>
#include "chain.h"
int main()
{
    chain<int> ic;
    ic.insert(0,1);ic.insert(0,2);ic.push_back(3);ic.push_back(4);
    chain<int> ic1(ic);ic1.reverse();
    cout << ic1 << endl;
    return 0;
}
我發現寫這個還是很鍛鍊人的,一個完善的數據結構輕輕鬆鬆幾百行代碼,每天一發,感覺很酸爽,C++簡直寫上癮。

不廢話了,我們迴歸頭來看看鏈表的頭文件裏都定義了啥:

chainNode類定義了節點類,包含數據成員以及指向下一個節點的指針。包含構造、拷貝以及析構函數。

chan類繼承自LinearList抽象類,包含節點類的成員變量,以及一個嵌套類iterator。

成員函數分爲幾個部分,首先是構造、拷貝以及析構函數,值得注意的是在構造函數中有一個參數initCapacity,實際是無作用的,僅僅爲了和之前的ArrayList一致。

然後是繼承自抽象類的方法,和ArrayList中的區別不大。

最後是我做的幾個習題,void removeRange(int fromIndex,int toIndex)的作用是將參數限定範圍內的節點刪除的操作。int lastIndexOf(const T& theElement)是返回與函數參數相等的最後一個位置的索引。T& operator[](int index) const 是對[]運算符進行重載,返回指定索引的節點的數據的引用。void reverse()是將整個鏈表進行反轉的操作,要求不開闢多餘的空間。



發佈了41 篇原創文章 · 獲贊 33 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章