用类的形式封装顺序表

此前我已经实现了用C语言写一个顺序表,现在尝试使用c++;有需要的话可以浏览我之前的博客哦害羞

静态顺序表:https://mp.csdn.net/postedit/79772162

动态顺序表:https://mp.csdn.net/postedit/79991561

 
  1. typedef int DataType;

  2. class Vector

  3. {

  4. public:

  5. //初始化部分

  6. //构造函数

  7. Vector()//构造空的vector

  8. :_array(new DataType[3])

  9. ,_capacity(3)

  10. , _size(0)

  11. {

  12.  
  13. }

  14. Vector(size_t n, const DataType& data)//构造n个值为data的元素

  15. :_array(new DataType[n])

  16. , _capacity(n)

  17. , _size(n)

  18. {

  19. for (size_t i = 0; i < n; ++i)

  20. _array[i] = data;

  21. }

  22. //[first,last)

  23. Vector(DataType *first, DataType *last)//用一段区间构造函数

  24. {

  25. size_t size = last - first;

  26. _array = new DataType[size];

  27. _capacity = size;

  28. _size = size;

  29. //拷贝

  30. //法1memcpy(_array, first, sizeof(DataType)*size);

  31. /*法2size_t i=0

  32. while (first != last)

  33. {

  34. _array[i++] = *first++;

  35. }*/

  36. //法3

  37. for (size_t i = 0; i < size; ++i)

  38. _array[i] = first[i];

  39. }

  40. Vector(const Vector& v);//const类类型的引用即拷贝构造(涉及资源应该将拷贝构造函数、析构函数等都给出来)

  41. //赋值运算符的重载

  42. Vector & operator=(const Vector& v);

  43. //析构函数

  44. ~Vector()

  45. {

  46. if (_array)

  47. {

  48. delete[] _array;

  49. _capacity = 0;

  50. _size = 0;

  51. }

  52. }

  53. ///容量

  54. //有效元素的个数

  55. size_t Size()const//不需要修改成员变量,用const修饰

  56. {

  57. return _size;

  58. }

  59. //返回容量

  60. size_t Capacity()const

  61. {

  62. return _capacity;

  63. }

  64. //顺序表是否为空

  65. bool Empty()const

  66. {

  67. return 0 == _size;

  68. }

  69. //改变size的值

  70. void ReSize(size_t newSize, const DataType&data = DataType())

  71. {

  72. //有效元素的个数减少了

  73. if (newSize <= _size)

  74. {

  75. _size = newSize;

  76. }

  77. else

  78. {

  79. if (newSize <= _capacity)

  80. {

  81. for (size_t i = _size; i < newSize; ++i)

  82. _array[_size++] = data;

  83. }

  84. else

  85. {

  86. //放不下,重新开辟新空间

  87. DataType *tmp = new DataType[newSize];

  88. //拷贝旧空间中的元素

  89. for (size_t i = 0; i < _size; ++i)

  90. tmp[i] = _array[i];

  91. for (size_t i = _size; i < newSize; ++i)

  92. tmp[i] = data;//多出来的元素用data填充

  93. //销毁旧空间,指向新空间

  94. delete[] _array;

  95. _array = tmp;

  96. _capacity = newSize;

  97. _size = newSize;

  98. }

  99. }

  100. }

  101. //访问

  102. //访问任意位置的元素[通过下标访问内容]

  103. DataType &operator[](size_t index)

  104. {

  105. assert(index < _size);//检测索引是不是有效的下标【小于有效元素的个数,则有效】

  106. return _array[index];

  107. }

  108. const DataType &operator[](size_t index)const

  109. {

  110. assert(index < _size);

  111. return _array[index];

  112. }

  113. //访问固定位置的元素

  114. DataType& Front()//访问起始位置的元素

  115. {

  116. return _array[0];

  117. }

  118. const DataType& Front()const

  119. {

  120. return _array[0];

  121. }

  122. //访问最后一个位置的数据

  123. DataType& Back()

  124. {

  125. return _array[_size-1];

  126. }

  127. const DataType& Back()const

  128. {

  129. return _array[_size - 1];

  130. }

  131. 修改任意元素

  132. //尾插

  133. void PushBack(const DataType& data)

  134. {

  135. _CheckCapacity();//检测容量是否够用

  136. _array[_size++] = data;

  137. }

  138. //尾删

  139. void PushBack()

  140. {

  141. --_size;

  142. }

  143. //任意位置的插入

  144. void Insert(size_t pos, const DataType& data);

  145. //任意位置的删除

  146. void Erase(size_t pos);

  147. //清空

  148. void Clear()

  149. {

  150. //有效元素置为0

  151. _size = 0;

  152. }

  153. private:

  154. void _CheckCapacity()

  155. {

  156.  
  157. }

  158.  
  159. private:

  160. DataType* _array;

  161. size_t _capacity;

  162. size_t _size;

  163. };

  164.  
  165. void TestVector()

  166. {

  167. Vector v;

  168. v.PushBack(1);

  169. v.PushBack(2);

  170.  
  171. }

