数据结构第1章 - 线性表(Part 1)
写在开头
作为生活中最常见的一种数据结构(嗯?),线性表以其简单和基本的特点被广泛使用,学好线性表非常重要,使用线性表能让我们更灵活地存储数据。
线性表的定义
线性表,LinearList,是由许多相同的数据元素所组成的一个有限序列,由于其存储的线性(这不需要解释吧),被成为线性表。 一个非空的线性表可以这么表示: L=(a1, a2, …, an ) 其中,ai被称为数据元素,i为在这个线性表中的位置
线性表基本操作
作为一个成熟的数据结构,当然要有好用的增删改查方法啦~ 因此对于一个抽象类型的线性表,我们需要有如下操作
- Init:初始化一个空的线性表【增】
- Destory:销毁当前使用的线性表【删】
- GetLength:获取当前线性表的数据数量【查】
- GetByIndex:获取指定位置的元素【查】
- Locate:查找指定元素并返回位置【查】
- Insert:在指定位置插入一个元素【增】
- Modify:在指定位置修改元素值【改】
- Delete:删除指定位置的元素【删】
- IsEmpty:查询线性表是否为空【查】
- Print:遍历并输出【查】,个人觉得是遍历+GetByIndex
线性表存储结构1 - 顺序表
顺序表的定义(不正经)
其实哦,线性表非常像一个我们一直用的东西——数组! 其实这个说的拉一点,就是一个开的很大的数组加上一个代表元素数量的变量(考试别这么写!顺序表和数组还是不一样滴) 因为每个元素的位置在内存里都是线性的(数组就是这么存哒)所以叫线性表啦: 第i个元素内存位置=第一个元素内存位置+(i-1)×每个数据元素所占空间
顺序表的定义(正经)
线性表的顺序存储结构称为顺序表(sequential list)。 顺序表是用一段地址连续的存储单元依次存储线性表的数据元素。由于线性表中每个元素的类型相同,通常用一维数组来实现顺序表,也就是把线性表中相邻的元素存储在数组中相邻的位置,从而导致了数据元素的序号和存放它的数组下标之间的一一对应关系。 ——王红梅,《数据结构(C++版)(第二版)》
顺序表代码实现
下面就是线性表的C++实现的大类~
const int MAX_SIZE=256;//按需修改
template<class DataType>
class SeqList {
public:
SeqList() {
//无参构造,创建空顺序表
this -> length = 0;
}
SeqList(DataType data[], int length) {
//带参数构造,将数据传入
if(length > MAX_SIZE) {
throw "illegal size";
}
this -> length = length;
for(int i = 0; i < length; i++) {
this -> data[i] = data[i];
}
}
~SeqList() {
//析构函数相当于Destory
}
int GetLength() {
//获取当前线性表的数据数量
return this -> length;
}
DataType GetByIndex(int index) {
//获取指定位置的元素,这边下标从1开始,需要-1
index--;
if(index < 0 || index >= this -> length) {
throw "index out of bounds";
}
return this -> data[index];
}
int Locate(DataType s) {
//查找指定元素并返回位置
for(int i = 0; i < this -> length; i++) {
if(data[i] == s) {
return i + 1;
}
}
return 0;
}
void Insert(int index, DataType s) {
//在指定位置插入一个元素
if(this -> length >= MAX_SIZE) {
throw "seqlist is full";
}
index--;
if(index < 0 || index > length) {
throw "index out of bounds";
}
for(int i = length; i > index; i--) {
this -> data[i] = this -> data[i - 1];
}
this -> data[index] = s;
this -> length++;
}
void Modify(int index, DataType m) {
//从指定位置修改值,这边下标从1开始,需要-1
index--;
if(index < 0 || index >= this -> length) {
throw "index out of bounds";
}
this -> data[index] = m;
}
void Delete(int index) {
//删除指定位置的元素
index--;
if(index < 0 || index >= length) {
throw "index out of bounds";
}
for(int i = index; i < this -> length - 1;i++) {
this -> data[i] = this -> data[i + 1];
}
this -> length--;
this -> data[this -> length] = NULL;
}
void Print() {
//遍历顺序表并输出
for(int i = 0; i < this -> length; i++) {
cout<<this -> data[i]<<endl;
}
}
private:
int length;
DataType data[MAX_SIZE];
};
顺序表代码详解
构造和析构
SeqList() {
//无参构造,创建空顺序表
this -> length = 0;//设置初始空顺序表长度为0
}
SeqList(DataType data[], int length) {
//带参数构造,将数据传入
if(length > MAX_SIZE) {//检查初始化大小是不是符合条件
throw "illegal size";
}
this -> length = length;//传入大小
for(int i = 0; i < length; i++) {//遍历传入的数组
this -> data[i] = data[i];//传入数据
}
}
~SeqList() {
//析构函数相当于Destory,销毁顺序表实例
}
查询
查询长度和用位置返回数据比较简单;定位元素则需要一个个的接下去寻找,由于无序也没办法二分,只能使用O(length)的查找方式
int GetLength() {
//获取当前线性表的数据数量
return this -> length;
}
DataType GetByIndex(int index) {
//获取指定位置的元素,这边下标从1开始,需要-1
index--;
if(index < 0 || index >= this -> length) {//检查查询下标是否合法
throw "index out of bounds";
}
return this -> data[index];
}
int Locate(DataType s) {
//查找指定元素并返回位置
for(int i = 0; i < this -> length; i++) {//顺序查找
if(data[i] == s) {
return i + 1;//位置是i + 1
}
}
return 0;
}
插入、修改和删除
插入时,我们需要先把位置空出来再放入数据,由于线性表有空的空间,我们从后往前逐个往后挪,最后将要插入元素插入空挡;
修改非常简单,就是改一下值; 删除则是插入的反过程,用后面的元素逐个覆盖前面的元素,最后把多出来的一个空清空。
void Insert(int index, DataType s) {
//在指定位置插入一个元素
if(this -> length >= MAX_SIZE) {//错误检查:是不是满了
throw "seqlist is full";
}
index--;
if(index < 0 || index > length) {//错误检查:插入位置是否合法
throw "index out of bounds";
}
for(int i = length; i > index; i--) {//把元素往后挪
this -> data[i] = this -> data[i - 1];
}
this -> data[index] = s;//在空挡插入元素
this -> length++;//加了一个元素,长度+1
}
void Modify(int index, DataType m) {
//从指定位置修改值,这边下标从1开始,需要-1
index--;
if(index < 0 || index >= this -> length) {//检查下标是否合法
throw "index out of bounds";
}
this -> data[index] = m;//简单修改
}
void Delete(int index) {
//删除指定位置的元素
index--;
if(index < 0 || index >= length) {//检查下标是否合法
throw "index out of bounds";
}
for(int i = index; i < this -> length - 1;i++) {//往前覆盖
this -> data[i] = this -> data[i + 1];
}
this -> length--;//长度-1
this -> data[this -> length] = NULL;//把往前挪之后多出来的一个空删掉
}
数据可视化
把数据都输出,应该也算是种可视化吧uwu
void Print() {
//遍历顺序表并输出
for(int i = 0; i < this -> length; i++) {
cout<<this -> data[i]<<endl;
}
}
顺序表小结
记不住就多看几遍,无非是增删改查,自己去试试看吧
写在最后(Part1)
刚开始学习数据结构难免会摸不着头脑,不过顺序表比较简单,试着从简单的数组过渡到线性表中最常见的顺序表会比较轻松,加油~~ 下一章讲线性表的链式存储结构——链表,将会非常好玩。
|