數據結構與算法應用C++描述第六章的單鏈表的課後題部分

頭文件

#pragma once
#ifndef __EXTENDEDCHAIN__H
#define __EXTENDEDCHAIN__H


//注意,在模板類的繼承過程中,你在派生類中使用模板基類的成員的時候,一定要加上、
//這個模板類的類型的比如說我想使用listSize,那麼就只能使用mychain<T>::listSize纔可以
#include "mychain.h"
template<typename T> class extendedChain :public extendedLinearList<T>, public mychain<T>{
//這個C是有別於T的,所以是一對多的友元關係
template<typename C>friend bool operator==(const extendedChain<C> &left,const extendedChain<C> &right);
template<typename C>friend bool operator<(const extendedChain<C> &left,const extendedChain<C> &right);
template<typename C>friend void meld(const extendedChain<C> &a,const extendedChain<C> &b,extendedChain<C> &c);
template<typename C>friend void merge(const extendedChain<C> &a,const extendedChain<C> &b,extendedChain<C> &c);
template<typename C>friend void split(extendedChain<C> &a,extendedChain<C> &b,const extendedChain<C> &c);
public:
    //using mychain<T>::get;方法2
    extendedChain(int initialCapacity=10):mychain<T>(initialCapacity),lastNode(NULL){}
    extendedChain(const extendedChain<T> &theChain):mychain<T>(theChain){}//拷貝構造函數直接將派生類放到基類的拷貝構造函數中,可以將
    //派生類中的基類對象拷貝到基類中去.
    ~extendedChain(){}
    bool empty()const override{return this->listSize==0;}
    int size()const override{return this->listSize;}
    T &get(int theIndex) override{
        //return this->get(theIndex);這句話報錯了
        //分析下上述操作報錯的原因:Segmentation fault (core dumped)
        //因爲在這裏你使用的是this->get(theIndex),而你是在get(theIndex)中使用的這個函數
        //那麼就會因爲遞歸調用這個函數而產生錯誤!!!也就是上述的報錯信息。
        //方法2使用using,在你的public中首先聲明
        //using mychain<T>::get;
        return mychain<T>::get(theIndex);
        //方法2是可以的。
        //方法3,直接調用mychain<T>::get(theIndex);
        //但是請注意,不用方法2,3直接調用get(theIndex)是錯誤的!!!爲什麼是這樣的
        /*
        這裏分析一下:
1.Parsing of a template. This phase occurs when a template definition is first seen 
by a compiler (point of definition [3]). During this phase, the lookup is completed
only for nondependent names.
2.Template instantiation. It happens when a template is instantiated, with template 
parameters substituted by the actual template arguments (point of instantiation). 
It is during this phase when the dependent names are looked up. 
上述是關於模板類的兩階段查找名字的過程。用中文描述就是:
1.模板定義階段:剛被定義時,只有模板中獨立的名字(可以理解爲和模板參數無關的名字)參加查找
2.模板實例化階段:實例化模板代碼時,非獨立的名字才參加查找
這個舉個例子來說明一下:
#include<iostream>
using namespace std;

template<typename T>
class A
{
     public:    
	 void f() {   
	 	cout << "A::f()" << endl;    
	 }
};
template<typename T>
class B:public A<T>
{
    public:   
	void  g()
      { 
           f();//報錯,這樣寫的話
           this->f();//A::f()
		   A<T>::f();//A::f()
      } 
};
int main(){
	B<int> b;
	b.g();
}
首先進入B的模板定義階段,此時B的基類A<T>依賴於模板參數T,所以是一個非
獨立的名字。所以在這個階段,對於B來說A<T>這個名字是不存在的,於是A<T>::f()
也不存在。但此時這段代碼仍舊是合法的,因爲此時編譯器可以認爲f是一個非成員函數。
當稍晚些時候進入B的模板實例化時,編譯器已經堅持認爲f是非成員函數,縱使此時
已經可以查到A<T>::f(),編譯器也不會去這麼做。編譯器會認爲查找非成員函數沒必要
去基類裏面查找,所以這個時候就會找不到f了。於是就會報錯。找不到f(no delcaration)。
那我們回過頭來看this->f():
1.模板定義階段:儘管沒法查到A<T>::f(),但明晃晃的this->告訴編譯器,f是一個成員函數
不是B類裏,就是在B類的基類裏,於是編譯器記住了。
2.模板實例化階段:此時編譯器查找的對象是一個成員函數,首先在B中查找,沒有找到
;然後在基類裏查找,於是成功找到A<T>::f()。所以不會報錯了
此分析來自:https://www.zhihu.com/question/31797003


         *
         */
    }
    int indexOf(const T& theElememt)const override{return mychain<T>::indexOf(theElememt);}
    void erase(int theIndex) override;
    void insert(int theIndex,const T &theElememt)override;//
    void clear()override;
    void push_back(const T& theElememt)override;
    void output(std::ostream &out)const override;

    //實例化抽象類的extendedLinearList
    //練習題新增加的功能
    void setSize(int newSize);
    void set(int theIndex,const T &theElememt);
    //這個的工作區間是[);前閉後開區間
    void removeRange(int frontIndex,int lastIndex);
    int lastIndexOf(const T& theElememt)const;
    T &operator[](int theIndex);
    void swap(extendedChain<T> &theChain);
    void leftShift(int numbers);
    void reverse();
    void meld(extendedChain<T> &a,extendedChain<T> &b);//這個函數的形式也可以寫成這種形式void meld(extendedChain &a,extendedChain &b);
    void merge(extendedChain<T> &a,extendedChain<T> &b);
    void splitByIndex(extendedChain<T> &a,extendedChain<T> &b,int size);
    void circularShift(int i);
    //排序的方法
    void insertSort();//插入排序
    void bubbleSort();//冒泡排序
    void selectionSort();//選擇排序
    void countingSort();//計數排序

    //因爲在類的作用域內,可以不用寫T
protected:
    mychainNode<T> *lastNode;
};

template<typename T> void extendedChain<T>::erase(int theIndex){
    //注意,因爲加入了新的lastNode指針,所以我們在刪除的時候,要記得把尾指針給移動一下
    //查看索引是不是在有效範圍之內
    //下面這句話等價於this->checkIndex(theIndex);
    //extendedChain::checkIndex(theIndex);
    this->checkIndex(theIndex);
    //上面的那句話等價於mychain<T>::checkIndex(theIndex);
    mychainNode<T> *deletedNode = NULL;

    //如果有效的話,
    if(theIndex == 0){//如果是在第一個位置刪除的話,那麼需要
        deletedNode = this->firstNode;
        //等價於deletedNode = mychain<T>->firstNode;
        //等價於mychain<T>::firstNode = deletedNode->next;
        this->firstNode = deletedNode->next;
    }
    else{

        mychainNode<T> *p = this->firstNode;
        for(int i = 0; i != theIndex -1; ++i)
            p = p->next;
        deletedNode = p->next;
        p->next = deletedNode->next;
        if(deletedNode == lastNode)
            lastNode = p;
    }
    this->listSize--;
    delete deletedNode;
}

template<typename T> void extendedChain<T>::insert(int theIndex,const T &theElement){
    //首先檢查一下你要插入的索引是不是有效的
    if(theIndex < 0 || theIndex > this->listSize){
        std::ostringstream s;
        s<<" theIndex is "<<theIndex<<" and the listSize is "<<this->listSize;
        throw illegalParameterValue(s.str());
    }
    //如果要是索引有效的話,就繼續插入
    if(theIndex == 0){
        this->firstNode = new mychainNode<T>(theElement,this->firstNode);
        if(this->listSize == 0)
            lastNode = this->firstNode;//現在firstNode指向的是第一個節點,所以你的lastNode也指向該節點
        //如果不等於0的話,此時lastNode已經指向尾節點了,所以不需要改變
    }
    else{//如果索引不是等於0的話
        mychainNode<T> *p = this->firstNode;
        for(int i = 0; i != theIndex-1;++i)
            p = p->next;
        //現在p指向你要插入位置的前一個位置了
        p->next = new mychainNode<T>(theElement,p->next);
        if(this->listSize == theIndex)
            lastNode = p->next;//如果是在尾後插入的話,你需要把尾後lastNode轉移一下。往後移動一下
    }
    this->listSize++;
}

template<typename T> void extendedChain<T>::clear(){
    mychainNode<T> *p = NULL;
    while(this->firstNode != NULL){
        p = this->firstNode->next;//指向firstNode的下一個節點
        delete this->firstNode;//刪除firstNode指向的節點
        this->firstNode = p;//將firstNode指向原先的firstNode的下一個節點
    }
    this->listSize=0;
    lastNode = NULL;
}

template<typename T> void extendedChain<T>::push_back(const T& theElement){
    mychainNode<T> *newNode = new mychainNode<T>(theElement,NULL);
    if(this->firstNode == NULL){//也就是本來這個鏈表是空的話,listSize==0的時候
        this->firstNode = lastNode = newNode;
    }
    else{
        lastNode->next = newNode;
        lastNode = newNode;
    }
    this->listSize++;
}

