數據結構學習——線性錶鏈式描述

阿偉最近墮落了一段時間,如今覺醒,阿偉又要堅持寫博客了!
最近數據結構學的一頭霧水,阿偉要從頭開始學數據結構了QAQ

首先給出線性表的ADT(抽象類)
(有關類模板在這裏

template <class T>
class linearList
{
public:
    virtual ~linearList(){};
    virtual bool empty() const=0;//返回true,當且僅當線性表爲空
    virtual int size() const=0;//返回線性表的元素個數
    virtual T& get(int theIndex) const=0;//返回索引爲theIndex的元素
    virtual int indexOf(const T& theElement) const=0;//返回元素theElement第一次出現的索引
    virtual void erase(int theIndex)=0;
    virtual void insert(int theIndex,const T& theElement)=0;
    virtual void output(ostream& out) const=0;//把線性表插入輸出流out
};

接下來是鏈表結點的定義,用的是結構體

template <class T>
struct chainNode
{
    T element;
    chainNode<T> *next;

    chainNode(){}
    chainNode(const T& element)
    {
        this->element=element;
    }
    chainNode(const T& element,chainNode<T>* next)
    {
        this->element=element;
        this->next=next;
    }
};

接下來是鏈表的定義

template <class T>
class chain:public linearList<T>
{
public:
    chain(int initialCapacity=10);//構造函數
    chain(const chain<T>&);//複製構造函數
    ~chain();//析構函數
    //ADT方法
    bool empty() const
    {
        return listSize==0;
    }
    int size() const
    {
        return listSize;
    }
    T& get(int theIndex)const;
    int indexOf(const T& theElement) const;
    void erase(int theIndex);
    void insert(int theIndex,const T& theElement);
    void output(ostream& out) const;
protected:
    void checkIndex(int theIndex) const;//如果索引無效,拋出異常
    chainNode<T>* firstNode;//指向鏈表第一個結點的指針,注意並不是頭結點
    int listSize;//線性表的元素個數
};

1. checkIndex函數的實現:

template<class T>
void chain<T>::checkIndex(int theIndex)const
{//確定索引在0和listSize-1之間
    if(theIndex<0||theIndex>=listSize)
    {
        ostringstream s;
        s<<"index="<<theIndex<<"size= "<<listSize;
        throw illegalIndex(s.str());
    }
}

2. 鏈表的構造函數(時間複雜度θ(1)

template<class T>
chain<T>::chain(int initialCapacity)
{
    if(initialCapacity<1)
    {
        ostringstream s;
        s<<"Initial capacity = "<<initialCapacity<<"Must be > 0";
        throw illegalParameterValue(s.str());
    }
    firstNode=NULL;
    listSize=0;
}

3. 鏈表的複製構造函數(時間複雜度*O( max{listSize,theList.listSize} ))

template<class T>
chain<T>::chain(const chain<T>& theList)
{
    listSize=theList.listSize;
    if(listSize==0)//鏈表theList爲空
    {
        firstNode=NULL;
        return;
    }
    //若不爲空
    chainNode<T>* sourceNode=theList.firstNode;//複製鏈表theList的節點
    firstNode=new chainNode<T>(sourceNode->element);//複製鏈表theList的首元素
    sourceNode=sourceNode->next;
    chainNode<T>* targetNode=firstNode;//當前鏈表的最後一個節點
    //複製剩餘元素
    while(sourceNode!=NULL)
    {
        targetNode->next=new chainNode<T>(sourceNode->element);
        targetNode=targetNode->next;
        sourceNode=sourceNode->next;
    }
    targetNode->next=NULL;//鏈表結束
}

對複製構造函數進行解釋:
在這裏插入圖片描述

4. 鏈表的析構函數(時間複雜度O(listSize))
析構函數是刪除所有節點,用的方法是從首結點開始刪除

template<class T>
chain<T>::~chain()//刪除鏈表的所有節點
{
    while(firstNode!=NULL)//刪除首節點
    {
        chainNode<T>* nextNode=firstNode->next;
        delete firstNode;
        firstNode=nextNode;
    }
}

5. get函數的實現(時間複雜度O(theIndex))
此函數的功能是找到指定索引的元素

template<class T>
T& chain<T>::get(int theIndex)const
{
    checkIndex(theIndex);//如果索引不存在,則拋出異常
    chainNode<T>* currentNode=firstNode;
    //移向所需要的節點
    for(int i=0;i<theIndex;i++)
        currentNode=currentNode->next;
    return currentNode->element;
}

6. indexOf函數的實現(時間複雜度O(listSize))
此函數的功能是找到元素theElement第一次出現的索引
如果沒找到,返回-1,找到了返回索引

template<class T>
int chain<T>::indexOf(const T& theElement)const
{
    chainNode<T>* currentNode=firstNode;
    int index=0;
    //退出循環的條件:①沒有找到,找到了最後,currentNode爲空;②找到了
    while(currentNode!=NULL&&currentNode->element!=theElement)
    {
        currentNode=currentNode->next;
        index++;
    }
    //如果是由於沒有找到退出的循環
    if(currentNode==NULL)
        return -1;
    //否則
    return index;
}

7. erase函數的實現(時間複雜度O(theIndex))
分爲三種情況:
①:theIndex<0或theIndex>=listSize。這時操作無效
②:刪除非空表的第0個元素節點(首元素)
③:刪除其他元素節點

template<class T>
void chain<T>::erase(int theIndex)
{
    checkIndex(theIndex);
    if(theIndex==0)//如果要刪除首節點
    {
        firstNode=firstNode->next;
    }
    else
    {
        chainNode<T>* currentNode=firstNode;
        for(int i=0;i<theIndex-1;i++)//找到要刪除的節點的前驅節點
        {
            currentNode=currentNode->next;
        }
        currentNode->next=currentNode->next->next;
    }
    listSize--;//將鏈表的個數減一
}

8. insert函數的實現(時間複雜度O(theIndex))
插入函數和刪除函數相似
下面是阿偉寫的代碼(看到課本上寫的我被自己菜哭了)

template<class T>
void chain<T>::insert(int theIndex,const T& theElement)
{
    chainNode<T>* tmpNode=new chainNode<T>(theElement);
    if(theIndex==0)
    {
        tmpNode->next=firstNode;
        firstNode=tmpNode;
    }
    else
    {
        chainNode<T>* p=firstNode;
        for(int i=0;i<theIndex-1;i++)
        {
            p=p->next;
        }
        tmpNode->next=p->next;
        p->next=tmpNode;//這兩行代碼位置不能換,因爲如果先將p指向tmpNode,那之前p的後繼就找不到了
    }
    listSize++;
}

下面請欣賞課本代碼:

template<class T>
void chain<T>::insert(int theIndex,const T& theElement)
{
    if(theIndex<0||theIndex>listSize)
    {
        ostringstream s;
        s<<"index="<<theIndex<<"size="<<listSize;
        throw illegalIndex(s.str());
    }
    if(theIndex==0)
        firstNode=new chainNode<T>(theElement,firstNode);
    else
    {
        chainNode<T>* p=firstNode;
        for(int i=0;i<theIndex-1;i++)
            p=p->next;
        p->next=new chainNode<T>(theElement,p->next);//太強了!
    }
    listSize++;
}

9. 對擴展的線性表的抽象類
需要擴展ADT使線性表包含一些其他操作,如清表clear,將元素插到表尾push_back

template<class T>
class extendedLinearList::linearList<T>
{
public:
    virtual ~extendedLinearList(){}
    virtual void clear()=0;//清表
    virtual void push_back(const T& theElement)=0;//將元素theElement插到表尾
};

10. clear函數的實現
我們需要開發一個類extendedChain,作爲抽象類extendedLinearList的鏈式描述,開發的捷徑是從鏈表chain派生,並且增加lastNode指針指向尾結點
下面是clear函數的實現

template<class T>
void extendedChain<T>::clear()
{
    //從首節點開始刪除
    while(firstNode!=NULL)
    {
        chainNode<T>* nextNode=firstNode->next;
        delete firstNode;
        firstNode=nextNode;
    }
    listSize=0;
}

11. push_back函數的實現

template<class T>
void extendedChain<T>::push_back(const T& theElement)
{
    chainNode<T>* newNode=new chainNode<T>(theElement,NULL);
    if(firstNode==NULL)
        firstNode=lastNode=newNode;//extendedChain中聲明瞭尾結點lastNode
    else
    {
        lastNode->next=newNode;
        lastNode=newNode;
    }
    listSize++;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章