chain.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();
//链表的成员类 iterator
/*
在单向链表中,使用指针 next,我们能很快地从一个节点找到它的后继。但是我们
不能从一个节点很快地找到它的前驱。因为对单向链表,只能定义一个向前和叠代器。而对
arrayList 类我们定义了一个双向迭代器很容易就能从任何一个元素移到它的后继和前驱,
*/
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;
//删除 deleteNode 指向的节点
p->next = p->next->next;
if(p->next->next == NULL)
{
lastNode = p->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 = currentPreNode->next;
chainNode<T>* maxNode = currentNode;
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;
}
return *this;
}
// void rank(int rank[]);
// chain<T>& rankSort();
int main()
{
cout<<"----------------------size start--------------------"<<endl;
chain<double> list1;
cout<<list1.size()<<endl;
cout<<"----------------------size end--------------------"<<endl;
cout<<"----------------------insert start--------------------"<<endl;
for(int i = 0;i < 10;i++)
{
list1.insert(0,i);
}
cout<<list1.size()<<endl;
cout<<list1<<endl;
cout<<"----------------------insert end--------------------"<<endl;
cout<<"----------------------get start--------------------"<<endl;
for(int i = 0;i < 10;i++)
{
cout<<list1.get(i)<<" ";
}
cout<<endl;
cout<<"----------------------get end--------------------"<<endl;
cout<<"----------------------erase start--------------------"<<endl;
cout<<list1<<endl;
cout<<list1.size()<<endl;
for(int i = 0;i < 6;i++)
{
list1.erase(0);
}
cout<<list1<<endl;
cout<<list1.size()<<endl;
cout<<"----------------------erase end--------------------"<<endl;
cout<<"----------------------push_back start--------------------"<<endl;
cout<<list1<<endl;
for(int i = 0;i < 10;i++)
{
list1.insert(3,i);
}
cout<<list1<<endl;
cout<<list1.size()<<endl;
for(int i = 0;i < 3;i++)
{
list1.push_back(1000);
}
cout<<list1<<endl;
cout<<list1.size()<<endl;
cout<<"----------------------push_back end--------------------"<<endl;
cout<<"----------------------iterator start--------------------"<<endl;
chain<double>::iterator iter;
for(iter = list1.begin();iter != list1.end();iter++)
{
cout<<*iter<<" ";
}
cout<<endl;
cout<<"----------------------iterator end--------------------"<<endl;
cout<<"----------------------setSize start--------------------"<<endl;
cout<<list1<<endl;
cout<<list1.size()<<endl;
list1.setSize(2);
cout<<list1<<endl;
cout<<list1.size()<<endl;
cout<<"----------------------setSize end--------------------"<<endl;
cout<<"----------------------set start--------------------"<<endl;
for(int i = 0;i < 5;i++)
{
list1.push_back(i);
}
cout<<list1<<endl;
cout<<list1.size()<<endl;
list1.set(2,10000);
cout<<list1.get(2)<<endl;
cout<<list1<<endl;
cout<<list1.size()<<endl;
cout<<"----------------------set end--------------------"<<endl;
cout<<"----------------------removeRange start--------------------"<<endl;
cout<<list1.size()<<endl;
cout<<list1<<endl;
list1.removeRange(2,5);
cout<<list1<<endl;
cout<<list1.size()<<endl;
cout<<"lastNode = "<<list1.getLastNode()<<endl;
cout<<"----------------------removeRange end--------------------"<<endl;
cout<<"----------------------lastIndexOf start--------------------"<<endl;
cout<<list1.size()<<endl;
cout<<list1<<endl;
cout<<list1.lastIndexOf(3)<<endl;
cout<<list1.size()<<endl;
cout<<list1<<endl;
cout<<"----------------------lastIndexOf end--------------------"<<endl;
cout<<"----------------------operator[] start--------------------"<<endl;
cout<<list1<<endl;
cout<<list1.size()<<endl;
for(int i = 0;i < list1.size();i++)
{
cout<<list1[i].element<<" ";
}
cout<<endl;
cout<<list1.size()<<endl;
cout<<list1[0].element<<" ";
cout<<list1[1].element<<" ";
cout<<list1[2].element<<" ";
cout<<list1[3].element<<" ";
cout<<endl;
for(int i = 0;i < list1.size();i++)
{
list1[i].element = i;
}
cout<<list1<<endl;
cout<<"----------------------operator[] end--------------------"<<endl;
cout<<"----------------------operator== start--------------------"<<endl;
chain<double> list2;
for(int i = 0;i < 4;i++)
{
list2.push_back(i);
}
cout<<list2<<endl;
cout<<(list2==list1)<<endl;
cout<<"----------------------operator== end--------------------"<<endl;
cout<<"----------------------operator!= start--------------------"<<endl;
cout<<(list2!=list1)<<endl;
cout<<"----------------------operator!= end--------------------"<<endl;
cout<<"----------------------leftShift start--------------------"<<endl;
cout<<list1<<endl;
list1.leftShift(2);
cout<<list1<<endl;
cout<<"----------------------leftShift end--------------------"<<endl;
cout<<"----------------------reverse start--------------------"<<endl;
cout<<list2<<endl;
cout<<list2.getLastNode()<<endl;
list2.reverse();
cout<<list2<<endl;
cout<<list2.getLastNode()<<endl;
cout<<"----------------------reverse end--------------------"<<endl;
cout<<"----------------------meld1 start--------------------"<<endl;
cout<<list1<<endl;
cout<<list2<<endl;
chain<double> list3;
list3.meld1(list1,list2);
cout<<list3<<endl;
cout<<list3.getLastNode()<<endl;
cout<<list3.size()<<endl;
cout<<"----------------------meld1 end--------------------"<<endl;
cout<<"----------------------meld2 start--------------------"<<endl;
cout<<list1<<endl;
cout<<list2<<endl;
chain<double> list4;
list4.meld2(list1,list2);
cout<<list1<<endl;
cout<<list2<<endl;
cout<<list4<<endl;
cout<<list4.getLastNode()<<endl;
cout<<list4.size()<<endl;
cout<<"----------------------meld2 end--------------------"<<endl;
cout<<"----------------------split start--------------------"<<endl;
cout<<list1<<endl;
cout<<list2<<endl;
cout<<list4<<endl;
list4.split(list1,list2);
cout<<list1<<endl;
cout<<list2<<endl;
cout<<list4<<endl;
cout<<"----------------------split end--------------------"<<endl;
cout<<"----------------------circularShift start--------------------"<<endl;
for(int i = 0;i < 10;i++)
{
list4.push_back(i);
}
cout<<list4<<endl;
list4.circularShift(4);
cout<<list4<<endl;
cout<<"----------------------circularShift end--------------------"<<endl;
cout<<"----------------------insertionSort start--------------------"<<endl;
cout<<list4<<endl;
cout<<list4.size()<<endl;
list4.insertionSort();
cout<<list4.size()<<endl;
cout<<list4<<endl;
cout<<"----------------------bubbleSort start--------------------"<<endl;
list4.circularShift(4);
cout<<list4.size()<<endl;
cout<<list4<<endl;
list4.bubbleSort();
cout<<list4<<endl;
cout<<"----------------------bubbleSort end--------------------"<<endl;
cout<<"----------------------selectionSort start--------------------"<<endl;
list4.circularShift(4);
cout<<list4.size()<<endl;
cout<<list4<<endl;
list4.selectionSort();
cout<<list4<<endl;
cout<<list4.getLastNode();
cout<<"----------------------selectionSort end--------------------"<<endl;
return 0;
}
测试输出
xz@xiaqiu:~/study/algorithm/c++/1/build$ ./test
----------------------size start--------------------
0
----------------------size end--------------------
----------------------insert start--------------------
10
9 8 7 6 5 4 3 2 1 0
----------------------insert end--------------------
----------------------get start--------------------
9 8 7 6 5 4 3 2 1 0
----------------------get end--------------------
----------------------erase start--------------------
9 8 7 6 5 4 3 2 1 0
10
3 2 1 0
4
----------------------erase end--------------------
----------------------push_back start--------------------
3 2 1 0
3 2 1 9 8 7 6 5 4 3 2 1 0 0
14
3 2 1 9 8 7 6 5 4 3 2 1 0 0 1000 1000 1000
17
----------------------push_back end--------------------
----------------------iterator start--------------------
3 2 1 9 8 7 6 5 4 3 2 1 0 0 1000 1000 1000
----------------------iterator end--------------------
----------------------setSize start--------------------
3 2 1 9 8 7 6 5 4 3 2 1 0 0 1000 1000 1000
17
3 2
2
----------------------setSize end--------------------
----------------------set start--------------------
3 2 0 1 2 3 4
7
10000
3 2 10000 1 2 3 4
7
----------------------set end--------------------
----------------------removeRange start--------------------
7
3 2 10000 1 2 3 4
3 2 3 4
4
lastNode = 4
----------------------removeRange end--------------------
----------------------lastIndexOf start--------------------
4
3 2 3 4
2
4
3 2 3 4
----------------------lastIndexOf end--------------------
----------------------operator[] start--------------------
3 2 3 4
4
3 2 3 4
4
3 2 3 4
0 1 2 3
----------------------operator[] end--------------------
----------------------operator== start--------------------
0 1 2 3
1
----------------------operator== end--------------------
----------------------operator!= start--------------------
0
----------------------operator!= end--------------------
----------------------leftShift start--------------------
0 1 2 3
2 3
----------------------leftShift end--------------------
----------------------reverse start--------------------
0 1 2 3
3
3 2 1 0
0
----------------------reverse end--------------------
----------------------meld1 start--------------------
2 3
3 2 1 0
2 3 3 2 1 0
0
6
----------------------meld1 end--------------------
----------------------meld2 start--------------------
2 3
3 2 1 0
2 3 3 2 1 0
0
6
----------------------meld2 end--------------------
----------------------split start--------------------
2 3 3 2 1 0
2 3 1
3 2 0
----------------------split end--------------------
----------------------circularShift start--------------------
0 1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 0 1 2 3
----------------------circularShift end--------------------
----------------------insertionSort start--------------------
4 5 6 7 8 9 0 1 2 3
10
10
0 1 2 3 4 5 6 7 8 9
----------------------bubbleSort start--------------------
10
4 5 6 7 8 9 0 1 2 3
0 1 2 3 4 5 6 7 8 9
----------------------bubbleSort end--------------------
----------------------selectionSort start--------------------
10
4 5 6 7 8 9 0 1 2 3
0 1 2 3 5 6 7 8 9
3----------------------selectionSort end--------------------
xz@xiaqiu:~/study/algorithm/c++/1/build$