封装二叉树:

 
  1. # include<assert.h>

  2. # include<malloc.h>

  3. # include<stdlib.h>

  4. # include<iostream>

  5. using namespace std;

  6. struct BTNode//类的构造

  7. {

  8. BTNode *_pLeft;

  9. BTNode *_pRight;

  10. int _data;

  11. BTNode(int data)

  12. :_pLeft(NULL)

  13. , _pRight(NULL)

  14. , _data(data)

  15. {}

  16. };

  17. //封装二叉树

  18. class BinTree

  19. {

  20. public:

  21. BinTree()

  22. :_pRoot(NULL)

  23. {}

  24. //遍历

  25. //前序遍历(递归)

  26. void PreOrder()

  27. {

  28. _PreOrder(_pRoot);

  29. }

  30. //前序遍历(递归)

  31. private:

  32. void _PreOrder(BTNode *pRoot)

  33. {

  34. if (pRoot)

  35. {

  36. cout << pRoot->_data << " ";

  37. _PreOrder(pRoot->_pLeft);

  38. _PreOrder(pRoot->_pRight);

  39. }

  40. }

  41. private:

  42. BTNode *_pRoot;

  43. };

  44.  

 

 

 

使用模板的方式封装动态顺序表:

 

vector的迭代器Iterator不需要封装成一个类,因为指针可以做到,只需要添加两个方法即可:Begin()和End()

 

test.h

template<class Iterator,class T>
//迭代器的类型:class Iterator;元素的类型:class T
Iterator Find(Iterator start, Iterator finish, const T& data)
{
	while (start != finish){
		if (*start != data)
			return start;
		++start;
	}
	return start;
}

 

  
 # include<stdio.h>
# include<stdlib.h>
# include<string.h>
# include<assert.h>
# include<iostream>
# include<vector>
# include<test.h>

using namespace std;
template<class T>
class Vector
{
public:
	typedef T* Iterator;
public:
	//第一种构造函数,初始化为0
	Vector()
		:_start(0)
		, _finish(0)
		, _endOfStrage(0)
	{}
	//顺序表中有size个值为data的元素
	Vector(size_t size, const T& data)
		:_start(new T[size])
		, _finish(_start)
		, _endOfStrage(_start+size)
	{
		for (size_t i = 0; i < size; ++i)
			_start[i] = data;//*_finish++ = data;
	}
	//用左闭右开的区间[first,last)来构造
	Vector(const T* first, const T* last);
	//拷贝构造:用const类类型的引用来构造当前对象
	Vector(const Vector<T>& v);
	//赋值运算符的重载
	Vector<T>& operator=(const Vector<T>& v);
	~Vector()
	{
		if (_start)
		{
			delete[] _start;
			_start = _finish = _endOfStrage = 0;
		}
	}
	Iterator Begin()
	{
		return _start;
	}
	Iterator End()
	{
		return _finish;
	}
	//有效元素的个数
	size_t Size() const
	{
		return _finish - _start;
	}
	//容量
	size_t Capacity()const
	{
		return _endOfStrage - _start;
	}
	//是不是空
	bool Empty() const
	{
		return _start == _finish;
	}
	// T():调用构造函数时,调用一个没有名字的对象,简称无对象。data引用无对象
	//多出来的对象用无对象填充
	void ReSize(size_t newSize, const T& data = T())
	{
		size_t oldSize = Size();
		if (newSize <= oldSize)//元素个数减少了
			_finish = _start + newSize;//更新_finish
		else
		{
			//将顺序表中的元素增加到newSize
			//顺序表的空间中可以存放多出来的元素,
			//多出来的空间存放元素data:const T& data = T()
			//data的类型为T,既可以代表自定义类型,也可以代表基类型
			//内置类型,默认值为0,多出来的空间data用缺省的值0进行填充
			size_t capacity = Capacity();
			if (newSize < capacity)
			{
				for (size_t i = oldSize; i < newSize; ++i)
					_start[i] = data;
				_finish = _start + newSize;
			}
			esle//超过容量了
			{
				//开辟新空间
				T* tmp = new T[newSize];
				//拷贝旧空间里的元素
				if (_start)//如果旧空间中没有元素,就不再拷贝
				{
					for (size_t i = 0; i < oldSize; ++i)
						tmp[i] = _start[i];
				}
				//多出来的元素给缺省值
				for (size_t i = oldSize; i < newSize; ++i)
					tmp[i] = data;
				//释放旧空间
				if (_start)
					delete[] _start;
				_start = tmp;//指向新空间
				_finish = _start + newSize;
				_endOfStrage = _finish;
			}
		}
	}
	//申请预留空间:只是预留空间,不改变元素的个数
	void Reserve(size_t newCapacity)
	{
		size_t oldCapacity = Capacity();
		if (newCapacity > oldCapacity)
		{
			//如果新的容量超过旧的容量,就重新给一个容量
			T* tmp = new T[newCapacity];
			//记录下没有改变之前的Size
			size_t size = Size();
			if (_start)//必须先检查旧空间是否存在
			{
				for (size_t i = 0; i < size; ++i)
					tmp[i] = _start[i];
				delete[] _start;//释放_start
			}
			_start = tmp;
			_finish = _start + size;
			_endOfStrage = _start + newCapacity;
		}
	}
	//下标运算符的重载
	T& operator[](size_t index)
	{
		return _start[index];
	}
	const T& operator[](size_t index)const
	{
		return _start[index];
	}
	//访问起始位置的数据
	T& Front()
	{
		return *_start;
	}
	const T& Front()const
	{
		return *_start;
	}
	//访问最后一个位置的数据
	T& Back()
	{
		return *(_finish - 1);
	}
	const T& Back()const
	{
		return *(_finish - 1);
	}
	//对顺序表中的元素进行修改
	//尾插
	void PushBack(const T& data)
	{
		_CheckCapacity();//先检查空间是否够用
		*_finish++ = data;
	}
	void PopBack()
	{
		if (_start == _finish)
			return;
		--_finish;
	}
	//任意位置的插入
	void Insert(size_t pos, const T& data);
	//任意位置的删除
	void Erase(size_t pos);
	void Clear()
	{
		_finish = _start;
	}
	void Swap(Vector<T>& v)
	{
		swap(_start, v._start);//将当前空间的起始位置和v空间的起始位置交换
		swap(_finish, v._finish);
		swap(_endOfStrage, v._endOfStrage)
	}
bool IsPODType()
{
    char *str[]={"char","short","int","long","long long"};
    const char *pType=typeid(T).name();
    for(int i=0;i<sizeof(str)/sizeof(str[0]);++i){
        if(strcmp(str[i],pType)==0)
            return true;
        else
            return false;
}
	void _CheckCapacity()
	{
		if (_finish == _endOfStrage)
		{
			//_finish走到了空间的末尾
			size_t newCapacity = Capacity() * 2 + 3;
//顺序表或者是vector中一个元素没有放,则认为底层是没有空间的,为0,乘以2之后仍然为0
			//Reserve(newCapacity);
			T* tmp = new T[newCapacity];
			//记录下没有改变之前的Size
			size_t size = Size();
			if (_start)//必须先检查旧空间是否存在
			{
				//for (size_t i = 0; i < size; ++i)
					//tmp[i] = _start[i];
				memcpy(tmp, _start, size*sizeof(T));
				/*判断以下是不是内置类型,优化memcpy(自定义类型会出错)和赋值(效率低)各自的缺点
				即让自定义类型时使用赋值,内置类型使用memcpy
				if (false)//char *strType[]={"int","double","short","char",}
				//bool IsPODType(strType,type)
				//strType[]中包含所有的类型,typeid(T).name()为函数IsPODType中的参数type,
				//用这个type和strType中找到的类型进行比较,看看是否存在。
					memcpy(tmp, _start, size*sizeof(T));
				else
				{
					for (size_t i = 0; i < size; ++i)
						tmp[i] = _start[i];
				}
				*/
				delete[] _start;//释放_start
			}
			_start = tmp;
			_finish = _start + size;
			_endOfStrage = _start + newCapacity;
		}
	}
private:
	T* _start;//T* _array;//动态顺序表
	T* _finish;// size_t _size;
	T* _endOfStrage;//size_t _capacity;
};
template<class T>
Vector<T>::Vector(const T* first, const T* last)
{
	size_t size = last - first;//区间中存在的元素
	_start = new T[size];
	for (size_t i = 0; i < size; ++i)
	{
		_start[i] = first[i];
	}
	_finish = _start + size;
	_endOfStrage = _finish;
}

void Test()
{
	Vector<int> v1;
	//vector后面接上一个<>才能算得上一个完整的类,模板中的vector只是模板类的一个名字
	v1.PushBack(1);
	v1.PushBack(2);
	v1.PushBack(3);
	v1.PushBack(4);
	v1.PushBack(5);
	cout << v1.Size() <<endl;
	cout << v1.Front() << endl;
	cout << v1.Back << endl;
	cout << v1.Capacity() << endl;
	v1.PopBack();
	v1.PopBack();
	cout << v1.Size() << endl;
	cout << v1.Capacity() << endl;
	v1.ReSize(7, 9);
	cout << v1.Size() << endl;
	for (size_t i = 0; i < v1.Size(); ++i)
		cout << v1[i] << " ";
	cout << endl;
	cout << v1.Capacity() << endl;
	v1.ReSize(20, 4);
	cout << v1.Size() << endl;
	Vector<int>::Iterator it = v1.Begin();
	while (it != v1.End())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	cout << v1.Capacity() << endl;
}

# include<vector>
//测试库函数中的vector(名字都为小写)
//增容的方式可能不同
void Testvector()
{
	vector<int> v1;
 	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	cout << v1.size() << endl;
	cout << v1.front() << endl;
	cout << v1.back << endl;
	cout << v1.capacity() << endl;
	v1. pop_back();
	v1.pop_back();
	cout << v1.size() << endl;
	cout << v1.capacity() << endl;
	v1.resize(7, 9);
	cout << v1.size() << endl;
	for (size_t i = 0; i < v1.size(); ++i)
		cout << v1[i] << " ";
	cout << endl;
	cout << v1.capacity() << endl;
	v1.resize(20, 4);
	cout << v1.size() << endl;
	vector<int>::iterator it = v1.begin();
	while (it != v1.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	cout << v1.capacity() << endl;
}


//普通版本的深拷贝
//向vector中存放一些自定义(string)类型
class String
{
public:
	String(const char * str = " ")//构造函数
	{
		if (NULL == str)
			str = "";
		_str = new char[strlen(str) + 1];//加一是为了存放\0
		strcpy(_str, str);//把字符串的内容拷贝到当前对象
	}
	//拷贝构造
	String(const String &s)
		:_str(new char[strlen(s._str)+1])
	{
		strcpy(_str, s._str);
	}
	//赋值操作符的重载
	String & operator=(const String& s)
	{
		if (this != &s)
		{
			char *tmp = new char[strlen(s._str) + 1];
			strcpy(tmp, s._str);
			//释放旧空间
			delete[] _str;
			_str = tmp;
		}
		return *this;
	}
	~String()
	{
		if (_str)
			delete[] _str;
	}

	//输出运算符
	friend ostream& operator<<(ostream& _cout, const String& s)
	{
		_cout << s._str;
		return _cout;
	}
private:
	char *_str;
};
void TestVectorString()//会打印随机值,问题是由memcpy引起的,
//memcpy是内存的拷贝,会将原空间中的内容原封不动的拷贝到临时空间
//会造成多个对象公用同一块临时空间,程序访问非法内存,会出现问题
//memcpy的拷贝是浅拷贝,换成代码中注释掉的赋值则不会出现问题:赋值得一个一个的赋,效率低,但是无论是内置类型,还是自定义类型都不会出错
//浅拷贝如果对象没有涉及资源就不会出现问题,一旦涉及资源就会出现问题
//自定义类型使用赋值,不会出错
{
	Vector<String> v;
	v.PushBack("1111");
	v.PushBack("2222");
	v.PushBack("3333");
	v.PushBack("4444");
	v.PushBack("5555");
	//用memecpy拷贝结束之后,旧空间string类型的对象和新空间string类型的对象,
	//在底层使用同一块空间,为浅拷贝
	//且只有三个对象_start,_finish,_endOfStorage
	//析构时,先析构旧空间中的对象,先析构对象,最后析构整体,析构后
	//新空间中中的地址还存在,相当于一块非法的空间:临时空间中三个sring类型的对象的指针会成为野指针
	
	//Vector<String>::Iterator是String *
	Vector<String>::Iterator it = v.Begin();
	while (it != v.End())
	{
		cout << *it << " ";
		++it;
	}
        it=Find(v.Begin(),v.End(),3);
        if(it!=v.End())
        {
            cout<<"3 is in vector"<<endl;
        }
        else
            cout<<"3 is not in vector"<<endl;
}
int main()
{
	Test();
	system("pause");
	return 0;
}

list库中的迭代器有两个版本普通的和const类型的;不提供头插和头删,因为顺序表在头部进行插入和删除的效率很低。

标准库STL中包含了六大组件:

(1)通用:使用模板

(2)效率尽可能高

容器:vector:动态顺序表

  List:带头节点的双向循环链表【

 

          

 

算法--->通用:

在某一区间内查找到某一元素后,返回其位置,想要在list或者vector中查找某一个元素,可以直接在库里面调用Find函数。

a、是vector:----->T*

Find(start, finish, data)
{
	while (start != finish){
if (*star == data)
   return start;
  start++;
	}
return NULL;//没有找到
}

 b、是链表:------->通过迭代器来操作Iterator封装成一个类

链表不是连续的空间不能直接++

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xuruhua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值