//数据结构算法与应用-C++语言描述 stack链表的实现
//链表描述
main.cpp
#include <iostream>
#include <sstream>
#include <iterator>
using namespace std;
//数据结构算法与应用-C++语言描述 chain 单链表
//一个线性表的抽象类
template <class T>
class linearList
{
public:
virtual ~linearList(){}
//返回true,当且仅当线性表为空
virtual bool empty() const = 0;
//返回线性表的元素个数
virtual int size() const = 0;
//返回索引为 theIndex 的元素
virtual T& get(int theIndex) const = 0;
//返回元素 theElement 第一次出现时的索引
virtual int indexOf(const T& theElement) const = 0;
//删除索引为 theIndex 的元素
virtual void erase(int theIndex) = 0;
//把 theElement 插入线性表中索引为 theIndex 的位置上
virtual void insert(int theIndex, const T& theElement) = 0;
//把线性表插入输出流 out
virtual void output(ostream& out) const = 0;
};
/*
结构 chainNode
为了用链表摘述线性表,我们要定义一个结构 chainNode 和一个类 chain。
数据成员 element 是节点的数据域,存储表元素; 数据成员 next 是节点的链域,存储下一个节点的指针。
*/
//链表节点的结构定义
template <class T>
struct chainNode
{
public:
//方法
chainNode(){}
chainNode(const T& element)
{
this->element = element;
}
chainNode(const T& element,chainNode<T>* next)
{
this->element = element;
this->next = next;
}
//数据成员
T element;
chainNode<T> *next;
};
//类 chain
/*
1. 链表 chain 的方法 header、empty 和 size
类 chain 用单向链表实现了线性表,其中最后一个节点的指针域为NULL,即它用单向
链接的一组节点实现线性表
*/
template<class T>
class chain : public linearList<T>
{
public:
//构造函数,复制构造函数和析构函数
chain(int initialCapacity = 10);
chain(const chain<T>&);
~chain();
//抽象数据类型 ADT 的方法
bool empty() const override { return listSize == 0;}
int size() const override {return listSize;}
T& get(int theIndex) const override;
int indexOf(const T& theElement) const override;
void erase(int theIndex) override;
void insert(int theIndex, const T& theElement) override;
void output(ostream& out) const override;
T getFirstNode(){return firstNode->element;}
T getLastNode(){return lastNode->element;}
//清表
void clear();
//将元素 theElement 插到表尾
void push_back(const T& theElement);
//ex2.大小小于 theSize,则不增加元素。若初始线性表的大小大于 theSize,则删除多余的元素。
//计算方法的复杂度。测试你的代码。
void setSize(int theSize);
//ex3. 编写方法 chain<T>::set(theIndex,theElement),它用元素 theElement 替换索引为 thelndex 的
//元素。若索引 theIndex 超出范围,则抛出异常。计算方法的复杂度。测试你的代码。
void set(int theIndex,const T& theElement);
//ex4. 编写方法 chain<T>::removeRange(fromIndex,toIndex),它删除指定索引范围内的所有元素。
//计算方法的复杂度。测试你的代码。
void removeRange(int fromIndex,int toIndex);
//ex5. 编写方法 chain<T>::lastIndexOf(theElemen),返回值是指定元素最后出现时的索引。若这
//样的元素不存在,则返回 -1。计算方法的复杂度。测试你的代码。
int lastIndexOf(const T& theElement) const;
//ex6. 重载操作符 [] ,使得表达式 x[i] 返回对链表 x 的第 i 个元素的引用。若链表没有第 i 个元素,
//则抛出异常。语句 x[i] = y 和y=x[i]按以往预期的方式执行。测试你的代码。
chainNode<T>& operator[](int theIndex);
//ex7. 重载操作符 ==,使得表达式 x==y 返回 true,当且仅当两个链表 x 和y 相等,即对所有的
//i,两个链表的第 i 个元素相等。测试你的代码。
bool operator==(const chain<T>& right) const;
//ex8. 重载操作符 !=,使得表达式 x!=y 返回 true,当且仅当两个链表 x 和y 不等 ( 见练习7 )。测
//试你的代码。
bool operator!=(const chain<T>& right) const;
//ex9 重载操作符 <,使得表达式 x<y 返回 true,当且仅当链表 x 按字典顺序小于链表 y( 见练习
//7)。测试你的代码。
bool operator<(const chain<T>& right) const;
//ex10. 编写方法 chain<T>::swap(theChain),它交换链表元素 *this 和 theChain。计算方法的复杂
//度。测试你的代码。
void swap(chain<T>& right);
//ex14. 1 ) 编写方法 chain<T>::leftShiftt),它将表中的元素向左移动个位置。如果 1=[0,1,2,3,4] ,
//那么 leftShift(2) 的结果是 1=[2,3,4]。
//2 ) 计算方法的复杂度。
//3 ) 测试你的代码。
void leftShift(int i);
//ex15. 1 ) 编写方法 chain<T>::reverse,它颠倒 *this 中的元素的顺序,而且原地完成,不用分配
//任何新的节点空间。
//2 ) 计算方法的复杂度。
//3 ) 使用自己的测试数据检验方法的正确性。
void reverse();
//ex17
//1 ) 编写一个非成员方法 meld,它生成一个新的扩展的链表 c,它从 a 的首元素开始,交
//替地包含a 和 b的元素。如果一个链表的元素取完了,就把另一个链表的剩余元素附
//加到新的扩展链表 c 中。方法的复杂度应与链表 a 和 的长度具有线性关系。
//2 ) 证明方法具有线性复杂度。
//3 ) 使用自己的测试数据检验方法的正确性。
chain<T>& meld1(const chain<T>& a, const chain<T>& b);
//ex18. 编写方法 chain<T>::meld。它与练习 17 的方法 meld类似。然而,a 和b 以及合并结果,
//都是 chain<T> 类型。合并后的链表使用的应该是链表 a 和 的节点空间。合并之后,输
//链表a 和b 是空表。
//1 ) 编写方法 meld,其复杂度应该与输入链表的长度具有线性关系。
//2 ) 证明方法具有线性复杂度。
//3 ) 测试代码的正确性。使用自己的测试数据。
chain<T>& meld2(chain<T>& a, chain<T>& b);
//ex19.
//1 ) 编写一个非成员方法 merge,它生成一个新的有序链表 c,包含a 和 b的所有元素。
//2 ) 计算方法的复杂度。
//3 ) 使用自己的测试数据检验方法的正确性。
chain<T>& merge1(chain<T>& a, chain<T>& b);
//ex20. 重做练习 19,但是编写的是方法 chain<T>::merge。归并之后,两个输入链表a 和 为空
chain<T>& merge2(chain<T>& a, chain<T>& b);
//ex22. 编写方法 chain<T>::split,它与练习 21 的函数类似。然而,它用输入链表 *this 的空间建
//立了链表a和b。
chain<T>& split(chain<T>& a, chain<T>& b);
//ex23. 在一个循环移动的操作中,线性表的元素根据给定的值,按顺时针方向移动。例如
//L=[0,1,2,3,4],循环移动 2 的结果是 L=[2,3,4,0,1]。
//1 ) 编写方法 circularShift(i),它将线性表的元素循环移动i 个位置。
//2 ) 测试你的代码。
chain<T>& circularShift(int index);
//ex26. 编写方法 chain<T>::insertSort,它使用插入排序 ( 见程序 2-15 ) 对链表按非递减顺序重新排序。
//不开发新的节点,也不删除老的节点。可以假设元素的类型定义了关系操作符 (<、> 等)。
//1 ) 方法在最坏情况下的复杂度是多少? 如果元素已经有序,那么该方法需要多少时间?
//2 ) 使用自己的测试数据检验方法的正确性。
chain<T>& insertionSort();
//ex27. 对如下的排序方法 ( 见第 2 章的描述 ) 重做练习 26:
//1 ) 冒泡排序。
//2 ) 选择排序。
//3 ) 计数排序或排列排序。
chain<T>& bubbleSort();
chain<T>& selectionSort();
//void rank(int rank[]);
// chain<T>& rankSort();
//每个箱子都以底部节点作为首节点,项部节点作为尾节点。每个箱子都有两个指
//针,分别存储在数组 bottom 和top 中,分别指向尾节点和头节点。bottom[theBin] 指向箱
//子theBin 的尾节点,而top[theBin] 指向箱子 theBin 的首节点。所有箱子开始为空表,这时
//bottom[theBin]=NULL。
chain<T>& binSort(int range);
//根据 棋牌的组号 样式 面值排序
chain<T>& binSort(int range,int (*func)(chainNode<T>*));
//例 6-1 假定对0 ~ 999 之间的 10 个整数进行排序。如果使用 range=1000 的箱子排序方
//法,那么箱子链表的初始化需要 1000 个执行步,节点分配需要 10 个执行步,从箱子中收集
//节点需要 1000 个执行步,总的执行步数为 2010。而基数排序方法是:
//1 ) 利用箱子排序方法,根据最低位数字 ( 即个位数字 ),对 10 个数进行排序。因为每个
//数字都在0 ~ 9之间,所以range=10。图 6-9a 是 10 个数的输入链表,图 6-9b 是按最低位数
//字排序后的链表。
//216->521->425->116->91->515->124->34->96->24 //a输入链表
//521->91->124->34->24->425->515->216->116->96 //b按照最后一位数字进行排序
//515->216->116->521->124->24->425->34->91->96 //c按照第二位数字进行排序
//24->34->91->96->116->124->216->425->515->521 //d按照最高位进行排序
//2 ) 利用箱子排序方法, 对 1 ) 的结果按次低位数字 ( 即十位数字 ) 进行排序。同样有
//range=10。因为箱子排序是稳定排序,所以次低位数字相同的节点,按最低位数字排序所得
//到的次序保持不变。因此,现在的链表是按照最后两位数字进行排序的。图 6-9c 是相应的排
//序结果
//3 ) 利用箱子排序方法,对 2 ) 的结果按第三位数字 ( 即百位数字 ) 进行排序。小于 100
//的数,第三位数字为 0。因为按第三位数字排序是稳定排序, 所以第三位数字相同的节点,
//按最后两位数字排序所得到的次序保持不变。因此,现在的链表是按照后三位数字进行排序
//的。图 6-9d 是相应的排序结果。
//上述基数排序方法是以 10 为基数,把数分解为十进制数字进行排序。因为每个数至少有
//三位数字,所以要进行三次排序,每次排序都使用 range=10 个箱子排序。每次箱子的初始化
//需要 10 个执行步,节点分配需要 10 个执行步,从箱子中收集节点需要 10 个执行步,总的执
//行步数为 90,比使用 range=1000 的箱子排序要少得多。单个箱子排序 (一数一个箱子的 ) 实
//际上等价于 一1000 的基数排序。
//64. 设计一个方法,它应用基数排序思想给链表排序。
//1 ) 编写方法 chain<T>::radixSort(cd),它使用基数排序思想,按递增顺序给链表排序。方
//法的输入为 : 基数 ”、按基数”分解的数字的个数d。假设定义了从类型T到 int 的类
//型转换。方法的复杂度应为 O(d(r+n))。证明这个复杂度成立。
//2 ) 使用自己设计的测试数据来测试方法的正确性。
//3 ) 比较你的方法和基于链表的插入排序方法的性能。
//为此可使用m=100, 1000, 10 000;r=10 和 d=3。
chain<T>& radixSort(int r,int d);
public:
class iterator
{
public:
//向前迭代器所需要的上typedef语句
typedef forward_iterator_tag iterator_capacity;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
//构造函数
iterator(chainNode<T>* theNode = NULL)
{
node = theNode;
}
//解引用操作符
T& operator*() const { return node->element; }
T* operator->() const { return &node->element; }
//迭代器加法操作 不能operator--
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:
chainNode<T>* node;
};
iterator begin(){ return iterator(firstNode);}
iterator end(){return iterator(NULL);}
protected:
//如果索引无效,抛出异常
void checkIndex(int theIndex) const;
//指向链表第一个节点的指针
chainNode<T>* firstNode;
chainNode<T>* lastNode;
//线性表的元素个数
int listSize;
};
//构造函数和复制构造函数
/*
与数组描述的线
性表不同,链表在创建时不需要估计元素的最大个数以分配初始空间。不过,构造函数还是
具有一个表示初始容量的形参 initialCapacity,目的是与类 arrayList 相容。尤其在应用中,可
能需要一个类型为 linearList 的数组,对数组成员的初始化将会用到如下所示的每一种形式的
构造函数。
linearList<int>* list[10];
list[0] = new arrayList<int>(20);
list[1] = new arrayList<int>();
list[2] = new chain<int>(5);
list[3] = new chain<int>;
*/
//链表的构造函数和复制构造函数
template<class T>
chain<T>::chain(int initialCapacity)
{
//构造函数
if(initialCapacity < 1)
{
ostringstream s;
s<<"Initial capacity = "<<initialCapacity<<" must be >0";
throw logic_error(s.str());
}
//为了创建一个空链表,只需令第一个节点指针 firstNode 的值为NULL。
firstNode = NULL;
listSize = 0;
lastNode = 0;
}
template<class T>
chain<T>::chain(const chain<T>& theList)
{
// 复制构造函数
listSize = theList.listSize;
if(listSize == 0)
{
//如果theList 为空创建空链表
firstNode = NULL;
return;
}
//链表 theList 为非空
//要复制链表 theList 的节点
chainNode<T>* sourceNode = theList.firstNode;
//复制链表 theList 的首元素
firstNode = new chainNode<T>(sourceNode->element);
//sourceNode 指向下一个节点
sourceNode = sourceNode->next;
//当前链表 *this 的最后一个节点
chainNode<T>* targetNode = firstNode;
while(sourceNode != NULL)
{
//复制剩余元素
targetNode->next = new chainNode<T>(sourceNode->element);
targetNode = targetNode->next;
sourceNode = sourceNode->next;
}
//链表结束
targetNode->next = NULL;
}
//析构函数
/*
析构函数要逐个清除链表的节点。实现的策略是重复清除链表的首元素节点,
直到链表为空。注意,我们必须在清除首元素节点之前用变量nextNode
保存第 2 个元素节点的指针。析构函数的时间复杂度是 O(listSize)。
*/
//链表的析构函数
template<class T>
chain<T>::~chain()
{
// 链表析构函数 .删除链表的所有节点
while(firstNode != NULL)
{
//保存下一个元素节点的指针
chainNode<T>* nextNode = firstNode->next;
//删除当前节点
delete firstNode;
//指向下一个节点
firstNode = nextNode;
}
lastNode = NULL;
}
//get方法
/*
在数组描述的线性表中,我们根据公式来计算一个表元素的位置。然而在链表中,要寻
找索引为 theIndex 的元素,必须从第一个节点开始,跟踪链域 next 直至找到所需的元素节点
指针,也就是说,必须跟踪 theIndex 个指针。不可能对 firstNode 套用公式来计算所需节点的
位置。其中的方法 checkIndex 与在 arrayList 中定义的一样。方
法 get 的时间复杂度在链表 chain 中为 O(theIndex),而在数组描述的线性表 arrayList 中是
*/
//get方法的返回值是索引为 thelndex 的元素
template<class T>
T& chain<T>::get(int theIndex) const
{
//返回索引为 theIndex 的元素
//若该元素不存在,则抛出异常
checkIndex(theIndex);
//开始时当前节点指向链表的第一个节点
chainNode<T>* currentNode = firstNode;
//依次寻找到下标为theIndex的节点 theIndex 是从0开始
for(int i = 0; i < theIndex && currentNode; i++)
{
currentNode = currentNode->next;
}
return currentNode->element;
}
//indexOf方法
/*
它与 arrayList<T>::indexOf 的代码不同
主要体现在从一个元素寻找下一个相邻元素的方式上面数组描述的线性表中
在链表描述的线性表中,唯一的方法是用当前节点的指针确定下一个相邻节点的位置。
返回元素 theElement 首次出现时的索引
*/
template<class T>
int chain<T>::indexOf(const T& theElement) const
{
//返回元素 theElement 首次出现时的索引
//该元素不存在,则返回 -1
//搜索链表寻找元素 theELement
chainNode<T>* currentNode = firstNode;
// 当前节点的索引
int index = 0;
while(currentNode != NULL &&
currentNode->element != theElement)
{
//移向下一个节点
currentNode = currentNode->next;
index++;
}
//确定是否找到所需的元素
if(currentNode == NULL)
return -1;
else
return index;
}
//erase方法
/*
它删除索引为 theIndex 的元素
需要考虑三种情况:
1.theIndex<0 或者 theIndex > listSize。这时,删除操作无效,
因为没有这个位置上的元素。这种情况可能表示链表为空。
2.删除非空表的第 0 个元素节点。
3.删除其他元素节点。
*/
template<class T>
void chain<T>::erase(int theIndex)
{
//删除索引为 theIndex 的元素
//该元素不存在,则抛出异常
checkIndex(theIndex);
//索引有效,需找要删除的元素节点
chainNode<T>* deleteNode;
if(theIndex == 0)
{
//删除链表的首节点
deleteNode = firstNode;
firstNode = firstNode->next;
}
else
{
//用指针P指向要删除节点的前驱节点
chainNode<T>*p = firstNode;
for(int i = 0; i < theIndex - 1;i++)
p = p->next;
deleteNode = p->next;
if(theIndex == listSize - 1)
{
p->next = nullptr;
lastNode = p;
}
else
{
//删除 deleteNode 指向的节点
p->next = p->next->next;
}
}
listSize--;
delete deleteNode;
}
//insert方法
/*
插入和删除的过程很相似。为了在链表中索引为theIndex的位置上插入一个新元素,需
要首先找到索引为 theIndex-1 的元素节点,然后在该节点之后插人新元素节点。
*/
template<class T>
void chain<T>::insert(int theIndex,const T& theElement)
{
// 在索引为 theIndex 的位置上插入元素 theElement
//如果theIndex = listSize是在链表尾插入元素
//如果theIndex = 0是在链表头插入元素
if(theIndex < 0 || theIndex > listSize)
{
//无效索引
ostringstream s;
s<<"index = "<<theIndex <<" size = "<<listSize;
throw logic_error(s.str());
}
if(theIndex == 0)
{
//在链表头插入
firstNode = new chainNode<T>(theElement,firstNode);
if(listSize == theIndex)
{
lastNode = firstNode;
}
}
else
{
//寻找新元素的前驱
chainNode<T>* p = firstNode;
//寻找到下标为theIndex-1的位置,就是第theIndex个节点
for(int i = 0;i < theIndex - 1;i++)
p = p->next;
//在P之后插入
p->next = new chainNode<T>(theElement,p->next);
if(theIndex == listSize-1)
{
lastNode = p->next->next;
}
}
listSize++;
}
//输出链表
/*
既是对输出方法 output 的实现,又是对流插入符 << 的重载。
chain<T>::output与arrayList<T>::output 不同,
主要在于它从一个节点向另一个节点移动时使用了指针 next。
不过,两者的时间复杂度一样,都是 O(listSize)。
*/
template<class T>
void chain<T>::output(ostream& out) const
{
//把链表放入输出流
for(chainNode<T>* currentNode = firstNode;
currentNode != NULL;
currentNode = currentNode->next)
{
out<<currentNode->element<<" ";
}
}
template<class T>
ostream& operator<<(ostream& out, const chain<T>& x)
{
x.output(out);
return out;
}
template<class T>
void chain<T>::clear()
{
//删除链表的所有节点
while(firstNode != NULL)
{
//删除节点 firstNode
chainNode<T>* nextNode = firstNode->next;
delete firstNode;
firstNode = nextNode;
}
listSize = 0;
};
template<class T>
void chain<T>::push_back(const T& theElement)
{
//在链表尾端插入元素 rheELement 的节点
chainNode<T>* newNode = new chainNode<T>(theElement,NULL);
if(firstNode == NULL)
{
//链表为空
firstNode = lastNode = newNode;
}
else
{
//把新元素节点附加到 lastNode 指向的节点
lastNode->next = newNode;
lastNode = newNode;
}
listSize++;
}
template<class T>
void chain<T>::checkIndex(int theIndex) const
{
if(theIndex < 0 || theIndex >= listSize)
{
ostringstream s;
s << "index = " << theIndex << " size = " << listSize;
throw logic_error(s.str());
}
}
//ex2.大小小于 theSize,则不增加元素。若初始线性表的大小大于 theSize,则删除多余的元素。
//计算方法的复杂度。测试你的代码。
template<class T>
void chain<T>::setSize(int theSize)
{
if(listSize == 0 || theSize >= listSize)
{
cout<<"listSize == 0 || theSize >= listSize";
return;
}
chainNode<T>* currentNode = firstNode;
for(int i = 0; i < theSize-1; i++)
{
currentNode = currentNode->next;
}
chainNode<T>* prev = currentNode;
if(theSize == 0)
{
firstNode = nullptr;
}
else
{
currentNode = currentNode->next;
lastNode = prev;
prev->next = nullptr;
}
for(int i = theSize; i < listSize-1;i++)
{
prev = currentNode;
currentNode = currentNode->next;
delete prev;
}
listSize = theSize;
}
//ex3. 编写方法 chain<T>::set(theIndex,theElement),它用元素 theElement 替换索引为 thelndex 的
//元素。若索引 theIndex 超出范围,则抛出异常。计算方法的复杂度。测试你的代码。
template<class T>
void chain<T>::set(int theIndex,const T& theElement)
{
checkIndex(theIndex);
if(theIndex == 0)
{
firstNode->element = theElement;
return;
}
chainNode<T>* currentNode = firstNode;
for(int i = 0; i < theIndex; i++)
{
currentNode = currentNode->next;
}
currentNode->element = theElement;
}
//ex4. 编写方法 chain<T>::removeRange(fromIndex,toIndex),它删除指定索引范围内的所有元素。
//计算方法的复杂度。测试你的代码。
template<class T>
void chain<T>::removeRange(int fromIndex,int toIndex)
{
checkIndex(fromIndex);
checkIndex(toIndex);
if(toIndex < fromIndex)
{
return;
}
chainNode<T>* currentNode = firstNode;
//获取删除节点的前一个节点
for(int i = 1;i < fromIndex;i++)
{
currentNode = currentNode->next;
}
chainNode<T>* preDeleteNode = currentNode;
if(toIndex == listSize - 1)
{
lastNode = currentNode;
}
for(int i = fromIndex;i < toIndex; i++)
{
if(fromIndex == 0)
{
firstNode = currentNode->next;
delete currentNode;
currentNode = firstNode;
}
else
{
currentNode = preDeleteNode->next;
preDeleteNode->next= currentNode->next;
delete currentNode;
}
}
listSize = listSize - (toIndex - fromIndex);
}
//ex5. 编写方法 chain<T>::lastIndexOf(theElemen),返回值是指定元素最后出现时的索引。若这
//样的元素不存在,则返回 -1。计算方法的复杂度。测试你的代码。
template<class T>
int chain<T>::lastIndexOf(const T& theElement) const
{
if(listSize < 1) return -1;
int index = -1;
chainNode<T>* currentNode = firstNode;
for(int i = 0;i < listSize; i++)
{
if(currentNode->element == theElement)
{
index = i;
}
currentNode = currentNode->next;
}
return index;
}
//ex6. 重载操作符 [] ,使得表达式 x[i] 返回对链表 x 的第 i 个元素的引用。若链表没有第 i 个元素,
//则抛出异常。语句 x[i] = y 和y=x[i]按以往预期的方式执行。测试你的代码。
template<class T>
chainNode<T>& chain<T>::operator[](int theIndex)
{
checkIndex(theIndex);
chainNode<T>* currentNode = firstNode;
if(theIndex == 0)
{
return *currentNode;
}
for(int i = 0;i < theIndex;i++)
{
currentNode = currentNode->next;
}
return *currentNode;
}
//ex7. 重载操作符 ==,使得表达式 x==y 返回 rue,当且仅当两个链表 x 和y 相等,即对所有的
//i,两个链表的第 i 个元素相等。测试你的代码。
template<class T>
bool chain<T>::operator==(const chain<T>& right) const
{
if(listSize == 0 && right.listSize == 0)
return true;
if(listSize != right.listSize)
return false;
chainNode<T>* currentNode1 = firstNode;
chainNode<T>* currentNode2 = right.firstNode;
for(int i = 0;i < listSize;i++)
{
if(currentNode1->element != currentNode2->element)
return false;
currentNode1 = currentNode1->next;
currentNode2 = currentNode2->next;
}
return true;
}
//ex8. 重载操作符 !=,使得表达式 x!=y 返回 true,当且仅当两个链表 x 和y 不等 ( 见练习7 )。测
//试你的代码。
template<class T>
bool chain<T>::operator!=(const chain<T>& right) const
{
return !(*this == right);
}
//ex9 重载操作符 <,使得表达式 x<y 返回 true,当且仅当链表 x 按字典顺序小于链表 y( 见练习
//7)。测试你的代码。
template<class T>
bool chain<T>::operator<(const chain<T>& right) const
{
if(listSize == 0 && right.listSize > 0) return true;
if(listSize > 0 && right.listSize == 0) return false;
int small = listSize <= right.listSize ? listSize : right.listSize;
chainNode<T>* cur1 = firstNode;
chainNode<T>* cur2 = right.firstNode;
for (int i = 0; i < small; i++){
if(cur1->element < cur2->element) return true;
if (cur1->element > cur2->element) return false;
cur1 = cur1->next;
cur2 = cur2->next;
}
if(cur2 != nullptr) return true;
return false;
}
//ex10. 编写方法 chain<T>::swap(theChain),它交换链表元素 *this 和 theChain。计算方法的复杂
//度。测试你的代码。
template<class T>
void chain<T>::swap(chain<T>& right)
{
std::swap(firstNode,right.firstNode);
std::swap(lastNode,right.lastNode);
std::swap(listSize,right.listSize);
}
//ex14. 1 ) 编写方法 chain<T>::leftShiftt),它将表中的元素向左移动个位置。如果 1=[0,1,2,3,4] ,
//那么 leftShift(2) 的结果是 1=[2,3,4]。
//2 ) 计算方法的复杂度。
//3 ) 测试你的代码。
template<class T>
void chain<T>::leftShift(int i)
{
if(i < 0 || i>listSize)
{
ostringstream s;
s<<"i < 0 || i>listSize";
throw logic_error(s.str());
}
if(int i = 0)
{
return;
}
chainNode<T>* currentNode = firstNode;
for(int j = 0;j < i; j++)
{
firstNode = currentNode->next;
delete currentNode;
currentNode = firstNode;
listSize--;
}
}
//ex15. 1 ) 编写方法 chain<T>::reverse,它颠倒 *this 中的元素的顺序,而且原地完成,不用分配
//任何新的节点空间。
//2 ) 计算方法的复杂度。
//3 ) 使用自己的测试数据检验方法的正确性。
template<class T>
void chain<T>::reverse()
{
if(listSize <= 0) return ;
chainNode<T>* currentNode = firstNode->next;
chainNode<T>* nextNode = currentNode->next;
firstNode->next = nullptr;
lastNode = firstNode;
while(nextNode)
{
currentNode->next = firstNode;
firstNode = currentNode;
currentNode = nextNode;
nextNode = nextNode->next;
}
currentNode->next = firstNode;
firstNode = currentNode;
}
//ex17
//1 ) 编写一个非成员方法 meld,它生成一个新的扩展的链表 c,它从 a 的首元素开始,交
//替地包含a 和 b的元素。如果一个链表的元素取完了,就把另一个链表的剩余元素附
//加到新的扩展链表 c 中。方法的复杂度应与链表 a 和 的长度具有线性关系。
//2 ) 证明方法具有线性复杂度。
//3 ) 使用自己的测试数据检验方法的正确性。
template<class T>
chain<T>& chain<T>::meld1(const chain<T>& a, const chain<T>& b)
{
if(a.listSize == 0 && b.listSize == 0)
{
return *this;
}
chainNode<T>* currentNodeA = a.firstNode;
chainNode<T>* currentNodeB = b.firstNode;
firstNode = new chainNode<T>(currentNodeA->element);
chainNode<T>* currentNode = firstNode;
currentNodeA = currentNodeA->next;
while(currentNodeA && currentNodeB)
{
currentNode->next = new chainNode<T>(currentNodeA->element);
currentNode = currentNode->next;
currentNodeA = currentNodeA->next;
currentNode->next = new chainNode<T>(currentNodeB->element);
currentNode = currentNode->next;
currentNodeB = currentNodeB->next;
}
while(currentNodeA)
{
currentNode->next = new chainNode<T>(currentNodeA->element);
currentNode = currentNode->next;
if(!currentNodeA->next)
{
currentNode->next = nullptr;
lastNode = currentNode;
}
currentNodeA = currentNodeA->next;
}
while(currentNodeB)
{
currentNode->next = new chainNode<T>(currentNodeB->element);
currentNode = currentNode->next;
if(!currentNodeB->next)
{
currentNode->next = nullptr;
lastNode = currentNode;
}
currentNodeB = currentNodeB->next;
}
listSize = a.listSize+b.listSize;
return *this;
}
//ex18. 编写方法 chain<T>::meld。它与练习 17 的方法 meld类似。然而,a 和b 以及合并结果,
//都是 chain<T> 类型。合并后的链表使用的应该是链表 a 和 的节点空间。合并之后,输
//链表a 和b 是空表。
//1 ) 编写方法 meld,其复杂度应该与输入链表的长度具有线性关系。
//2 ) 证明方法具有线性复杂度。
//3 ) 测试代码的正确性。使用自己的测试数据。
template<class T>
chain<T>& chain<T>::meld2(chain<T>& a, chain<T>& b)
{
if(a.listSize == 0 && b.listSize == 0)
{
return *this;
}
chainNode<T>* currentNodeA = a.firstNode;
chainNode<T>* currentNodeB = b.firstNode;
firstNode = currentNodeA;
chainNode<T>* currentNode = firstNode;
currentNodeA = currentNodeA->next;
while(currentNodeA && currentNodeB)
{
currentNode->next = currentNodeA;
currentNode = currentNode->next;
currentNodeA = currentNodeA->next;
currentNode->next = currentNodeB;
currentNode = currentNode->next;
currentNodeB = currentNodeB->next;
}
while(currentNodeA)
{
currentNode->next = currentNodeA;
currentNode = currentNode->next;
if(!currentNodeA->next)
{
currentNode->next = nullptr;
lastNode = currentNode;
}
currentNodeA = currentNodeA->next;
}
while(currentNodeB)
{
currentNode->next = currentNodeB;
currentNode = currentNode->next;
if(!currentNodeB->next)
{
currentNode->next = nullptr;
lastNode = currentNode;
}
currentNodeB = currentNodeB->next;
}
listSize = a.listSize+b.listSize;
a.firstNode = b.firstNode = nullptr;
a.lastNode = b.lastNode = nullptr;
a.listSize = b.listSize = 0;
return *this;
}
//ex19.
//1 ) 编写一个非成员方法 merge,它生成一个新的有序链表 c,包含a 和 b的所有元素。
//2 ) 计算方法的复杂度。
//3 ) 使用自己的测试数据检验方法的正确性。
template<class T>
chain<T>& chain<T>::merge1(chain<T>& a, chain<T>& b)
{
chainNode<T>* currentNodeA = a.firstNode;
chainNode<T>* currentNodeB = b.firstNode;
chainNode<T>* currentNodeC = firstNode;
while(currentNodeA || currentNodeB)
{
if(currentNodeA == nullptr ||
currentNodeB != nullptr &&
currentNodeA->element > currentNodeB->element)
{
if(!firstNode)
{
firstNode = new chainNode<T>(currentNodeB->element);
currentNodeC = firstNode;
}
else
{
currentNodeC->next = currentNodeB;
currentNodeC = new chainNode<T>(currentNodeB->element);;
}
currentNodeB = currentNodeB->next;
}
else if(currentNodeB == nullptr ||
currentNodeA != nullptr &&
currentNodeA->element <= currentNodeB->element)
{
if(!firstNode)
{
firstNode = new chainNode<T>(currentNodeA->element);;
currentNodeC = firstNode;
}
else
{
currentNodeC->next = currentNodeA;
currentNodeC = new chainNode<T>(currentNodeA->element);;
}
currentNodeA = currentNodeA->next;
}
lastNode = currentNodeC;
listSize = a.listSize + b.listSize;
a.firstNode = b.firstNode = nullptr;
a.lastNode = b.lastNode = nullptr;
a.listSize = b.listSize = 0;
return *this;
}
}
//ex20. 重做练习 19,但是编写的是方法 chain<T>::merge。归并之后,两个输入链表a 和 为空
template<class T>
chain<T>& chain<T>::merge2(chain<T>& a, chain<T>& b)
{
chainNode<T>* currentNodeA = a.firstNode;
chainNode<T>* currentNodeB = b.firstNode;
chainNode<T>* currentNodeC = firstNode;
while(currentNodeA || currentNodeB)
{
if(currentNodeA == nullptr ||
currentNodeB != nullptr &&
currentNodeA->element > currentNodeB->element)
{
if(!firstNode)
{
firstNode = currentNodeB;
currentNodeC = firstNode;
}
else
{
currentNodeC->next = currentNodeB;
currentNodeC = currentNodeB;
}
currentNodeB = currentNodeB->next;
}
else if(currentNodeB == nullptr ||
currentNodeA != nullptr &&
currentNodeA->element <= currentNodeB->element)
{
if(!firstNode)
{
firstNode = currentNodeA;
currentNodeC = firstNode;
}
else
{
currentNodeC->next = currentNodeA;
currentNodeC = currentNodeA;
}
currentNodeA = currentNodeA->next;
}
lastNode = currentNodeC;
listSize = a.listSize + b.listSize;
a.firstNode = b.firstNode = nullptr;
a.lastNode = b.lastNode = nullptr;
a.listSize = b.listSize = 0;
return *this;
}
}
//ex22. 编写方法 chain<T>::split,它与练习 21 的函数类似。然而,它用输入链表 *this 的空间建
//立了链表a和b。
template<class T>
chain<T>& chain<T>::split(chain<T>& a, chain<T>& b)
{
chainNode<T>* currentNode = firstNode;
chainNode<T>* next = nullptr;
chainNode<T>* currentNodeA = nullptr;
chainNode<T>* currentNodeB = nullptr;
for(int i = 0; i<listSize && currentNode;++i)
{
next = currentNode->next;
if(i % 2 == 0)
{
if(i == 0)
{
a.firstNode = currentNode;
currentNodeA = currentNode;
}
else
{
currentNodeA->next = currentNode;
currentNodeA = currentNode;
currentNodeA->next = nullptr;
}
a.listSize++;
}
else
{
if(i == 1)
{
b.firstNode = currentNode;
currentNodeB = currentNode;
}
else
{
currentNodeB->next = currentNode;
currentNodeB = currentNode;
currentNodeB->next = nullptr;
}
b.listSize++;
}
currentNode = next;
}
firstNode = nullptr;
listSize = 0;
return *this;
}
//ex23. 在一个循环移动的操作中,线性表的元素根据给定的值,按顺时针方向移动。例如
//L=[0,1,2,3,4],循环移动 2 的结果是 L=[2,3,4,0,1]。
//1 ) 编写方法 circularShift(i),它将线性表的元素循环移动i 个位置。
//2 ) 测试你的代码。
template<class T>
chain<T>& chain<T>::circularShift(int index)
{
if(listSize <= 1)
return *this;
for(int i = 0;i < index;i++)
{
lastNode->next = firstNode;
lastNode = firstNode;
firstNode = firstNode->next;
lastNode->next = nullptr;
}
return *this;
}
//ex26. 编写方法 chain<T>::insertSort,它使用插入排序 ( 见程序 2-15 ) 对链表按非递减顺序重新排序。
//不开发新的节点,也不删除老的节点。可以假设元素的类型定义了关系操作符 (<、> 等)。
//1 ) 方法在最坏情况下的复杂度是多少? 如果元素已经有序,那么该方法需要多少时间?
//2 ) 使用自己的测试数据检验方法的正确性。
template<class T>
chain<T>& chain<T>::insertionSort()
{
int len = listSize;
if(len <= 1) return *this;
for(int i = 2;i<=len;++i)
{
//寻找要插入的元素
chainNode<T>* Elem = firstNode;
chainNode<T>* ElemPre = nullptr;
for(int j = 1;j < i;++j)
{
ElemPre = Elem;
Elem = Elem->next;
}
//找到之前已经排序好的队列里第一个比要插入元素大的位置
chainNode<T>* insertPos = firstNode;
chainNode<T>* insertPrePos = nullptr;
for(int j = 1;j < i && insertPos->element < Elem->element;++j)
{
insertPrePos = insertPos;
insertPos = insertPos->next;
}
//把值Elem插入到currentMaxPreNode 和 insertPos
//如果当前要插入元素是要插入的位置则跳过
if(insertPos == Elem)
continue;
//如果要插入的元素是首节点
if(!ElemPre)
firstNode = Elem->next;
else
{
ElemPre->next = Elem->next;
if(Elem == lastNode)
{
lastNode = ElemPre;
ElemPre->next = nullptr;
}
}
//如果要插的位置首节点的位置
if(!insertPrePos)
firstNode = Elem;
else
{
insertPrePos->next = Elem;
}
Elem->next = insertPos;
}
return *this;
}
template<class T>
chain<T>& chain<T>::bubbleSort()
{
int len = listSize;
if(len <= 1) return *this;
//循环扫描链表len-1次如果前面的元素大于后面元素进行交换
for(int i = len; i >= 2;--i)
{
chainNode<T>* currentPreNode = nullptr;
chainNode<T>* currentNode = firstNode;
chainNode<T>* currentNextNode = currentNode->next;
while(currentNextNode)
{
if(currentNode->element > currentNextNode->element)
{
if(!currentPreNode)
firstNode = currentNextNode;
else
currentPreNode->next = currentNextNode;
currentNode->next = currentNextNode->next;
currentNextNode->next = currentNode;
}
currentPreNode = currentNode;
currentNode = currentNextNode;
currentNextNode = currentNode->next;
}
lastNode = currentNode;
}
return *this;
}
template<class T>
chain<T>& chain<T>::selectionSort()
{
int len = listSize;
if(len <= 1) return *this;
for(int i = len;i >= 2;--i)
{
chainNode<T>* currentPreNode = firstNode;
chainNode<T>* currentNode = firstNode->next;
chainNode<T>* maxNode = currentPreNode;
chainNode<T>* maxPreNode = nullptr;
//寻找最大值
for(int j = 2; j <= i;++j)
{
if(currentNode->element > maxNode->element)
{
maxNode = currentNode;
maxPreNode = currentPreNode;
}
currentPreNode = currentNode;
currentNode = currentNode->next;
}
if(currentPreNode == maxNode) continue;
if(!maxPreNode)
firstNode = maxNode->next;
else
maxPreNode->next = maxNode->next;
currentPreNode->next = maxNode;
maxNode->next = currentNode;
if(i == len)
{
lastNode = maxNode;
lastNode->next = nullptr;
}
}
return *this;
}
// void rank(int rank[]);
// chain<T>& rankSort();
//每个箱子都以底部节点作为首节点,项部节点作为尾节点。每个箱子都有两个指
//针,分别存储在数组 bottom 和top 中,分别指向尾节点和头节点。bottom[theBin] 指向箱
//子theBin 的尾节点,而top[theBin] 指向箱子 theBin 的首节点。所有箱子开始为空表,这时
//bottom[theBin]=NULL。
template<class T>
chain<T>& chain<T>::binSort(int range)
{
//对链表中的节点排序
//创建并初始化箱子
chainNode<T> **bottom,**top;
bottom = new chainNode<T>* [range + 1];
top = new chainNode<T>* [range + 1];
for(int b = 0; b <= range; b++)
{
bottom[b] = NULL;
}
//把链表的节点分配到箱子
//for 循环把输入链表的节点逐个插人相应的箱子顶
for(;firstNode != NULL; firstNode = firstNode->next)
{
//把首节点 firstNode 加到箱子中
//元素类型转换到整型 int
int theBin = firstNode->element;
//箱子为空
if(bottom[theBin] == NULL)
{
bottom[theBin] = top[theBin] = firstNode;
}
else
{
//箱子不空
top[theBin]->next = firstNode;
top[theBin] = firstNode;
}
}
//把箱子中的节点收集到有序链表
// for 循环从第 0 个箱子开始,把非空的箱子依次链接起来,形成一个有序链表。
chainNode<T> *y = NULL;
for(int theBin = 0; theBin <= range; theBin++)
{
if(bottom[theBin] != NULL)
{
//箱子不空
//第一个非空箱子
if(y == NULL)
{
firstNode = bottom[theBin];
}
else //不是第一个非空箱子
{
y->next = bottom[theBin];
}
y = top[theBin];
}
if(y != NULL)
{
y->next = NULL;
}
}
delete[] bottom;
delete[] top;
return *this;
}
//根据 棋牌的组号 样式 面值排序
template<class T>
chain<T>& chain<T>::binSort(int range,int (*func)(chainNode<T>*))
{
//对链表中的节点排序
//创建并初始化箱子
chainNode<T> **bottom,**top;
bottom = new chainNode<T>* [range + 1];
top = new chainNode<T>* [range + 1];
for(int b = 0; b <= range; b++)
{
bottom[b] = NULL;
}
//把链表的节点分配到箱子
//for 循环把输入链表的节点逐个插人相应的箱子顶
for(;firstNode != NULL; firstNode = firstNode->next)
{
//把首节点 firstNode 加到箱子中
//元素类型转换到整型 int
int theBin;
if(!func)
{
theBin = firstNode->element;
}
else
{
//根据 组号 样式 面值排序
theBin = func(firstNode);
}
//箱子为空
if(bottom[theBin] == NULL)
{
bottom[theBin] = top[theBin] = firstNode;
}
else
{
//箱子不空
top[theBin]->next = firstNode;
top[theBin] = firstNode;
}
}
//把箱子中的节点收集到有序链表
// for 循环从第 0 个箱子开始,把非空的箱子依次链接起来,形成一个有序链表。
chainNode<T> *y = NULL;
for(int theBin = 0; theBin <= range; theBin++)
{
if(bottom[theBin] != NULL)
{
//箱子不空
//第一个非空箱子
if(y == NULL)
{
firstNode = bottom[theBin];
}
else //不是第一个非空箱子
{
y->next = bottom[theBin];
}
y = top[theBin];
}
if(y != NULL)
{
y->next = NULL;
}
}
delete[] bottom;
delete[] top;
return *this;
}
//例 6-1 假定对0 ~ 999 之间的 10 个整数进行排序。如果使用 range=1000 的箱子排序方
//法,那么箱子链表的初始化需要 1000 个执行步,节点分配需要 10 个执行步,从箱子中收集
//节点需要 1000 个执行步,总的执行步数为 2010。而基数排序方法是:
//1 ) 利用箱子排序方法,根据最低位数字 ( 即个位数字 ),对 10 个数进行排序。因为每个
//数字都在0 ~ 9之间,所以range=10。图 6-9a 是 10 个数的输入链表,图 6-9b 是按最低位数
//字排序后的链表。
//216->521->425->116->91->515->124->34->96->24 //a输入链表
//521->91->124->34->24->425->515->216->116->96 //b按照最后一位数字进行排序
//515->216->116->521->124->24->425->34->91->96 //c按照第二位数字进行排序
//24->34->91->96->116->124->216->425->515->521 //d按照最高位进行排序
//2 ) 利用箱子排序方法, 对 1 ) 的结果按次低位数字 ( 即十位数字 ) 进行排序。同样有
//range=10。因为箱子排序是稳定排序,所以次低位数字相同的节点,按最低位数字排序所得
//到的次序保持不变。因此,现在的链表是按照最后两位数字进行排序的。图 6-9c 是相应的排
//序结果
//3 ) 利用箱子排序方法,对 2 ) 的结果按第三位数字 ( 即百位数字 ) 进行排序。小于 100
//的数,第三位数字为 0。因为按第三位数字排序是稳定排序, 所以第三位数字相同的节点,
//按最后两位数字排序所得到的次序保持不变。因此,现在的链表是按照后三位数字进行排序
//的。图 6-9d 是相应的排序结果。
//上述基数排序方法是以 10 为基数,把数分解为十进制数字进行排序。因为每个数至少有
//三位数字,所以要进行三次排序,每次排序都使用 range=10 个箱子排序。每次箱子的初始化
//需要 10 个执行步,节点分配需要 10 个执行步,从箱子中收集节点需要 10 个执行步,总的执
//行步数为 90,比使用 range=1000 的箱子排序要少得多。单个箱子排序 (一数一个箱子的 ) 实
//际上等价于 一1000 的基数排序。
//64. 设计一个方法,它应用基数排序思想给链表排序。
//1 ) 编写方法 chain<T>::radixSort(cd),它使用基数排序思想,按递增顺序给链表排序。方
//法的输入为 : 基数r、按基数r分解的数字的个数d。假设定义了从类型T到int的类
//型转换。方法的复杂度应为 O(d(r+n))。证明这个复杂度成立。
//2 ) 使用自己设计的测试数据来测试方法的正确性。
//3 ) 比较你的方法和基于链表的插入排序方法的性能。
//为此可使用m=100, 1000, 10 000;r=10 和 d=3。
template<class T>
chain<T>& chain<T>::radixSort(int r,int d)
{
//基数r、按基数r分解的数字的个数d。
//假设定义了从类型T到int的类型转换。
chainNode<T>** bottom = nullptr;
chainNode<T>** top = nullptr;
bottom = new chainNode<T>* [r + 1];
top = new chainNode<T>* [r + 1];
for(int i = 0; i < d; i++)
{
for(int j = 0; j <= r; j++)
{
bottom[j] = nullptr;
}
while(firstNode)
{
int num = firstNode->element;
for(int k = 0;k < i;k++)
num /= r;
num %= r;
if(bottom[num] == nullptr)
{
bottom[num] = top[num] = firstNode;
}
else
{
top[num]->next = firstNode;
top[num] = firstNode;
}
firstNode = firstNode->next;
}
chainNode<T>* end = nullptr;
for(int j = 0; j <= r; j++)
{
if(bottom[j] == nullptr)
continue;
if(end == nullptr)
{
firstNode = bottom[j];
}
else
{
end->next = bottom[j];
}
end = top[j];
}
if(end != nullptr)
{
end->next = nullptr;
}
}
delete[] bottom;
delete[] top;
return *this;
}
//当用链表描述栈时,我们必须确定用链表的哪一端表示栈顶。若用链表的右端作为栈项,
//则栈操作top 、push和pop的实现需要调用链表方法get(size()-1) 、insert(size(),theElement)和
//erase(size(0)-1)。每一个链表方法需要用时O(size())。而用链表的左端作为栈顶,需要调用的
//链表方法是 get(0)、insert(0,theElement) 和 erase(0),甚中每一个链表方法需要用时 O(1)。分
//析表明,我们应该选择链表的左端作为栈项。
//类 derivedLinkedStack
//类 derivedLinkedStack 从 chain派生,实现了抽象类 stack,其代码可
//以从 derivedArrayStack 的代码得到,但是要用分句 private chain<T> 替代
//Private arrayList<T>,用名称 derivedLinkedStack 替代名称 derivedArrayStack,将方法 get、
//insert 和 erase 的调用中作为索引的实参改为0,使这些操作发生在链表的左端。这样做有什
//么好处? 因为使用了面向对象设计中信息隐藏和封装的原理,所以大大简化了程序的设计。
//derivedLinkedStack 的每一种方法 (包括构造函数和 push 方法 ) 的时间复杂度都为 O(1)。
template<class T>
class stack
{
public:
virtual ~stack(){}
virtual bool empty() const = 0;
virtual int size() const = 0;
virtual T& top() = 0;
virtual void pop() = 0;
virtual void push(const T& theElement) = 0;
};
template<class T>
class derivedLinkedStack : public chain<T>,public virtual stack<T>
{
public:
derivedLinkedStack<T>() : chain<T>::chain(){}
virtual bool empty() const override{ return chain<T>::empty(); }
virtual int size() const override{ return chain<T>::size(); }
virtual T& top() override
{
if(empty())
{
throw logic_error("out of bounds");
}
return chain<T>::get(0);
}
virtual void pop() override
{
if(empty())
{
throw logic_error("out of band");
}
chain<T>::erase(0);
}
virtual void push(const T& theElement) override
{
chain<T>::insert(0,theElement);
}
};
//类linkedStack
//就像类 arrayStack一样,我们可以定制代码而不是从类 chain 派生,由此
//改进代码的时间性能。程序便是这样的定制代码。
//定制链表栈
template<class T>
class linkedStack : public stack<T>
{
public:
linkedStack(int initialCapacity = 10)
{
stackTop = NULL;
stackSize = 0;
}
~linkedStack();
bool empty() const
{
return stackSize == 0;
}
int size() const
{
return stackSize;
}
T& top()
{
if(stackSize == 0)
throw logic_error("stack empty");
return stackTop->element;
}
void pop();
void push(const T& theElement)
{
stackTop = new chainNode<T>(theElement,stackTop);
stackSize++;
}
//ex12.在某些栈应用中,要插入的元素已经存储在类型为
//chainNode 的节点中。对此,需要方法
//pushNode(chainNode* theNode) 把节点theNode压和入栈,
//还需要方法popNode把栈顶节点删除并返回。
//1 ) 编写这两个方法的代码。
//2 ) 测试代码。
//3 ) 比较 pushNode 和 popNode的10000000
//操作序列与push和pop的10000000操作序列的性能。
void pushNode(chainNode<T>* theNode)
{
theNode->next = stackTop;
stackTop = theNode;
++stackSize;
}
chainNode<T>* popNode()
{
if(stackSize == 0)
throw logic_error("out of bound");
chainNode<T>* temp = stackTop;
stackTop = stackTop->next;
return temp;
}
chainNode<T>* stackTop; //栈顶指针
private:
int stackSize; //栈中元素个数
};
template<class T>
class extendedStack : public virtual stack<T>
{
public:
virtual istream& input(istream& in) = 0;
virtual string toString() const = 0;
virtual void split(extendedStack<T>& st1,extendedStack<T>& st2) const = 0;
virtual void merge(extendedStack<T>& st2) = 0;
};
//13. 设计具体类 extendedLinkedStack,它派生于类 linkedStack 和抽象类 extendedStack
template <class T>
class extendedLinkedStack : public linkedStack<T>, public extendedStack<T>
{
template<class U>
friend istream& operator>>(istream& in, extendedLinkedStack<U>& st);
template<class U>
friend ostream& operator<<(ostream& out, const extendedLinkedStack<U>& st);
public:
extendedLinkedStack<T>() : linkedStack<T>()
{
}
virtual bool empty() const override
{
return linkedStack<T>::empty();
}
virtual int size() const override
{
return linkedStack<T>::size();
}
virtual T& top() override
{
return linkedStack<T>::top();
}
virtual void push(const T& theElement) override
{
linkedStack<T>::push(theElement);
}
virtual void pop() override
{
linkedStack<T>::pop();
}
virtual istream& input(std::istream& in) override;
virtual string toString() const override;
virtual void split(extendedStack<T>& st1, extendedStack<T>& st2) const override;
virtual void merge(extendedStack<T>& st2) override;
ostream& output(ostream& out) const
{
out<<toString();
return out;
}
};
template<class T>
istream& extendedLinkedStack<T>::input(istream& in)
{
T t;
while(in >> t)
{
push(t);
}
return in;
}
template<class U>
istream& operator>>(istream& in, extendedLinkedStack<U>& st)
{
st.input(in);
return in;
}
template<class U>
ostream& operator<<(ostream& out,const extendedLinkedStack<U>& st)
{
st.output(out);
return out;
}
template<class T>
string extendedLinkedStack<T>::toString() const
{
std::string s = "";
chainNode<T>* node = linkedStack<T>::stackTop;
while(node)
{
s = std::to_string(node->element) + " " + s;
node = node->next;
}
return s;
}
template<class T>
void extendedLinkedStack<T>::split(extendedStack<T>& st1,extendedStack<T>& st2) const
{
auto& st1_t = dynamic_cast<extendedLinkedStack<T>&>(st1);
auto& st2_t = dynamic_cast<extendedLinkedStack<T>&>(st2);
std::string s = toString();
std::istringstream iss(s);
int i = 0;
T t;
for(;i < size() / 2; i++)
{
iss>>t;
st1_t.push(t);
}
for(;i < size(); i++)
{
iss>>t;
st2_t.push(t);
}
}
template<class T>
void extendedLinkedStack<T>::merge(extendedStack<T>& st2)
{
auto & st_t = dynamic_cast<extendedLinkedStack<T>&>(st2);
string s = st_t.toString();
std::istringstream iss(s);
T t;
for(int i = 0; i < st_t.size();i++)
{
iss>>t;
push(t);
}
}
template<class T>
ostream& operator<<(ostream& out, const extendedLinkedStack<T>& st);
template<class T>
linkedStack<T>::~linkedStack()
{
//析构函数
while(stackTop != NULL)
{
//删除栈顶节点
chainNode<T>* nextNode = stackTop->next;
delete stackTop;
stackTop = nextNode;
}
}
template <class T>
void linkedStack<T>::pop()
{
//删除栈顶节点
if(stackSize == 0)
throw logic_error("stack empty");
chainNode<T>* nextNode = stackTop->next;
delete stackTop;
stackTop = nextNode;
stackSize--;
}
int main()
{
derivedLinkedStack<double> stack1;
for(int i = 0; i < 10; i++)
{
stack1.push(i);
}
cout<<stack1.size()<<endl;
for(int i = 0; i < 10; i++)
{
cout<<stack1.top()<<" ";
stack1.pop();
}
cout<<endl;
linkedStack<double> stack2;
for(int i = 0; i < 10; i++)
{
stack2.push(i);
}
cout<<stack2.size()<<endl;
for(int i = 0; i < 10; i++)
{
cout<<stack2.top()<<" ";
stack2.pop();
}
cout<<endl;
extendedLinkedStack<int> exStack1,exStack2,exStack3;
for(int i = 0; i < 10; i++)
{
exStack1.push(i*2+1);
exStack2.push(i*2);
}
for(int i = 0; i < 10; i++)
{
cout<<exStack1.top()<<" ";
exStack1.pop();
}
cout<<endl;
for(int i = 0; i < 10; i++)
{
cout<<exStack2.top()<<" ";
exStack2.pop();
}
for(int i = 0; i < 10; i++)
{
exStack1.push(i*2+1);
exStack2.push(i*2);
}
exStack1.merge(exStack2);
cout<<endl;
for(int i = 0; i < 20; i++)
{
cout<<exStack1.top()<<" ";
exStack1.pop();
}
cout<<endl;
return 0;
}
测试输出
xz@xiaqiu:~/study/algorithm/c++/1/build$ ./test
10
9 8 7 6 5 4 3 2 1 0
10
9 8 7 6 5 4 3 2 1 0
19 17 15 13 11 9 7 5 3 1
18 16 14 12 10 8 6 4 2 0
18 16 14 12 10 8 6 4 2 0 19 17 15 13 11 9 7 5 3 1
xz@xiaqiu:~/study/algorithm/c++/1/build$