此前我已经实现了用C语言写一个顺序表,现在尝试使用c++;有需要的话可以浏览我之前的博客哦
静态顺序表:https://mp.csdn.net/postedit/79772162
动态顺序表:https://mp.csdn.net/postedit/79991561
-
typedef int DataType;
-
class Vector
-
{
-
public:
-
//初始化部分
-
//构造函数
-
Vector()//构造空的vector
-
:_array(new DataType[3])
-
,_capacity(3)
-
, _size(0)
-
{
-
}
-
Vector(size_t n, const DataType& data)//构造n个值为data的元素
-
:_array(new DataType[n])
-
, _capacity(n)
-
, _size(n)
-
{
-
for (size_t i = 0; i < n; ++i)
-
_array[i] = data;
-
}
-
//[first,last)
-
Vector(DataType *first, DataType *last)//用一段区间构造函数
-
{
-
size_t size = last - first;
-
_array = new DataType[size];
-
_capacity = size;
-
_size = size;
-
//拷贝
-
//法1memcpy(_array, first, sizeof(DataType)*size);
-
/*法2size_t i=0
-
while (first != last)
-
{
-
_array[i++] = *first++;
-
}*/
-
//法3
-
for (size_t i = 0; i < size; ++i)
-
_array[i] = first[i];
-
}
-
Vector(const Vector& v);//const类类型的引用即拷贝构造(涉及资源应该将拷贝构造函数、析构函数等都给出来)
-
//赋值运算符的重载
-
Vector & operator=(const Vector& v);
-
//析构函数
-
~Vector()
-
{
-
if (_array)
-
{
-
delete[] _array;
-
_capacity = 0;
-
_size = 0;
-
}
-
}
-
///容量
-
//有效元素的个数
-
size_t Size()const//不需要修改成员变量,用const修饰
-
{
-
return _size;
-
}
-
//返回容量
-
size_t Capacity()const
-
{
-
return _capacity;
-
}
-
//顺序表是否为空
-
bool Empty()const
-
{
-
return 0 == _size;
-
}
-
//改变size的值
-
void ReSize(size_t newSize, const DataType&data = DataType())
-
{
-
//有效元素的个数减少了
-
if (newSize <= _size)
-
{
-
_size = newSize;
-
}
-
else
-
{
-
if (newSize <= _capacity)
-
{
-
for (size_t i = _size; i < newSize; ++i)
-
_array[_size++] = data;
-
}
-
else
-
{
-
//放不下,重新开辟新空间
-
DataType *tmp = new DataType[newSize];
-
//拷贝旧空间中的元素
-
for (size_t i = 0; i < _size; ++i)
-
tmp[i] = _array[i];
-
for (size_t i = _size; i < newSize; ++i)
-
tmp[i] = data;//多出来的元素用data填充
-
//销毁旧空间,指向新空间
-
delete[] _array;
-
_array = tmp;
-
_capacity = newSize;
-
_size = newSize;
-
}
-
}
-
}
-
//访问
-
//访问任意位置的元素[通过下标访问内容]
-
DataType &operator[](size_t index)
-
{
-
assert(index < _size);//检测索引是不是有效的下标【小于有效元素的个数,则有效】
-
return _array[index];
-
}
-
const DataType &operator[](size_t index)const
-
{
-
assert(index < _size);
-
return _array[index];
-
}
-
//访问固定位置的元素
-
DataType& Front()//访问起始位置的元素
-
{
-
return _array[0];
-
}
-
const DataType& Front()const
-
{
-
return _array[0];
-
}
-
//访问最后一个位置的数据
-
DataType& Back()
-
{
-
return _array[_size-1];
-
}
-
const DataType& Back()const
-
{
-
return _array[_size - 1];
-
}
-
修改任意元素
-
//尾插
-
void PushBack(const DataType& data)
-
{
-
_CheckCapacity();//检测容量是否够用
-
_array[_size++] = data;
-
}
-
//尾删
-
void PushBack()
-
{
-
--_size;
-
}
-
//任意位置的插入
-
void Insert(size_t pos, const DataType& data);
-
//任意位置的删除
-
void Erase(size_t pos);
-
//清空
-
void Clear()
-
{
-
//有效元素置为0
-
_size = 0;
-
}
-
private:
-
void _CheckCapacity()
-
{
-
}
-
private:
-
DataType* _array;
-
size_t _capacity;
-
size_t _size;
-
};
-
void TestVector()
-
{
-
Vector v;
-
v.PushBack(1);
-
v.PushBack(2);
-
}
封装二叉树:
-
# include<assert.h>
-
# include<malloc.h>
-
# include<stdlib.h>
-
# include<iostream>
-
using namespace std;
-
struct BTNode//类的构造
-
{
-
BTNode *_pLeft;
-
BTNode *_pRight;
-
int _data;
-
BTNode(int data)
-
:_pLeft(NULL)
-
, _pRight(NULL)
-
, _data(data)
-
{}
-
};
-
//封装二叉树
-
class BinTree
-
{
-
public:
-
BinTree()
-
:_pRoot(NULL)
-
{}
-
//遍历
-
//前序遍历(递归)
-
void PreOrder()
-
{
-
_PreOrder(_pRoot);
-
}
-
//前序遍历(递归)
-
private:
-
void _PreOrder(BTNode *pRoot)
-
{
-
if (pRoot)
-
{
-
cout << pRoot->_data << " ";
-
_PreOrder(pRoot->_pLeft);
-
_PreOrder(pRoot->_pRight);
-
}
-
}
-
private:
-
BTNode *_pRoot;
-
};
使用模板的方式封装动态顺序表:
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封装成一个类
链表不是连续的空间不能直接++