頭文件
#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;
}