摘要:
it人员无论是使用哪种高级语言开发东东,想要更高效有层次的开发程序的话都躲不开三件套:数据结构,算法和设计模式。数据结构是相互之间存在一种或多种特定关系的数据元素的集合,即带“结构”的数据元素的集合,“结构”就是指数据元素之间存在的关系,分为逻辑结构和存储结构。
此系列专注讲解数据结构数组、链表、队列、栈、树、图,通过介绍概念以及提及一些可能适用的场景,并以C++代码简易实现,多方面认识数据结构,最后为避免重复造轮子会浅提对应的STL容器。本文介绍的是数组Array。
(开发环境:VScode,C++17)
关键词
: C++,数据结构,数组,Array
声明:
本文作者原创,转载请附上文章出处与本文链接。
正文:
介绍:
数组是最简单、使用最频繁的一种数据结构,它是一种线性表数据结构,除了第一个元素以外,集合中的每个数据元素均只有一个前驱,除了最后一个元素以外,集合中每个元素均只有一个后继,用一组连续的内存空间,来存储一组具有相同类型的数据。
特性:
- 静态大小:在创建数组时,需要指定数组的大小,一旦创建,数组的大小就固定不变,不能动态修改。这意味着在数组的生命周期内,元素的数量是固定的。
- 连续存储:数组中的所有元素都存储在连续的内存位置上。这种连续性使得数组具有随机访问的特性,即可以通过索引直接访问数组中的任意元素,而不需要遍历整个数组。
- 相同类型:数组中的所有元素都必须是同一类型。这确保了数组在内存中的一致性和可管理性。
应用:
- 数值计算:在科学计算和工程应用中,数组经常用于存储和处理大量的数值数据。
- 图像处理:在图像处理中,像素值通常存储在一个二维数组中。
- 数据结构和算法:许多其他数据结构(如栈、队列、列表等)都是基于数组实现的。
- 数据库:在数据库中,索引通常使用数组来实现,以加快数据检索的速度。
代码实现:
#carray.h
#ifndef CARRAY_H
#define CARRAY_H
#include<iostream>
#define MAX_SIZE 256
using namespace std;
template <class T>
class CArray
{
public:
CArray(); // 构造函数
CArray(unsigned int, unsigned int = 0); // 数组构造函数
~CArray(); // 析构函数
CArray(CArray const&); // 拷贝构造函数
CArray& operator = (CArray const&); // 重载等号操作符,用于一个数组给另外一个数组赋值
T const& operator [] (unsigned int) const; // 重载中括号操作符,返回一个T数值常量,返回值不能被改变,在函数末尾加const表示this指针指向const
T& operator [] (unsigned int); // 重载中括号操作符,返回一个T数值常量,其返回值可以被改变
void setBase(unsigned int); // 设置成员变量base的数值
void setLength(unsigned int); // 设置成员变量length的数值
T* data() const; // 返回数组数据的指针m_pData
unsigned int getBase() const; // 返回成员base
unsigned int getLength() const; // 返回成员length
void print(); // 打印数组内容以及各属性
private:
T *m_pData; // 指向数组数据的指针
unsigned int base; // base为数组的起始下标
unsigned int length; // length为数组的长度
};
// 构造函数不含变量,只需要给对象的变量一个初始值
template <class T>
CArray<T>::CArray() : m_pData(new T[MAX_SIZE]),base(0),length(0)
{
}
// 初始化数组,n为数组的长度
template <class T>
CArray<T>::CArray(unsigned int n, unsigned int m) : m_pData(new T[n]),base(m),length(n)
{
}
// 析构函数,删除数组所占用的内存空间
template <class T>
CArray<T>::~CArray()
{
delete[] m_pData;
m_pData = nullptr;
}
// 拷贝构造函数,将一个数组从赋值到另外一个数组
template <class T>
CArray<T>::CArray(CArray<T> const& CArray) :
m_pData(new T[CArray.length]),
base(CArray.base),
length(CArray.length)
{
for (unsigned int i = 0; i < length; ++i)
m_pData[i] = CArray.m_pData[i];
}
// 重载赋值操作符
template <class T>
CArray<T>& CArray<T>::operator = (CArray<T> const& CArray)
{
if (this != &CArray){
delete[] m_pData;
base = CArray.base;
length = CArray.length;
m_pData = new T[length];
for (unsigned int i = 0; i < length; ++i)
m_pData[i] = CArray.m_pData[i];
}
return this;
}
// 这两个都为取下表操作符的重载,区别为第一个返回值不可以作为左值,第二个返回值可以作为左值
template <class T>
T const& CArray<T>::operator[] (unsigned int position) const
{
unsigned int const offset = position - base;
if (offset >= length)
throw out_of_range("invalid position");
return m_pData[offset];
}
template <class T>
T& CArray<T>::operator[] (unsigned int position)
{
unsigned int const offset = position - base;
if (offset >= length)
throw out_of_range("invalid position");
return m_pData[offset];
}
template <class T>
void CArray<T>::setBase(unsigned int newBase)
{
base = newBase;
}
template <class T>
void CArray<T>::setLength(unsigned int newLength)
{
T* const newm_pData = new T[newLength];
unsigned int const min = length < newLength ? length : newLength;
for (unsigned int i = 0; i < min; ++i)
newm_pData[i] = m_pData[i];
delete[] m_pData;
m_pData = newm_pData;
length = newLength;
}
template <class T>
T* CArray<T>::data() const
{
return m_pData;
}
template <class T>
unsigned int CArray<T>::getBase() const
{
return base;
}
template <class T>
unsigned int CArray<T>::getLength() const
{
return length;
}
template <class T>
void CArray<T>::print()
{
cout << "m_pData:";
for (unsigned int i = base; i < length; i++){
cout << m_pData[i] << " ";
}
cout << endl;
cout << "length:" << length << endl;
cout << "base:" << base << endl;
}
#endif // !CARRAY_H
#carray.cpp
#include "carray.h"
using namespace std;
int main(int argc, char** argv)
{
CArray<int> CArray0 = CArray<int>();
CArray0.print();
cout << endl;
CArray<int> CArray1 = CArray<int>(10);
CArray1.print();
cout << endl;
CArray<int> CArray2(CArray1);
CArray2.print();
cout << endl;
CArray2.~CArray();
CArray<int> CArray3(10);
for (unsigned int i = CArray1.getBase(); i < CArray1.getLength() - CArray1.getBase(); i++){
CArray3.data()[i] = i;
}
CArray3.print();
cout << endl;
CArray3.setBase(2);
CArray3.print();
cout << endl;
CArray3.setLength(7);
CArray3.print();
return 0;
}
对应STL:
-
string
string类本不是STL的容器,但是它与STL容器有着很多相似的操作,C++中的string类相当于是字符数组,但是其更方便于我们的操作,而且不需要在输入之前初始化字符数组的容量,节省空间。
-
array
array即数组,其大小固定,所有的元素严格按照内存地址线性排列,array 并不维护元素之外的任何多余数据,甚至也不会维护一个size这样的变量,这保证了它在存储性能上和C++语法中的数组符号
[]
无异。 -
vector
vector 就是能够动态调整大小的 array。和 array 一样,vector 使用连续内存空间来保存元素,这意味着其元素可以用普通指针的++和–操作来访问;不同于 array 的是,其存储空间可以自动调整。
-
bitset
bitset容器相当于是01数组,其方便之处是可以直接按位(下标)进行位运算,但是要注意下标从小到大依次存低位到高位,是逆序的。
推荐阅读
C/C++专栏:
https://blog.csdn.net/weixin_45068267/category_12268204.html
(后续会更新更多数据结构以及对应的STL容器使用)
(画饼ing:)
C++数据结构之:链List:
C++数据结构之:队Queue:
C++数据结构之:栈Stack:
C++数据结构之:堆Heap:
C++数据结构之:树Tree:
C++数据结构之:图Graph:
C++ STL容器:序列式容器-数组string,vector,array,bitset: