数据结构算法与应用-C++语言描述 stack数组的实现

//栈
//定义和应用
//定义8-1 栈(stack) 是一种特殊的线性表,其插入(也称入栈或压栈)和删除(也称出栈或弹栈)操作都在表的同一端进行。这一端称为栈顶(top),另一端称为栈底(bottom),图给出了一个4个元素的栈。假定要在的栈中插入一个元素E,这个元素删除E之后的结果是图如果对栈连续执行三次删除操作,结果从上面的讨论可以看出,栈是一个后进先出表。这种类型的表在计算过程中将频繁使用。


				E<-top
D<-top	        D
C               C
B               B              B<-top
A<-bottom       A<-bottom      A<-bottom

#include <iostream>
#include <sstream>
#include <algorithm>
#include <iterator>

//数据结构算法与应用-C++语言描述 stack数组的实现

using namespace std;
//线性表一数组

//抽象数据类型
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;
};

//改变一个一维数组长度
template<class T>
void changeLength1D(T *&a, int oldLength, int newLength)
{
    if (newLength < 0)
        throw logic_error("new length must be >= 0");

    //新数组
    T *temp = new T[newLength];

    //需要复制的元素个数
    int number = min(oldLength, newLength);
    copy(a, a + number, temp);

    //释放老数组的内存空间
    delete [] a;
    a = temp;
}



//arrayList 的类定义
template<class T>
class arrayList : public linearList<T>
{
public:
    //构造函数,复制构造函数和析构函数
    arrayList(int initialCapacity = 10);
    arrayList(const arrayList<T> &);
    ~arrayList() {delete[] element;}

    //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;

    //其他方法
    int capacity() const { return arrayLength; }

    //ex5. 编写一个方法 arrayList<T>::trimToSize,它使数组的长度等于 max{listSize,1}。
    //这个方法的复杂度是多少?” 测试你的代码。
    arrayList<T>& trimToSize();

    //ex6. 编写方法 arrayList<T>::setSize,它使线性表的大小等于指定的大小。若线性表开始的大小
    //小于指定的大小,则不增加元素。若线性表开始的大小大于指定的大小,则删除多余的元
    //素。这个方法的复杂度是多少? 测试你的代码。
    arrayList<T>& setSize(int length);

	//ex7. 重载操作符[],使得表达式 x加返回对线性表第i个元素的引用。
	//若线性表没有第i个元则抛出异常语句 x[i]=y 和 y= x[i]] 按以往预期的方式执行。
	//测试你的代码。
    T& operator[](int i);

    //ex8. 重载操作符 ==,使得表达式 x==y 返回 true,当上且仅当两个用数组描述的线性表x 
    //和y 相等(即对所有的 i,两个线性表的第i 个元素相等 )。测试你的代码。
    bool operator==(const arrayList<T>& right) const;

    //ex9.
    bool operator!=(const arrayList<T>& right) const;

    //ex10. 重载操作符 <,使得表达式 x<y 返回 true,当且仅当用数组描述的线性表 x 按字典顺序小
    //于用数组描述的线性表v ( 见练习 8 )。测试你的代码。
    bool operator<(const arrayList<T>& right) const;

    //ex11. 编写方法 arrayList<T>::push_back,它把元素 theElement 插到线性表的右端。不要利用
    //insert 方法。方法的时间复杂度是多少?测试你的代码。
    void push_back(const T& theElement);

    //ex12. 编写方法 arrayList<T>::pop_back,它把线性表右端的元素删除。不要利用 erase 方法。方
    //法的时间复杂度是多少? 测试你的代码。
	T& pop_back();    

	//ex13. 编写方法 arrayList<T>::swap(theLisb,它交换线性表的元素 *this 和 theList。方法的时间
	//复杂度是多少? 测试你的代码。
	arrayList<T>& swap(arrayList<T>& theList);

	//ex14. 编写方法 arrayList<T>::reserve(theCapacity),它把数组的容量改变为当前容量和 theCapacity
	//的较大者。测试你的代码。
	arrayList<T>& reserve(int theCapacity);

	//ex15. 编写方法 arrayList<T>::set(theIndex,theElement),它用元素 theElement 替换索引为 theIndex
	//的元素。若索引 theIndex 超出范围,则抛出异常。返回原来索引为 theIndex 的元素。测试
	//你的代码。
	T set(int theIndex, const T& theElement);

	//ex16. 编写方法 arrayList<T>::clear,它使线性表为空。方法的复杂度是多少?” 测试你的代码。
	arrayList<T>& clear();

	//ex17. 编写方法 arrayList<T>::removeRange,它删除指定索引范围内的所有元素。方法的复杂度
	//是多少?测试你的代码。 
	arrayList<T>& removeRange(int startIndex,int endIndex);

	//ex18. 编写方法 arrayList<T>::lastInexOf,它的返回值是指定元素最后出现时的索引。如果这样
	//的元素不存在,则返回 -1。方法的复杂度是多少? 测试你的代码。
	int lastIndexOf(const T& theElement) const;

	//ex20. 类 arrayList ( 程序 5-1 ) 的缺点是,它不减少数组 element 的长度。
	//1: 编写类 arrayList 的一个新版本。如果在删除之后,线性表的大小降至 arrayLength/4 以
	//	下,就创建一个新的数组,长度为 max{arrayLength/2,initialCapacity}。然后将老表
	//	中的元素复制到新表。
	//2 ( 选择性练习 ) 从空表开始,考察大小为地的线性表的操作序列。假设当初始容量等于
	//	或超过线性表大小的最大值时,总的执行步数是f(n)。证明,如果起始容量为1,而且
	//	在插入和删除操作中,可以按照上面和 5.3 节所述的方式改变数组长度,那么执行步
	//	数最多为 cf(n),其中 c 是某个常数。
	arrayList<T>& decreaseArray(int capacity);

	///ex33. 1 ) 编写方法 arrayList<T>::reverse,它原地颠倒线性表元素的顺序 ( 即在数组 element 中
	//		完成操作,不创建新的数组 )。颠倒顺序之前,线性表的第 k 个元素是 element[k],站
	//		倒之后,线性表的第 k 个元素是 element[listSize-k-1]。不要利用 STL 函数 reverse。
	//		2 ) 方法应具有 listSize 的线性复杂度。证明这个性能。
	//		3 ) 设计测试数据,测试方法的正确性。
	//		4 ) 编写另一个原地颠倒 arrayList 对象的方法。它不是 arrayList 的成员函数,不能访问
	//		arrayList 的数据成员。不过,这个方法可以调用 arrayList 的成员函数。
	//		5 ) 计算方法的复杂度
	//		6 ) 使用大小分别为 1000、5000 和 10 000 的线性表,比较两个颠倒顺序算法的运行时间
	arrayList<T>& reverse();

	//ex23.1) 编写方法 arrayList<T>::leftShift(i),它将线性表的元素向左移动i个位置。如果
	//		x=[0,1,2,3,4],那么 x.leftShift(2) 的结果是 x=[2,3,4]。
	//		2 ) 计算方法的复杂度。
	//		3 ) 测试你的代码-
	arrayList<T>& leftShift(int shift);

	//ex24. 在一个循环移动的操作中,线性表的元素根据给定的值,按顺时针方向移动。例如,
	//x=[0,1,2,3,4],循环移动 2 的结果是 x=[2,3,4,0,1]。
	//		1 ) 描述一下如何利用 3 次逆转操作完成循环移动。每一次逆转操作都可以将线性表的一
	//		部分或全部逆转。
	//		2 ) 编写方法 arrayList<T>::circularShiftt),它将线性表的元素循环移动i个位置。方法应
	//		具有线性表长度的线性复杂度。
	//		3 ) 测试你的代码。
	arrayList<T>& circularShift(int shift);

	//ex25. 调用语句 x.half,可以将 x 的元素隔一个删除一个。如果 xsize() 是 7, xelement[]=[2,13,4.5,17,8,29],
	//		那么 x.half() 的结果是 x.size() 是 4,x.element[]=[2,4.17,9]。如果 x.size() 是 4,x.element[]=[2,13,4.5],
	//		那么 x.half() 的结果是 x.size() 是 2,x.element[]=[2,4]。如果 x 为空,那么 x.half() 的结果也是X 为空。
	//		1 ) 编写方法 arrayList<T>::half()。不能利用类 arrayList 的其他方法。复杂度应该为O(listSize)
	//		2 ) 证明方法的复杂度为 O(listSize)。
	//		3 ) 测试你的代码。
	arrayList<T>& half();

	///ex34.令 a 和b 是类 arrayList 的两个对象。
	//		1 ) 编写方法 arrayList<T>::meld(ab),它生成一个新的线性表,从 a 的第 0 个元素开始,
	//		交替地包含a 和 b的元素。如果一个表的元素取完了,就把另一个表的剩余元素附加
	//		到新表中。调用语句 c.meld(a,b) 使 成为合并后的表。方法应具有两个输入线性表大
	//		小的线性复杂度。
	//		2 ) 证明方法具有 a 和b 大小之和的线性复杂度。
	//		3 ) 测试你的代码。

	arrayList<T>& meld(arrayList<T>& a, arrayList<T>& b);

	///ex35.令a 和b 是类 arrayList 的两个对象。假设它们的元素从左到右非递减有序。
	//		1 ) 编写方法 arrayList<T>::merge(a,b),它生成一个新的有序线性表,包含a 和 的所有元
	//		素。归并后的线性表是调用对象 *this。不要利用 STL 本数 merge。
	//		2 ) 计算方法的复杂度。
	//		3 ) 测试你的代码。
	arrayList<T>& merge(arrayList<T>& a, arrayList<T>& b);

	///ex36. 1 ) 编写方法 arrayList<T>::split(lab),它生成两个线性表a 和b。a 包含 *this 中索引为偶
	//		数的元素,b 包含其余的元素。
	//	  2 ) 计算方法的复杂度。
	//	  3 ) 测试你的代码。
	arrayList<T>& split(arrayList<T>& a, arrayList<T>& b);

	//ex31. 假设用公式 ( 5-3 ) 来表示线性表。分别用变量 first 和 last 表示线性表首元素和尾元素的
	//		位置。
	//		1 ) 开发一个类 circularArrayList,它与 arrayList 类似。实现所有的方法。在删除和插人方
	//		法中,对位于删除或插和人元素的左面或右面的元素,有选择地决定向左移动或向右移
	//		动,以此提高方法的性能。
	//		2 ) 计算每一个方法的复杂度。
	//		3 ) 测试你的代码。


public:
	class iterator
	{
	public:
		// C++ 的typedef 语句实现双向迁代器
		typedef bidirectional_iterator_tag iterator_category;
		typedef T value_type;
		typedef ptrdiff_t difference_type;
		typedef T* pointer;
		typedef T& reference;

		//构造函数
		iterator(T* thePosition = 0){ position = thePosition; }

		//解引用操作符
		T& operator*() const{ return *position; }
		T* operator->() const{ return &*position; }
		

		//迭代器的值增加	
		iterator& operator++() //前加
		{
			++position;
			return *this;
		}
		iterator operator++(int) //后加
		{
			iterator old = *this;
			++position;
			return old;
		}

		//迭代器的值减少
		iterator& operator--() //前减
		{
			--position;
			return *this;
		}

		iterator operator--(int) //后减
		{
			iterator old = *this;
			--position;
			return old;
		}

		//测试是否相等
		bool operator!=(const iterator right) const
		{
			return position != right.position;
		}

		bool operator==(const iterator right) const
		{
			return position == right.position;
		}
		//27. 扩展迭代器类 arrayList::iterator ( 程序 5-11 ),使得它成为随机访问迭代器。利用 STL 的
		//	  排序函数对一个线性表排序,以测试这个和迭代器类。
		T& operator[](int i)
		{ 
			return *(position + i);
		}

		ptrdiff_t operator-(const arrayList<T>::iterator & right) const
		{
			return position - right.position;
		}

		T& operator-(const ptrdiff_t & diff) const
		{
			return *(position - diff);
		}

		T& operator+(const ptrdiff_t & diff) const
		{
			return *(position + diff);
		}

	protected:
		T* position; //指向表元素的指针
	};

	iterator begin(){ return iterator(element); }
	iterator end(){ return iterator(element+listSize); }

protected:
	//索引 theIndex 无效,则抛出异常
	void checkIndex(int theIndex) const;
	//扩容
	void increaseArray(int capacity);

	//存储线性表元素的一维数组
	T* element = NULL; 
	//一维数组的容量
	int arrayLength = 0;
	//线性表的元素个数
	int listSize = 0;
	//初始容量
	int initialCapacity = 10;
};

//类 arrayList 的构造函数
template<class T>
arrayList<T>::arrayList(int initialCapacity)
{
	//构造函数
	if(initialCapacity < 1)
	{
		ostringstream s;
		s<<"Initial capacity = "<<initialCapacity<<" must be > 0";
		throw logic_error(s.str());
	}
	arrayLength = initialCapacity;
	initialCapacity = initialCapacity;
	element = new T[arrayLength];
	listSize = 0;
}

template<class T>
arrayList<T>::arrayList(const arrayList<T>& theList)
{
	//复制构造函数
	arrayLength = theList.arrayLength;
	listSize = theList.listSize;
	element = new T[arrayLength];
	//利用了 STL 的算法copy 
	copy(theList.element,theList.element + listSize,element);
}

//方法 checkIndex的时间复杂度是 (1), 
template<class T>
void arrayList<T>::checkIndex(int theIndex) const
{
	//确定索引theIndex在0 和 listSize - 1之间
	if(theIndex < 0 || theIndex >= listSize)
	{
		//字符串输出流对象
		ostringstream s;
		s<<"index = "<<theIndex<<" size = "<<listSize;
		throw logic_error(s.str());
	}
}

//方法 get的时间复杂度是 (1), 
template<class T>
T& arrayList<T>::get(int theIndex) const
{
	//返回索引为 theIndex 的元素
	//若此元素不存在,则抛出异常
	checkIndex(theIndex);
	return element[theIndex];
}

//indexOf 的时间复杂度是 O(max{listSize,1})
template<class T>
int arrayList<T>::indexOf(const T& theElement) const
{
	//返回元素 theElement 第一次出现时的索引
	//该元素不存在,则返回 -1
	//查找元素 theElement
	int theIndex = (int)(find(element,element+listSize,theElement) - element);
	//确定元素 theElement 是否找到
	if(theIndex == listSize)
	{
		//没有找到
		return -1;
	}
	else
	{
		return theIndex;
	}
}

/*
 删除一个元素为了从线性表中删除索引为 theIndex 的元素,
 首先要确定线性表包含这个元素,然后删除这个元素。
 若没有这个元素,则抛出类型为异常

 如果没有索引 theIndex 的元素,
 就抛出异常,erase 时间复杂度是 O(1)。如果有这个元素,
 那么要移动的元素个数是 listSize-theIndex
 时间复杂度是 O(listSize-theIndex) 
*/
template<class T>
void arrayList<T>::erase(int theIndex)
{
	//删除其索引为 theIndex 的元素
	//如果该元素不存在,则抛出异常
	checkIndex(theIndex);
	//有效索引,移动其索引大于 theIndex 的元素
	copy(element+theIndex+1,element+listSize,element+theIndex);
	//调用析构函数
	element[--listSize].~T();
}

/*
 插入一个元素
 要在线性表中索引为 theIndex 的位置上插和人一个新元素,
 首先把索引从 theIndex 到listSize-1的元素向右移动一个位置
 然后将新元素插人索引为 theIndex 的位置最后将变量listSize 的值增 1。
 向右移动元素的操作是利用 STL 函数 copy_backward 来完成的
 而没有利用 copy 函数该函数是从最右端的元素开始移动。
*/
template<class T>
void arrayList<T>::insert(int theIndex,const T& theElement)
{
	//在索引 theIndex 处插入元素 theElement
	//确定索引theIndex在0 和 listSize 之间
	if(theIndex < 0 || theIndex > listSize)
	{
		//字符串输出流对象
		ostringstream s;
		s<<"index = "<<theIndex<<" size = "<<listSize;
		throw logic_error(s.str());
	}

	//有效索引,确定数组是否已满
	if(listSize == arrayLength)
	{
		//数组空间已满,数组长度倍增
		changeLength1D(element,arrayLength,2*arrayLength);
		arrayLength *= 2;
	}

	//把元素向右移动一个位置
	copy_backward(element + theIndex,
				  element + listSize,
				  element + listSize + 1);

	element[theIndex] = theElement;
	listSize++;
}

//输出函数 output 和重载 <<
template<class T>
void arrayList<T>::output(ostream& out) const
{
	//把线性表插入输出流
	copy(element, element + listSize,ostream_iterator<T>(cout," "));
}

//重载 <<
template<class T>
ostream& operator<<(ostream& out,const arrayList<T>& x)
{
	x.output(out);
	return out;
}

//扩容
template<class T>
void arrayList<T>::increaseArray(int capacity)
{
	if(capacity <= arrayLength) 
	{
		cout<<"input capacity <= arrayLength";
		return;
	}

	changeLength1D(element,arrayLength,capacity);
	arrayLength = capacity;
}


//ex5. 编写一个方法 arrayList<T>::trimToSize,它使数组的长度等于 max{listSize,1}。
//这个方法的复杂度是多少?” 测试你的代码。
template<class T>
arrayList<T>& arrayList<T>::trimToSize()
{
	if(listSize == arrayLength) return *this;
	int oldLength = arrayLength;
	arrayLength = max(listSize,1);
	changeLength1D(element,oldLength,arrayLength);
	return *this;
}

//ex6. 编写方法 arrayList<T>::setSize,它使线性表的大小等于指定的大小。若线性表开始的大小
//小于指定的大小,则不增加元素。若线性表开始的大小大于指定的大小,则删除多余的元
//素。这个方法的复杂度是多少? 测试你的代码。
template<class T>
arrayList<T>& arrayList<T>::setSize(int length)
{
	if(length < 0 || length > listSize)
		return *this;
	listSize = length;
	return *this;
}

//ex7. 重载操作符[],使得表达式 x加返回对线性表第i个元素的引用。
//若线性表没有第i个元则抛出异常语句 x[i]=y 和 y= x[i] 按以往预期的方式执行。
//测试你的代码。
template<class T>
T& arrayList<T>::operator[](int i)
{
	checkIndex(i);
	return element[i];
}

//ex8. 重载操作符 ==,使得表达式 x==y 返回 true,当上且仅当两个用数组描述的线性表x 
//和y 相等(即对所有的 i,两个线性表的第i 个元素相等 )。测试你的代码。
template<class T>
bool arrayList<T>::operator==(const arrayList<T>& right) const
{
	if(right.listSize != listSize) return false;
	for(int i = 0;i < listSize;i++)
	{
		if(element[i] != right.element[i]) return false;
	}
	return true;
}

//ex9.
template<class T>
bool arrayList<T>::operator!=(const arrayList<T>& right) const
{
	if(*this == right) 
	{
		return false;
	}
	else
	{
		return true;
	}
}

//ex10. 重载操作符 <,使得表达式 x<y 返回 true,当且仅当用数组描述的线性表 x 按字典顺序小
//于用数组描述的线性表v ( 见练习 8 )。测试你的代码。
template<class T>
bool arrayList<T>::operator<(const arrayList<T>& right) const
{
	int minSize = min(size(),right.size());

	for(int i = 0;i<size();i++)
	{
		if(element[i] < right.element[i]) return true;
	}
	if(size() < right.size()) return true;
	return false;
}

//ex11. 编写方法 arrayList<T>::push_back,它把元素 theElement 插到线性表的右端。不要利用
//insert 方法。方法的时间复杂度是多少?测试你的代码。
template<class T>
void arrayList<T>::push_back(const T& theElement)
{
	if(arrayLength == listSize)
		increaseArray(2*arrayLength);
	element[listSize++] = theElement;
}

//ex12. 编写方法 arrayList<T>::pop_back,它把线性表右端的元素删除。不要利用 erase 方法。方
//法的时间复杂度是多少? 测试你的代码。
template<class T>
T& arrayList<T>::pop_back()
{
	if(listSize == 0) 
	{
		throw logic_error("arrayList is empty");
	}
	T& theElement = element[--listSize];

	if(listSize < arrayLength/4)
		decreaseArray(arrayLength/2);

	return theElement;
}    

//ex13. 编写方法 arrayList<T>::swap(theLisb,它交换线性表的元素 *this 和 theList。方法的时间
//复杂度是多少? 测试你的代码。
template<class T>
arrayList<T>& arrayList<T>::swap(arrayList<T>& theList)
{
	std::swap(listSize, theList.listSize);
	std::swap(arrayLength,theList.arrayLength);
	std::swap(element,theList.element);
	return *this;
}

//ex14. 编写方法 arrayList<T>::reserve(theCapacity),它把数组的容量改变为当前容量和 theCapacity
//的较大者。测试你的代码。
template<class T>
arrayList<T>& arrayList<T>::reserve(int theCapacity)
{
	if(theCapacity <= arrayLength) return *this;
	changeLength1D(element,arrayLength,theCapacity);
	arrayLength = theCapacity;	
	return *this;
}

//ex15. 编写方法 arrayList<T>::set(theIndex,theElement),它用元素 theElement 替换索引为 theIndex
//的元素。若索引 theIndex 超出范围,则抛出异常。返回原来索引为 theIndex 的元素。测试
//你的代码。
template<class T>
T arrayList<T>::set(int theIndex, const T& theElement)
{
	checkIndex(theIndex);
	T tmp = element[theIndex];
	element[theIndex] = theElement;
	return tmp;
}

//ex16. 编写方法 arrayList<T>::clear,它使线性表为空。方法的复杂度是多少?” 测试你的代码。
template<class T>
arrayList<T>& arrayList<T>::clear()
{
	for(int i = 0; i < size(); i++)
	{
		element[i].~T();
	}
	listSize = 0;
	decreaseArray(initialCapacity);
	arrayLength = initialCapacity;
	return *this;
}

//ex17. 编写方法 arrayList<T>::removeRange,它删除指定索引范围内的所有元素。方法的复杂度
//是多少?测试你的代码。 
template<class T>
arrayList<T>& arrayList<T>::removeRange(int startIndex,int endIndex)
{
	checkIndex(startIndex);
	checkIndex(endIndex);
	int count = endIndex - startIndex + 1;
	copy(element+endIndex, element+listSize, element+startIndex);

	for(int i = startIndex+count;i<listSize;i++)
		element[i].~T();

	listSize -= count;

	if(listSize < arrayLength/4)
	{
		decreaseArray(arrayLength/2);
	}	
	return *this;
}

//ex18. 编写方法 arrayList<T>::lastInexOf,它的返回值是指定元素最后出现时的索引。如果这样
//的元素不存在,则返回 -1。方法的复杂度是多少? 测试你的代码。
template<class T>
int arrayList<T>::lastIndexOf(const T& theElement) const
{
	for(int i = listSize - 1;i>=0;i--)
	{
		if(element[i] == theElement)
			return i;
	}
	return -1;
}


//ex20. 类 arrayList ( 程序 5-1 ) 的缺点是,它不减少数组 element 的长度。
//1: 编写类 arrayList 的一个新版本。如果在删除之后,线性表的大小降至 arrayLength/4 以
//	下,就创建一个新的数组,长度为 max{arrayLength/2,initialCapacity}。然后将老表
//	中的元素复制到新表。
//2 ( 选择性练习 ) 从空表开始,考察大小为地的线性表的操作序列。假设当初始容量等于
//	或超过线性表大小的最大值时,总的执行步数是f(n)。证明,如果起始容量为1,而且
//	在插入和删除操作中,可以按照上面和 5.3 节所述的方式改变数组长度,那么执行步
//	数最多为 cf(n),其中 c 是某个常数。
template<class T>
arrayList<T>& arrayList<T>::decreaseArray(int capacity)
{
	if(capacity >= arrayLength || capacity < 0)
	{
		return *this;
	}
	changeLength1D(element, arrayLength, capacity);
	arrayLength = capacity;
	return *this;	
}


///ex33. 1 ) 编写方法 arrayList<T>::reverse,它原地颠倒线性表元素的顺序 ( 即在数组 element 中
//		完成操作,不创建新的数组 )。颠倒顺序之前,线性表的第 k 个元素是 element[k],站
//		倒之后,线性表的第 k 个元素是 element[listSize-k-1]。不要利用 STL 函数 reverse。
//		2 ) 方法应具有 listSize 的线性复杂度。证明这个性能。
//		3 ) 设计测试数据,测试方法的正确性。
//		4 ) 编写另一个原地颠倒 arrayList 对象的方法。它不是 arrayList 的成员函数,不能访问
//		arrayList 的数据成员。不过,这个方法可以调用 arrayList 的成员函数。
//		5 ) 计算方法的复杂度
//		6 ) 使用大小分别为 1000、5000 和 10 000 的线性表,比较两个颠倒顺序算法的运行时间
template<class T>
arrayList<T>& arrayList<T>::reverse()
{
	for(int i = 0;i < listSize / 2; i++)
	{
		std::swap(element[i],element[listSize - i - 1]);
	}
	return *this;
}

//ex23.1) 编写方法 arrayList<T>::leftShift(i),它将线性表的元素向左移动i个位置。如果
//		x=[0,1,2,3,4],那么 x.leftShift(2) 的结果是 x=[2,3,4]。
//		2 ) 计算方法的复杂度。
//		3 ) 测试你的代码-
template<class T>
arrayList<T>& arrayList<T>::leftShift(int shift)
{
	if(shift < 0 || shift > listSize)
	{
		ostringstream s;
		s << "shift shift < 0 || shift > listSize";
		throw logic_error(s.str());
	}

	copy(element + shift,element + listSize, element);
	listSize -= shift;

	for (int i = listSize - shift; i < listSize; i++)
	{
		element[i].~T();
	}

	if (listSize < arrayLength / 4)
	{
		changeLength1D(element, arrayLength, arrayLength / 2);
	}

	return *this;
}

//ex24. 在一个循环移动的操作中,线性表的元素根据给定的值,按顺时针方向移动。例如,
//x=[0,1,2,3,4],循环移动 2 的结果是 x=[2,3,4,0,1]。
//		1 ) 描述一下如何利用 3 次逆转操作完成循环移动。每一次逆转操作都可以将线性表的一
//		部分或全部逆转。
//		2 ) 编写方法 arrayList<T>::circularShiftt),它将线性表的元素循环移动i个位置。方法应
//		具有线性表长度的线性复杂度。
//		3 ) 测试你的代码。
template<class T>
arrayList<T>& arrayList<T>::circularShift(int shift)
{
	if(shift < 0)
	{
		ostringstream s;
		s <<"circularShift shift < 0";
		throw logic_error(s.str());
	}

	shift %= listSize;

	reverse();
	std::reverse(element, element + listSize - shift);
	std::reverse(element + listSize - shift, element + listSize);
	return *this;
}

//ex25. 调用语句 x.half,可以将 x 的元素隔一个删除一个。如果 xsize() 是 7, xelement[]=[2,13,4.5,17,8,29],
//		那么 x.half() 的结果是 x.size() 是 4,x.element[]=[2,4.17,9]。如果 x.size() 是 4,x.element[]=[2,13,4.5],
//		那么 x.half() 的结果是 x.size() 是 2,x.element[]=[2,4]。如果 x 为空,那么 x.half() 的结果也是X 为空。
//		1 ) 编写方法 arrayList<T>::half()。不能利用类 arrayList 的其他方法。复杂度应该为O(listSize)
//		2 ) 证明方法的复杂度为 O(listSize)。
//		3 ) 测试你的代码。
template<class T>
arrayList<T>& arrayList<T>::half()
{
	if(listSize <= 1) return *this;

	for(int i = 1;i < (listSize + 1) / 2; i++)
	{
		element[i] = element[i*2];
	}

	int oldSize = listSize;
	listSize = (listSize + 1) / 2;

	for(int i = listSize; i < oldSize; i++)
	{
		element[i].~T();
	}

	if(listSize < arrayLength / 4)
	{
		changeLength1D(element, arrayLength, arrayLength / 2);
	}
	return *this;
}

///ex34.令 a 和b 是类 arrayList 的两个对象。
//		1 ) 编写方法 arrayList<T>::meld(ab),它生成一个新的线性表,从 a 的第 0 个元素开始,
//		交替地包含a 和 b的元素。如果一个表的元素取完了,就把另一个表的剩余元素附加
//		到新表中。调用语句 c.meld(a,b) 使 成为合并后的表。方法应具有两个输入线性表大
//		小的线性复杂度。
//		2 ) 证明方法具有 a 和b 大小之和的线性复杂度。
//		3 ) 测试你的代码。

template<class T>
arrayList<T>& arrayList<T>::meld(arrayList<T>& a, arrayList<T>& b)
{
	if(a.listSize == 0 && b.listSize == 0) return *this;
	int minSize = a.listSize < b.listSize ? a.listSize:b.listSize;
	int maxSize = a.listSize > b.listSize ? a.listSize:b.listSize;
	int newLength = a.listSize > b.listSize ? a.arrayLength : b.arrayLength;
	T* maxElement = a.listSize > b.listSize ? a.element:b.element;

	if(maxSize + minSize > arrayLength)
	{
		newLength = a.arrayLength + b.arrayLength;
	}
	increaseArray(newLength);
	listSize = maxSize + minSize;
	for(int i = 0;i<minSize;i++)
	{
		element[i*2] = a.element[i];
		element[i*2 + 1] = b.element[i];
	}
	copy(maxElement + minSize, maxElement + maxSize,element+2*minSize);
	return *this;
}

///ex35.令a 和b 是类 arrayList 的两个对象。假设它们的元素从左到右非递减有序。
//		1 ) 编写方法 arrayList<T>::merge(a,b),它生成一个新的有序线性表,包含a 和 的所有元
//		素。归并后的线性表是调用对象 *this。不要利用 STL 本数 merge。
//		2 ) 计算方法的复杂度。
//		3 ) 测试你的代码。
template<class T>
arrayList<T>& arrayList<T>::merge(arrayList<T>& a, arrayList<T>& b)
{
	if(a.listSize == 0 && b.listSize == 0) return *this;
	int minSize = a.listSize < b.listSize ? a.listSize:b.listSize;
	int maxSize = a.listSize > b.listSize ? a.listSize:b.listSize;
	int newLength = a.listSize > b.listSize ? a.arrayLength : b.arrayLength;
	T* maxElement = a.listSize > b.listSize ? a.element:b.element;
	if(minSize == 0) return *this;

	if(maxSize + minSize > arrayLength)
	{
		newLength = a.arrayLength + b.arrayLength;
	}
	listSize = maxSize + minSize;
	increaseArray(newLength);
	int index = 0,aindex = 0,bindex = 0;
	cout<<listSize<<endl;
	for(int i = 0;i<listSize;i++)
	{
		if(aindex < a.size() && bindex < b.size())
		{
			if(a.element[aindex]<=b.element[bindex])
				element[index] = a.element[aindex++];
			else
				element[index] = b.element[bindex++];
		}
		else
		{
			if(aindex < a.size() && bindex >= b.size())
				element[index] = a.element[aindex++];
			else if(aindex >= a.size() && bindex < b.size())
				element[index] = b.element[bindex++];
		}	
	}
	return *this;
}

//30. 1 ) 编写方法 arrayList<T>::split(lab),它生成两个线性表a 和b。a 包含 *this 中索引为偶
//		数的元素,b 包含其余的元素。
//	  2 ) 计算方法的复杂度。
//	  3 ) 测试你的代码。
template<class T>
arrayList<T>& arrayList<T>::split(arrayList<T>& a, arrayList<T>& b)
{
	if(listSize == 0) 
	{
		cout<<"listSize == empty";
		return *this;
	}

	a.increaseArray(listSize);
	b.increaseArray(listSize);

	int index,aindex = 0,bindex = 0;
	for(int i = 0;i < listSize; i++)
	{
		if(i % 2 == 0)
		{
			a.element[aindex++] = element[i];
		}
		else
		{
			b.element[bindex++] = element[i];
		}
	}
	a.listSize = (listSize + 1) / 2;
	b.listSize = listSize / 2;

	return *this;
}


template<class T>
class stack
{
public:
	virtual ~stack(){}
	//返回true ,当且仅当栈为空
	virtual bool empty() const = 0;
	//返回栈中元素个数
	virtual int size() const = 0;
	//返回栈顶元素的引用
	virtual T& top() = 0;
	//删除栈顶元素
	virtual void pop() = 0;
	//将元素 theElement 压入栈顶
	virtual void push(const T& theElement) = 0;
};

//从类 arrayList 和 stack 派生的类 derivedArrayStack。
//类 derivedArrayStack 的构造函数直接调用类 arrayList 的构造函数,动态创建一维数组,
//数组容量 ( 长度 ) 是参数 initialCapaticy 的值。initialCapaticy 的缺省值是 10。其他成员函数
//的代码也是直接调用基类的成员函数来实现的。
template <class T>
class derivedArrayStack : public arrayList<T>,
						  public stack<T>
{
public:
	derivedArrayStack(int initialCapacity = 10)
		:arrayList<T>(initialCapacity){}
	bool empty() const
	{
		return arrayList<T>::empty();
	}

	int size() const
	{
		return arrayList<T>::size();
	}

	//函数top和pop都在类方法get和erase之前检查栈是否为空
	//因为基类的方法get和erase在遇到空栈时将抛出异常
	//所以我们可以从top和pop中删除对空栈的检查
	//而不会影响程序结果。
	T& top()
	{
		if(arrayList<T>::empty())
			throw logic_error("空栈");
		return arrayList<T>::get(arrayList<T>::size() - 1);
	}

	void pop()
	{
		if(arrayList<T>::empty())
			throw logic_error("空栈");
		arrayList<T>::erase(arrayList<T>::size() - 1);
	}

	void push(const T& theElement)
	{
		arrayList<T>::insert(arrayList<T>::size(),theElement);
	}
};


//类 arrayStack
template<class T>
class arrayStack : public stack<T>
{
public:
	arrayStack(int initialCapacity = 10);
	~arrayStack(){delete [] stack;}
	bool empty() const {return stackTop == -1;}
	int size() const
	{
		return stackTop+1;
	}

	T& top()
	{
		if(stackTop == -1)
			throw logic_error("stack empty");
		return stack[stackTop];
	}

	void pop()
	{
		if(stackTop == -1)
			throw logic_error("stack empty");
		stack[stackTop--].~T(); //T的析构函数
	}

	void push(const T& theElement);


	T* stack;	//元素数组
private:
	int stackTop;//当前栈顶
	int arrayLength;//栈容量
};

template<class T>
arrayStack<T>::arrayStack(int initialCapacity)
{
//构造函数
	if(initialCapacity < 1)
	{
		ostringstream s;
		s << "Initial capacity = "<<initialCapacity<<"must be > 0";
		throw logic_error(s.str());
	}
	arrayLength = initialCapacity;
	stack = new T[arrayLength];
	stackTop = -1;
}

template<class T>
void arrayStack<T>::push(const T& theElement)
{
	//将元素 theElement 压入栈
	if(stackTop == arrayLength - 1)
	{
		//空间已满,容量加们
		changeLength1D(stack,arrayLength,2*arrayLength);
		arrayLength *= 2;
	}
	//在栈顶插入
	stack[++stackTop] = theElement;
}

//7. 
//1 ) 对栈的 ADT 进行扩充,增加以下函数:
//i. 输入栈。
//将一个栈转变为一个适合输出的串。
//将一个栈分裂为两个栈。第一个栈包含从栈底开始的一半元素,第二个栈包含剩余元素。
//iv. 将两个栈合并,把第二个栈的所有元素置于第一个栈的顶部。不改变第二个栈中元素
//的相对顺序。
//2 ) 定义抽象类 extendedStack,它扩展抽象类 stack,而且包含与 1) 中函数对
//应的方法。
//4) 测试你的代码的正确性。
template<class T>
class extendedStack : public virtual stack<T>
{
public:
	virtual std::istream& input(std::istream& in) = 0;
	virtual std::string toString() const = 0;
	virtual void split(extendedStack<T>& st1,
		               extendedStack<T>& st2) = 0;
	virtual void merge(extendedStack<T>& st2) = 0;
};

template<class T>
class extendedArrayStack : public arrayStack<T>, 
                           public extendedStack<T>
{
	template<class U>
	friend std::istream& operator>>(std::istream& in,
		                            extendedArrayStack<U>& st);
	template<class U>
	friend std::ostream& operator<<(std::ostream& out, 
		                            const extendedArrayStack<U>& st);
public:
	extendedArrayStack<T>(int initialCapacity = 10)
		:arrayStack<T>(initialCapacity)
		{

		}
	virtual std::istream& input(std::istream& in) override;
	virtual std::string toString() const override;
	virtual void split(extendedStack<T>& st1,
					   extendedStack<T>& st2);
	virtual void merge(extendedStack<T>& st2);

	virtual bool empty() const override
	{
		return arrayStack<T>::empty();
	}
	virtual int size() const override 
	{
		return arrayStack<T>::size();
	}
	virtual T& top() override
	{
		return arrayStack<T>::top();
	}
	virtual void pop() override
	{
		arrayStack<T>::pop();
	}
	virtual void push(const T& theElement) override
	{
		arrayStack<T>::push(theElement);
	}

	std::ostream& output(std::ostream& out) const
	{
		out<<toString();
		return out;
	}
};

template<class T>
std::istream& extendedArrayStack<T>::input(std::istream& in)
{
	T t;
	while(in >> t)
	{
		push(t);
	}
	return in;
}

template<class U>
std::istream& operator>>(std::istream& in, extendedArrayStack<U>& st)
{
	st.input(in);
	return in;
}

template<class U>
std::ostream& operator<<(std::ostream& out, 
						 const extendedArrayStack<U>& st)
{
	st.output(out);
	return out;
}

template <class T>
std::string extendedArrayStack<T>::toString() const
{
	std::string s = "";
	for(int i = 0; i < size(); i++)
	{
		s += std::to_string(arrayStack<T>::stack[i]);
		s += " ";
	}
	return s;
}

template<class T>	
void extendedArrayStack<T>::split(extendedStack<T>& st1,
								  extendedStack<T>& st2)
{
	auto& st1_t = dynamic_cast<extendedArrayStack<T>&>(st1);
	auto& st2_t = dynamic_cast<extendedArrayStack<T>&>(st2);
	int i = 0;
	for(;i < size() / 2;i++)
	{
		st1_t.push(arrayStack<T>::stack[i]);
	}
	for(;i<size();i++)
	{
		st2_t.push(arrayStack<T>::stack[i]);
	}
}

template<class T>
void extendedArrayStack<T>::merge(extendedStack<T>& st2)
{
	auto& st_t = dynamic_cast<extendedArrayStack<T>&>(st2);
	for(int i = 0; i < st_t.size();i++)
	{
		push(arrayStack<T>::stack[i]);
	}
}

//ex7
//3 ) 开发具体类 extendedDerivedArrayStack 和 extendedArrayStack,它们的基类是 extendedStack,
//而且各自派生于 derivedArrayStack 和 arrayStack。
//4) 测试你的代码的正确性。
template <class T>
class extendedDerivedArrayStack : private arrayList<T>,public extendedStack<T>
{
	template <class U>
	friend istream& operator>>(std::istream& in,extendedDerivedArrayStack<U>& st);
	template<class U>
	friend ostream& operator<<(std::ostream& out, const extendedDerivedArrayStack<U>& st);
public:
	extendedDerivedArrayStack<T>(int initialCapacity = 10)
		:arrayList<T>::arrayList(initialCapacity) {}
	virtual bool empty() const override
	{
		return arrayList<T>::empty();
	}

	virtual int size() const override
	{
		return arrayList<T>::size();
	}

	virtual T& top() override
	{
		if(empty())
		{
			throw logic_error("out of bound");
		}
		return arrayList<T>::get(size() - 1);
	}

	virtual void pop() override
	{
		if(empty())
		{
			throw logic_error("out of bound");
		}
		arrayList<T>::erase(size() - 1);
	}

	virtual void push(const T& theElement) override
	{
		arrayList<T>::insert(size(),theElement);
	}

	virtual std::istream& input(std::istream& in) override;
	virtual std::string toString() const override;
	virtual void split(extendedStack<T>& st1,extendedStack<T>& st2) override;
	virtual void merge(extendedStack<T>& st2) override;

	// ostream& output(ostream& out) const
	// {
	// 	out<<toString();
	// 	return 	out;
	// }
};

template <class T>
istream& extendedDerivedArrayStack<T>::input(istream& in)
{
	T t;
	while(in>>t)
	{
		push(t);
	}
	return in;
}

template <class U>
istream& operator>>(istream& in, extendedDerivedArrayStack<U>& st)
{
	st.input(in);
	return in;
}

template <class U>
ostream& operator<<(ostream& out,const extendedDerivedArrayStack<U>& st)
{
	st.output(out);
	return out;
}

template <class T>
string extendedDerivedArrayStack<T>::toString() const
{
	string s = "";
	for(int i = 0; i < size(); i++)
	{
		s += std::to_string(arrayList<T>::get(i));
		s += " ";
	}
	return s;
}

template <class T>
void extendedDerivedArrayStack<T>::split(extendedStack<T>& st1,extendedStack<T>& st2)
{
	int i = 0;
	for(;i < size() / 2;i++)
	{
		st1.push(arrayList<T>::get(i));
	}

	for(;i < size();i++)
	{
		st2.push(arrayList<T>::get(i));
	}
}

template <class T>
void extendedDerivedArrayStack<T>::merge(extendedStack<T>& st1)
{
	auto& st_t = dynamic_cast<extendedDerivedArrayStack<T>&>(st1);
	for(int i = 0; i < st_t.size(); i++)
	{
		push(st_t.arrayList<T>::get(i));
	}
}

//ex10. 开发具体类 stackWithArrayList,它派生于抽象类 stack。这个类具有单个数据成员 list,其
//类型为 arrayList<T>。
template <class T>
class stackWithArrayList : public stack<T>
{
public:
	stackWithArrayList<T>(int initialCapacity = 10)
		:list(initialCapacity){}
	virtual bool empty() const override
	{
		return list.empty();
	}

	virtual int size() const override 
	{
		return list.size();
	}

	virtual T& top() override
	{
		if(empty())
		{
			throw logic_error("out of bound");
		}
		return list.get(size() - 1);
	}

	virtual void pop() override
	{
		if(empty())
		{
			throw logic_error("out of bound");
		}
		list.erase(size() - 1);
	}

	virtual void push(const T& theElement) override
	{
		list.insert(size(),theElement);
	}
private:
	arrayList<T> list;
};

//ex11. 开发类 twoStacks,它用一个数组描述两个栈。一个栈的栈底在位置 0,另一个栈的栈底在
//位置 arrayLength-1。两个栈都向数组的中间增长〈见图 8-4 )。该类的方法 ”中 
//必须能够在每一个栈中实施 ADT 栈的所操作。而且每一个坟计的旬杂度 上直下上 
//应为 O(1),其中不包括改变数组大小所需要的时间 -

template <class T>
class twoStacks
{
public:
	twoStacks(int initialCapacity = 10);
	~twoStacks(){ delete[] stack; }
	bool empty1() const
	{
		return stackTop1 == -1;
	}
	bool empty2() const
	{
		return stackTop2 == arrayLength;
	}

	int size1() const
	{
		return stackTop1 + 1;
	}

	int size2() const
	{
		return arrayLength - stackTop2;
	}
	T& top1()
	{
		if(stackTop1 == -1)
			throw logic_error("empty stack");
		return *(stack + stackTop1);
	}
	T& top2()
	{
		if(stackTop2 == arrayLength)
			throw logic_error("empty stack");
		return *(stack + stackTop2);
	}

	void pop1()
	{
		if(stackTop1 == -1)
			throw logic_error("empty stack");

		stack[stackTop1--].~T();
		if(size1() + size2() < arrayLength / 4);
			decreaseLength();
	}

	void pop2()
	{
		if(stackTop2 == arrayLength)
		{
			throw logic_error("empty stack");
		}

		stack[stackTop2++].~T();
		if(size1() + size2() < arrayLength / 4)
		{
			decreaseLength();
		}
	}

	void push1(const T& theElement)
	{
		if(size1() + size2() == arrayLength)
		{
			increaseLength();
		}
		stack[++stackTop1] = theElement;
	}

	void push2(const T& theElement)
	{
		if(size1() + size2() == arrayLength)
		{
			increaseLength();
		}
		stack[--stackTop2] = theElement;
	}
private:
	void decreaseLength()
	{
		int sz2 = size2();
		changeLength(false);
		arrayLength *= 2;
		stackTop2 = arrayLength - sz2;
	}

	void increaseLength()
	{
		int sz2 = size2();
		changeLength(true);
		arrayLength *= 2;
		stackTop2 = arrayLength - sz2;
	}

	void changeLength(bool bigger)
	{
		int sz1 = size1();
		int sz2 = size2();
		int newLength = arrayLength / 2;
		if(bigger)
			newLength = arrayLength * 2;

		T* temp = new T[newLength];

		std::copy(stack,stack+sz1,temp);
		std::copy_backward(stack + arrayLength - sz2, stack+arrayLength, temp + newLength);
		delete[] stack;
		stack = temp;
	}
	int stackTop1,stackTop2;
	int arrayLength;
	T* stack;
};

template<class T>
twoStacks<T>::twoStacks(int initialCapacity)
{
	if(initialCapacity <= 0)
		throw logic_error("capacity should be > 0");

	stack = new T[initialCapacity];
	stackTop1 = -1;
	stackTop2 = initialCapacity;
	arrayLength = initialCapacity;
}

int main()
{
	derivedArrayStack<double> stack1;
	arrayStack<double> stack2;
	cout<<stack1.empty()<<endl;
	cout<<stack2.empty()<<endl;
	for(int i = 0; i < 10; i++)
	{
		stack1.push(i);
		stack2.push(i);
	}
	cout<<stack1.size()<<endl;
	cout<<stack2.size()<<endl;
	extendedArrayStack<double> stack3;
	string str("1 3 4 5 6 7");
	istringstream iss1(str);
	iss1>>stack3;
	cout<<stack3<<endl;
	extendedArrayStack<double> stack4;
	string str2("2 3 1 1 2 1");
	istringstream iss2(str2);
	iss2>>stack4;
	cout<<stack4<<endl;
	stack3.merge(stack4);
	cout<<stack3<<endl;
	extendedDerivedArrayStack<double>stack5;
	string str3("2 3 1 1 2 1");
	istringstream iss3(str2);
	iss3>>stack5;
	cout<<stack5<<endl;

	twoStacks<double> twoStacks1;
	for(int i = 0; i < 10; i++)
	{
		twoStacks1.push1(i);
		twoStacks1.push2(10-i);
	}
	cout<<twoStacks1.size1()<<endl;
	cout<<twoStacks1.size2()<<endl;
	cout<<twoStacks1.top1()<<endl;
	cout<<twoStacks1.top2()<<endl;

/*
	for(int i = 0; i < 10; i++)
	{
		std::cout<<stack1.top()<<std::endl;
		std::cout<<stack2.top()<<std::endl;
		stack1.pop();
		stack2.pop();
	}
*/

	return 0;
}

测试输出


xz@xiaqiu:~/study/algorithm/c++/1/build$ ./test 
1
1
10
10
1.000000 3.000000 4.000000 5.000000 6.000000 7.000000 
2.000000 3.000000 1.000000 1.000000 2.000000 1.000000 
1.000000 3.000000 4.000000 5.000000 6.000000 7.000000 1.000000 3.000000 4.000000 5.000000 6.000000 7.000000 
2 3 1 1 2 1 
10
10
9
1
xz@xiaqiu:~/study/algorithm/c++/1/build$ 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值