template<typename T> void extendedChain<T>::output(std::ostream &out)const{
    mychain<T>::output(out);
    //this->output();//會發生內存溢出,因爲會遞歸調用
}


template<typename T> std::ostream &operator<<(std::ostream &out,const extendedChain<T> &x){
    x.output(out);
    return out;
}

template<typename T> void extendedChain<T>::setSize(int newSize){
    if(newSize < this->listSize){//如果新的大小小於原先的大小
        //則刪除多餘的元素
        while(this->listSize != newSize)
            this->erase(newSize);//lastNode已經在erase中處理了
    }
    //如果大於listSize,那麼不改變
}

template<typename T> void extendedChain<T>::set(int theIndex,const T& theElememt){
    this->checkIndex(theIndex);
    mychainNode<T> *p = this->firstNode;
    for(int i = 0; i != theIndex;++i)
        p = p->next;
    p->element = theElememt;
}

template<typename T> void extendedChain<T>::removeRange(int frontIndex,int lastIndex){
    if(frontIndex <0 || frontIndex>=this->listSize || frontIndex >= lastIndex){
        std::ostringstream s;
        s<<"the range is wrong"<<std::endl;
        throw illegalParameterValue(s.str());
    }
    //如果範圍正確的話,那就開始刪除
    int deletedIndex = frontIndex;
    while(frontIndex++ != lastIndex){
        this->erase(deletedIndex);//lastNode已經在erase中被處理了
    }
}

template<typename T> int extendedChain<T>::lastIndexOf(const T &theElememt)const{
    int index=0,i=0;
    bool flag=0;
    mychainNode<T> * p = this->firstNode;
    while( p != NULL ){
        if(p->element == theElememt){
            index = i;
            flag=1;
        }
        i++;p = p->next;
    }
    return flag==0 ? -1 : index;
}

template<typename T> T& extendedChain<T>::operator[](int theIndex){
    //通過這個方法的重寫,可以看出,在vector以及list中[]僅僅是改變現有的元素的
    //值的。但是不能用其新建一個元素,包括數組都是一樣的,[]僅僅是用來改變和
    //查找元素的,但是不能用來新建一個元素的
    mychainNode<T> *p = this->firstNode;
    for(int i = 0;i != theIndex;i++)
        p = p->next;
    return p->element;
}

template<typename T> bool operator==(const extendedChain<T> &left,const extendedChain<T> &right){
    mychainNode<T> *pLeft = left.mychain<T>::firstNode,*pRight = right.mychain<T>::firstNode;
    if(left.size() != right.size())//這個可以解決如果兩個很長的鏈表他們有很大一部分相同,那麼我們就要查好久,這樣會浪費很多時間
    //所以加一個長度比較可以防止出現這種極端的情況。
        return false;
    //left.mychain<T>::begin(); 
    //std::cout<<"the left is "<<left<<"\nand the right is "<<right<<std::endl;
    while(pLeft != NULL && pRight != NULL){
        if(pLeft->element != pRight->element)//如果有一個不相等直接返回false
            return false;
        else{//如果到目前爲止,元素一直相等,那麼我們就繼續比較
            pLeft = pLeft->next;pRight = pRight->next;
            //std::cout<<"left is "<<left.get(i)<<" and right is "<<right.get(i)<<std::endl;
        }
    }
    if(pLeft == NULL && pRight == NULL)
        return true;
    else
        return false;
}

template<typename T> bool operator!=(const extendedChain<T> &left,const extendedChain<T> &right){
    return !(left==right);
}

template<typename T> bool operator<(const extendedChain<T> &left,const extendedChain<T> &right){
    mychainNode<T> *pLeft = left.mychain<T>::firstNode,*pRight = right.mychain<T>::firstNode;

    int iShortLength = std::min(left.size(),right.size());
    int i = 0;
    //如果相等的話,我就直接返回false
    if(left == right)
        return false;
    //如果不相等的話,我就判斷是不是小於或者大於了
    while(i < iShortLength){
        if(pLeft->element > pRight->element)//因爲不相等了,所以一旦遇見一個>我們就直接返回false
            return false;
        else if(pLeft->element <= pRight->element){//如果到目前爲止,元素一直小於等於,那麼我們就繼續比較
            pLeft = pLeft->next;pRight = pRight->next;
            i++;
        }
    }
    //運行到這一步的是,就說明短的那個是比長的那個鏈表小了
    return (( left.size() <= right.size() ) ? true : false);

}

template<typename T> void extendedChain<T>::swap(extendedChain<T> &theChain){
    mychainNode<T> *tmp = this->firstNode;//保留該鏈表的頭結點
    //上面的語句等價於mychainNode *tmp = this->firstNode
    //在類的作用域內類名可以不用加<T>
    this->firstNode = theChain.mychain<T>::firstNode;//將本地的頭節點指針轉換到傳入的鏈表的頭結點中去
    theChain.mychain<T>::firstNode = tmp;//交換
    int length = this->listSize;
    this->listSize = theChain.mychain<T>::listSize;
    theChain.mychain<T>::listSize = length;
}

template<typename T> void extendedChain<T>::leftShift(int numbers){
    for(int i = 0; i != numbers;++i)
        erase(0);//lastNode已經在erase中被處理了
}

template<typename T> void extendedChain<T>::reverse(){
    /*
    //這個方法的複雜度爲O(n2)有點高
    //原地進行翻轉,其實就是兩個元素進行交換
    int midIndex = (this->listSize + 1)/2;
    T tmp;
    for(int i = 0; i != midIndex; ++i){
        std::swap(get(i),get(this->listSize-1-i));
        *
        tmp = get(i);
        set(i,get(this->listSize-1-i));
        set(this->listSize-i-1,tmp);//這個沒有涉及node節點的倒置,只是
        *
        //節點中的element被倒置,所以不需要處理lastNode;
    }
    */
    //下面這個算法的時間複雜度爲O(n)
    if(this->firstNode==NULL)
    	return;
    auto head = this->firstNode;
    while(head->next != NULL){
    	auto p = head->next;
    	head->next = p->next;
    	p->next = this->fisrtNode;
    	this->firstNode = p;
    }
}

template<typename T> void reverseNoMember(extendedChain<T> &a){
    a.reverse();
}

template<typename T> void meld(const extendedChain<T> &a,const extendedChain<T> &b,extendedChain<T> &c){
    c.clear();//如果c是非空的,我們首先需要把所有的原先的節點給刪除掉
    int iShortLength = std::min(a.size(),b.size()),i = 0;
    c.mychain<T>::firstNode = new mychainNode<T>(a.mychain<T>::firstNode->element);
    mychainNode<T> *pa = a.mychain<T>::firstNode->next;
    mychainNode<T> *pb = b.mychain<T>::firstNode->next;

    mychainNode<T> *p = c.mychain<T>::firstNode;
    p->next = new  mychainNode<T>(b.mychain<T>::firstNode->element);
    p = p->next;//已經添加了兩個節點了
    while(i++ != iShortLength-1){
        p->next = new mychainNode<T>(pa->element);
        p = p->next;
        p->next = new mychainNode<T>(pb->element);
        p = p->next;
        pa = pa->next;
        pb = pb->next;
    }
    while(pa != NULL){
        p->next = new mychainNode<T>(pa->element);
        p = p->next;
        pa = pa->next;
    }
    while(pb != NULL){
        p->next = new mychainNode<T>(pb->element);
        p = p->next;
        pb = pb->next;
    }
    //注意,上面的寫法還有一種就是類似我在下面的meld中寫的一樣的!!!
    c.lastNode = p;//處理下尾指針
    p->next = NULL;
    c.mychain<T>::listSize = a.size() + b.size();
}

template<typename T> void extendedChain<T>::meld(extendedChain<T> &a,extendedChain<T> &b){
    int iShortLength = std::min(a.size(),b.size()),i=0;
    this->clear();//先把原先所有的節點給清除掉
    /*
    this->firstNode = a.mychain<T>::firstNode;
    mychainNode<T> *p = this->firstNode;//讓p指向本對象的firstNode
    //然後讓本地的firstNode指向a的第一個節點
    //pa和pb都指向a和b的頭結點的下一個位置,爲的是讓可以讓別人找到這個節點
    mychainNode<T> *pa = a.mychain<T>::firstNode->next;
    mychainNode<T> *pb = b.mychain<T>::firstNode->next;
    p->next = b.mychain<T>::firstNode;//到這一步,已經進行了兩個節點的合併了
    p = p->next;//合併完了
    while(i++ != (iShortLength-1)){
        std::cout<<"\n 進入了while循環中";
        a.mychain<T>::firstNode = pa;//得到最新的頭結點
        b.mychain<T>::firstNode = pb;
        
        pa = pa->next;//保留好下一個節點的位置
        pb = pb->next;

        //將兩個鏈表當前的頭結點進行合併
        p ->next = a.mychain<T>::firstNode;
        p = p->next;
        p->next = b.mychain<T>::firstNode;
        p = p->next;
    }
    */
    //這是第二種方法
    int index = 0;
    this->firstNode    = a.mychain<T>::firstNode;
    mychainNode<T> *p  = this->firstNode;

    mychainNode<T> *pa = a.mychain<T>::firstNode->next;
    mychainNode<T> *pb = b.mychain<T>::firstNode;

    while(pa != NULL && pb != NULL){
        if(index % 2 == 0){//用來表示每次插入的位置
            p->next = pb;
            p = p->next;
            pb = pb->next;
        }
        else{
            p->next = pa;
            p = p->next;
            pa = pa->next;
        }
        index++;
    }
    if(pa != NULL){//如果鏈表a還有元素的話
        p->next = pa;
        lastNode = a.lastNode;
    }else if(pb != NULL){
        p->next = pb;
        lastNode = b.lastNode;
    }
    this->listSize = a.size() + b.size();
    a.mychain<T>::firstNode = NULL;
    b.mychain<T>::firstNode = NULL;
    a.mychain<T>::listSize = b.mychain<T>::listSize = 0;
}

template<typename T> void merge(const extendedChain<T> &a,const extendedChain<T> &b,extendedChain<T> &c){
    //注意a和b都是有序的鏈表
    //先c本身所擁有的全部節點給刪除掉
    c.clear();
    mychainNode<T> *pa = a.mychain<T>::firstNode;
    mychainNode<T> *pb = b.mychain<T>::firstNode;
    //注意,對於空的firstNode,千萬不能寫成這樣的
    //mychainNode<T> *p = this->firstNode;因爲這樣的話,p僅僅是和
    //firstNode指向的位置一樣,但是p->next = otherP;那麼我的firstNode是沒改變的
    //只有firstNode是有值的時候,纔是可以的,也就是對於這種合併的,我們
    //必須先確保this->firstNode是有值的纔可以。
    if(pa->element <= pb->element){
        c.mychain<T>::firstNode = new mychainNode<T>(pa->element);
        pa = pa->next;
    }
    else{
        c.mychain<T>::firstNode = new mychainNode<T>(pb->element);
        pb = pb->next;
    }
    mychainNode<T> *p  = c.mychain<T>::firstNode;
    while(pa != NULL && pb != NULL){
        if(pa->element <= pb->element){
            p->next = new mychainNode<T>(pa->element);
            p = p->next;
            pa = pa->next;
        }
        else{
            p->next = new mychainNode<T>(pb->element);
            p = p->next;
            pb = pb->next;
        }
    }
    /*
    while(pa != NULL && pb != NULL){
        //前插法
        //c.mychain<T>::firstNode = new mychainNode<T>(pa->element,c.mychain<T>::firstNode);
        if(pa->element <= pb->element){//前插法,所以需要到最後倒轉一下
            c.mychain<T>::firstNode = new mychainNode<T>(pa->element,c.mychain<T>::firstNode);            
            pa = pa->next;
        }
        else{
            c.mychain<T>::firstNode = new mychainNode<T>(pb->element,c.mychain<T>::firstNode);
            pb = pb->next;
         }
    }
    
    注意使用本方法的時候需要在結尾加個翻轉的工作,因爲這是使用前插法的方法去插入元素的
    */


    //如果一個鏈表的元素都取完了,那麼剩下的就是把沒有遍歷完的給合併了
    while(pa != NULL){
        p->next = new mychainNode<T>(pa->element);
        p = p->next;
        pa = pa->next;
    }
    while(pb != NULL){
        p->next = new mychainNode<T>(pb->element);
        p = p->next;
        pb = pb->next;
    }
    c.lastNode = p;
    c.mychain<T>::listSize = a.size() + b.size();
}

template<typename T> void extendedChain<T>::merge(extendedChain<T> &a,extendedChain<T> &b){
    this->clear();//先把原先的成員的節點給刪除掉
    //這個需要我們不去單獨創建新的節點,而是利用a和b的節點去做
    //先讓pa和pb分別指向a和b的頭結點
    mychainNode<T> *pa = a.mychain<T>::firstNode,*pb = b.mychain<T>::firstNode;
    //然後讓c的第一個指針指向兩個鏈表的最小的那個
    if(a.mychain<T>::firstNode->element <= b.mychain<T>::firstNode->element){
        this->firstNode = a.mychain<T>::firstNode;
        pa = pa->next;   
    }else {
        this->firstNode = b.mychain<T>::firstNode;
        pb = pb->next;
    }   
    mychainNode<T> *p  = this->firstNode;
    while(pa != NULL && pb != NULL){
        if(pa->element <= pb->element){
            p->next = pa;
            p = p->next;
            pa = pa->next;
        }else{
            p->next = pb;
            p = p->next;
            pb = pb->next;
        }
    }
    if(pa != NULL ){
        p->next = pa;
        lastNode = a.lastNode;
    }else{
        p->next = pb;
        lastNode = b.lastNode;
    }
    this->listSize = a.size() + b.size();
    a.mychain<T>::firstNode = NULL;
    b.mychain<T>::firstNode = NULL;
    a.mychain<T>::listSize = b.mychain<T>::listSize = 0;
}

template<typename T> void split(extendedChain<T> &a,extendedChain<T> &b,const extendedChain<T> &c){
    a.clear();b.clear();//首先不管a和b是不是空,我們都要給它清空
    mychainNode<T> *p  = c.mychain<T>::firstNode;
    a.mychain<T>::firstNode = new mychainNode<T>(p->element);
    p = p->next;
    mychainNode<T> *pa = a.mychain<T>::firstNode;//a是奇數項

    b.mychain<T>::firstNode = new mychainNode<T>(p->element);
    p = p->next;
    mychainNode<T> *pb = b.mychain<T>::firstNode;
    
    int index = 0;
    while(p != NULL){
        if(index % 2 == 0){
            pa->next = new mychainNode<T>(p->element);
            pa = pa->next;
            p = p->next;
        }else{
            pb->next = new mychainNode<T>(p->element);
            pb = pb->next;
            p = p->next;
        }
        index++;
    }
    a.lastNode = pa;
    b.lastNode = pb;
    a.mychain<T>::listSize = (c.mychain<T>::listSize + 1)/2;//奇數項
    b.mychain<T>::listSize = (c.mychain<T>::listSize + 1)/2;//偶數項
}

template<typename T> void extendedChain<T>::splitByIndex(extendedChain<T> &a,extendedChain<T> &b,int size){
    a.clear();b.clear();//不管a和b是不是空的,都給清空
    a.mychain<T>::firstNode = new mychainNode<T>(this->firstNode->element);

    mychainNode<T> *pa = a.mychain<T>::firstNode;
    mychainNode<T> *p  = this->firstNode->next;
    int index = 0;
    while(index++ != size-1){
        pa->next = new mychainNode<T>(p->element);
        p = p->next;
        pa = pa->next;
    }//到了這一步,已經把前size個元素分配給a了
    b.mychain<T>::firstNode = new mychainNode<T>(p->element);
    p = p->next;
    mychainNode<T> *pb = b.mychain<T>::firstNode;
    while(p != NULL){
        pb->next = new mychainNode<T>(p->element);
        p = p->next;
        pb = pb->next;
    }

    a.lastNode = pa;b.lastNode = pb;
    a.mychain<T>::listSize = size;b.mychain<T>::listSize = this->mychain<T>::listSize - size;
}

template<typename T> void extendedChain<T>::circularShift(int i){
    //circularShift其實就是三次倒置而已
    //先把本對象分成兩個,然後各自倒置,再合併一下就好了
    extendedChain<T> a;extendedChain<T> b;
    this->reverse();//先倒置
    this->splitByIndex(a,b,this->size()-i);
    a.reverse();b.reverse();//把a和b倒置
    std::cout<<"a is "<<a<<" and b is "<<b<<std::endl;
    mychainNode<T> *pa = a.mychain<T>::firstNode;
    mychainNode<T> *pb = b.mychain<T>::firstNode;
    mychainNode<T> *p = this->firstNode;
    while(pa != NULL){
        p->element  = pa->element;
        p = p->next;
        pa = pa->next;
    }
    while(pb != NULL){
        p->element = pb->element;
        p = p->next;
        pb = pb->next;
    }
    //因爲我們只是改的值,沒有動節點,所以不需要改變大小和lastNode節點

}
//插入排序的時間複雜度是O(n2) = 3*(n+1)*n/2
//其實就是插入到有序的鏈表中去就是普通的插入排序的思路
//插入排序的時間複雜度
template<typename T> void extendedChain<T>::insertSort(){
    mychainNode<T> *insertElement = this->firstNode->next;//這個表示用來插入的節點的
    while(insertElement != NULL){
        mychainNode<T> *p = this->firstNode;
        while(p->element <= insertElement->element && p != insertElement){
            p = p->next;//如果小於的了的話,那麼就一直往右查找
        }//已經找到了要改變的元素的位置了
        //第一個while循環是用來查找要插入的位置的 
        //第二個while循環是用來改變當前鏈表中的元素的值的
        while(p != insertElement){
            /*
            //自己寫的swap功能
            T tmp;
            //通過將當前的位置節點的元素的值與最後一個位置進行
            //交換,就是把最後一個節點當做是一箇中轉的,然後讓
            //所有的元素都與這個進行交換
            tmp = p->element;
            p->element = insertElement->element;
            insertElement->element = tmp;
            */
            std::swap(p->element,insertElement->element);//利用標準庫函數的swap函數
            p = p->next;
        }    
        insertElement = insertElement->next;
    }
}
//冒泡排序的時間複雜度是O(n2) = 3*(n+1)*(n)/2
template<typename T> void extendedChain<T>::bubbleSort(){
    //冒泡的話,我們就直接找兩個尾節點就好了
    mychainNode<T> *lastNodeOfChain = lastNode;
    mychainNode<T> *tmp=NULL;
    while(this->firstNode != lastNodeOfChain){//這個是表示的是我從最長的鏈表到最小的鏈表
        mychainNode<T> *p = this->firstNode;//這個是用來從頭到尾去遍歷當前的鏈表的
        while(p != lastNodeOfChain){//去遍歷當前這個鏈表
            if(p->element > p->next->element){
                std::swap(p->element,p->next->element);//如果左邊的大,那麼我們就交換
            }
            if(p->next == lastNodeOfChain){
                tmp = p;//保留當前尾節點的前一個位置,用來作爲下一次遍歷的鏈表的尾節點
            }
            p = p->next;
        }
        lastNodeOfChain = tmp;
    }
}
//選擇排序算法
//算法思想主要是先找出本鏈表中最大的一個節點,然後放到最後
//依次縮短鏈表就可以得出
//時間複雜度爲O(n2)
template<typename T> void extendedChain<T>::selectionSort(){
    mychainNode<T> *lastNodeOfChain = lastNode;
    mychainNode<T> *tmp=NULL;
    while(this->firstNode != lastNodeOfChain){//這個是表示的是我從最長的鏈表到最小的鏈表
        mychainNode<T> *p = this->firstNode;//這個是用來從頭到尾去遍歷當前的鏈表的
        mychainNode<T> *Max = this->firstNode;//這個是用來保存當前鏈表中最大的元素
        while(p != lastNodeOfChain){//去遍歷當前這個鏈表
            if(p->element > Max->element){
                Max = p;//保留較大的成員
            }
            if(p->next == lastNodeOfChain){
                tmp = p;//保留當前尾節點的前一個位置,用來作爲下一次遍歷的鏈表的尾節點
            }
            p = p->next;
        }
        std::swap(Max->element,lastNodeOfChain->element);
        lastNodeOfChain = tmp;
    }
}

/*
 算法思想就是找到每個元素的名次位置信息,然後在鏈表中進行一個一個位置找到其真正對應的
 元素
 *
 */
template<typename T> void extendedChain<T>::countingSort(){
    //首先需要藉助一個數組去存儲相應的名次信息
    //分兩步去實現,第一步是先建立好相應的元素的名稱信息
    int *res = new int[this->listSize];//res是用來保存各個元素的名次信息的
    int currentIndex = 0;
    for(int i = 0; i != this->listSize; i++)
        res[i] = 0;
    mychainNode<T> *currentHead = this->firstNode;
    mychainNode<T> *lastNodeOfChain = lastNode;
    mychainNode<T> *tmp = NULL;
    int index = 0;
    while(currentHead != lastNodeOfChain){//控制鏈表的長度
        mychainNode<T> *p = currentHead;
        currentIndex = index+1;
        while(p != lastNodeOfChain){//遍歷當前的鏈表
            if(currentHead->element >= p->next->element)
                res[index]++;
            else
                res[currentIndex]++;
            currentIndex++;
            p = p->next;
        }
        currentHead = currentHead->next;
        index++;
    }
    //通過上面的步驟已經得到了各個節點元素對應的名次的位置信息了
    for(int i = 0; i != this->listSize;++i){
        while(res[i] != i){//這個主要是用來讓這個i對應的位置一定要找到相應的元素纔可以結束
            //這個while一定得加,只有讓這個位置找到其對應的元素纔可以進行下一個位置的查找
            std::swap(get(i),get(res[i]));
            std::swap(res[i],res[res[i]]);        
        }    
    }
} 
#endif

.cpp文件

#include "extendedChain.h"



int main()
{   extendedChain<char> L;
    for(int i = 0;i != 5;++i)
        L.insert(i,'a'+i);
    std::cout<<L<<std::endl;
    L.setSize(14);
    std::cout<<"L is "<<L<<" and the size is "<<L.size()<<std::endl;
    L.set(0,'f');
    std::cout<<L<<std::endl;
    //L.removeRange(0,3);
    std::cout<<L.indexOf('f')<<std::endl;
    L.insert(3,'f');
    std::cout<<L<<std::endl;
    std::cout<<L.lastIndexOf('f')<<std::endl;
    L[3] = 'j';
    std::cout<<L<<std::endl;
    extendedChain<char> L1(L);
    std::cout<<"L is\n"<<L;
    L1[5] = 'i';
    //std::cout<<"after the L1[5] the L is\n"<<L;
    std::cout<<"\nthe L1 is\n"<<L1<<std::endl;
    //注意這裏,我現在還不清楚爲什麼在std::cout中,輸出的時候進入的==函數中傳入的參數左右顛倒了,也就是
    //left綁定的是第二個參數,而right綁定的是第一個參數
    std::cout<<"L is equal to L1 ? "<<(L==L1)<<"\nand the L1 is equal to L ? "<<(L1==L)<<std::endl;

    std::cout<<"L is not equal to L1 ? "<<(L != L1)<<std::endl;
    std::cout<<"this is the test\n";
    std::cout<<"L is < L1 ? "<<(L < L1)<<std::endl;

    //測試swap;
    std::cout<<"the current L is "<<L<<" and the L1 is "<<L1<<std::endl;
    L.swap(L1);
    std::cout<<"after the L.swap(L1) the L is "<<L<<" and the L1 is "<<L1<<std::endl;
    
    //測試L.reverse
    std::cout<<"the current L is "<<L<<std::endl;
    L.reverse();
    std::cout<<"after the L.reverse the L is "<<L<<std::endl;

    reverseNoMember(L);
    std::cout<<"after the reverseNoMember(L) the L is "<<L<<std::endl;

    //測試leftShift
    L.leftShift(2);
    std::cout<<"after the L.leftShit(2) the L is "<<L<<std::endl;
    
    //測試meld
    extendedChain<char> L2;
    meld(L1,L,L2);
    std::cout<<"L is "<<L<<" and L1 is "<<L1<<std::endl;
    std::cout<<"after meld(L1,L,L2) the L2 is "<<L2<<std::endl;
    //測試meld成員函數
    extendedChain<int> L3,L4,L5;
    L3.insert(0,1);L4.insert(0,2);
    L3.insert(1,3);L4.insert(1,4);
    std::cout<<"L3 is "<<L3<<" and L4 is "<<L4;
    L5.meld(L3,L4);
    std::cout<<"after L5.meld(L3,L4) L5 is "<<L5<<std::endl;


    //測試merge非成員函數
    L3.insert(0,10);L4.insert(0,20);
    L3.insert(1,30);L4.insert(1,40);
    merge(L3,L4,L5);
    std::cout<<"after merge L5 is "<<L5<<std::endl;
    L5.merge(L3,L4);
    std::cout<<"after L5.merge the L5 is "<<L5<<std::endl;

    //測試split
    std::cout<<"L3 is "<<L3<<" and the L4 is "<<L4<<" and the L5 is "<<L5<<std::endl;
    split(L4,L3,L5);
    std::cout<<"after the split(L4,L3,L5) the L3 is "<<L3
    <<" and the L4 is "<<L4<<" and the L5 is "<<L5<<std::endl;

    //測試circuShift()
    std::cout<<"the current L2 is "<<L2<<std::endl;
    L2.circularShift(4);
    std::cout<<"after the L2.circularShift(4) the L2 is "<<L2<<std::endl;

    //
    L2.insert(L2.size(),'a');
    std::cout<<"the current L2 is "<<L2<<std::endl;
    //測試插入排序
    //L2.insertSort();
    //測試冒泡排序
    //L2.bubbleSort();
    //測試選擇排序
    //L2.selectionSort();
    //測試計數排序
    L2.countingSort();
    std::cout<<"after tne L2.countingSort() the L2 is "<<L2<<std::endl;

    
    
    return 0;
}

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