-
线性表的顺序存储
1.1线性表的定义
线性表例子:
- 英文字母小写字母表(a,,b,c….,z)是一个长度为26的线性表。
- 一年中的四个季节(春,夏,秋,冬)是一个长度为4的线性表。
- 矩阵是一个比较复杂的线性表。
- 学生情况登记表是一个复杂的线性表:由若干个数据项组成的数据元素称为记录;
由多个记录构成的线性表又称为文件。
线性表是由n(n>=0)个属性相同的数据元素a1,a2,a3…an组成的一个有限序列。
线性表或是空表,或可以表示为:A=(a1,a2,a3…ai,…,an),其中ai(i=1,2,…n)是线性表中的一个元素,i表示元素存在的位置。
1.2线性表的逻辑结构
1、有且只有一个表头元素a1,它无前驱;
2、有且只有一个表尾元素an,它无后继;
3、表头元素与表尾元素外,其它所有元素有且只有一个前驱,也有且只有一个后继。
4、线性表中结点的个数n称为线性表的长度。当n=0时,称为空表。
A=(a1,a2,…,ai,…,an)
定义一个数据结构需要元素+关系
线性表数据结构定义
Linear_list=(D,R),其中D={ai|ai∈A,i=1,2,…n;n>=0},R={<ai,ai+1>|1<=i<=n-1};
关系的定义<ai,ai+1>:ai,ai+1必定相邻;ai必定在ai+1之前(如果i+1存在)
1.3线性表的抽象数据类型
线性表的抽象数据类型ADT
数据元素D:D={ai|ai∈A,i=1,2,…,n,n>=0}
数据关系R:R={<ai,ai+1>|ai|ai+1∈D,i=1,…,n-1}
操作P:
1、初始化(InitList):初始化线性表
2、求表长(ListLength):求线性表中数据元素个数
3、判空表(ListEmpty):判断线性表是否为空
4、插入(ListInsert):在指定位置插入数据元素
5、删除(ListDelete): 删除指定位置上的数据元素
6、取值(GetElem):获取指定位置数据元素的值
1.4线性表的顺序存储结构与基本运算的实现
1.4.1顺序表概念
线性表的存储方式:顺序存储(使用数组,顺序表)、链式存储(使用指针,链表)
顺序表的定义:用一组地址连续的存储单元一次存储线性表的每个数据元素,这种存储结构称为线性表的顺序存储结构,用这种结构表示的线性表称为顺序表。
顺序表的特点:用数据元素在计算机内物理位置相邻来表示线性表中数据元素之间的逻辑关系。
1.4.2数据元素的存储结构
顺序表中第i个数据元素ai的存储位置:LOC(ai)=LOC(a1)+(i-1)*m, LOC(ai)为顺序表的首地址;m为顺序表的一个数据元素占用的存储空间。
顺序表为随机存储结构(读取数据元素所需要的时间与其所在的位置无关)。
顺序存储结构内存视图:
1.4.3顺序表的C++语言描述
//MaxSize表示顺序表中最多元素个数
#define MaxSize 100
//ElemType是一个抽象类型。在实现时,要定义为具体的数据类型。如typedef char ElemType
typedef int ElemType; //声明顺序表的元素类型
typedef struct{
ElemType data[MaxSize]; //存放顺序表数据
//length表示顺序表的当前表长,非负值且<=MaxSize;
int length;;
}SqList;//SqList为用户定义的顺序表类型
1.4.4SqList类型变量的内存视图
SqList my_list;//定义顺序表类型的变量my_list
SqList——顺序表数据类型
My_list——SqList类型的实例化变量my_list拥有两个数据域:数组(data,存放顺序表数据)、变量(length,保存顺序表数据个数)
1.4.5顺序表程序实现方法
1.声明顺序表的数据类型:一般在头文件中声明(该头文件中还应包括操作接口的声明),其告诉编译器该数据类型占内存空间的大小。
2.定义顺序表类型的变量:一般在函数中或实现代码中定义,其告诉编译器为变量分配内存空间。
3.操作顺序表类型变量:操作变量中保存的数据。
1.4.6顺序表的基本操作
在顺序存储结构基础上,实现顺序表的基本操作。
注意:在实现每一个操作时都要确保当前存储结构下的顺序表其逻辑结构不变。
初始化顺序表:
void InitList(SqList &L)//考虑为何使用引用传递
{//L为指向顺序表类型的引用
L.length=0;
}
在InitList()函数中,需要改变顺序表的length域的值,因此参数L使用引用传递。(引用:变量的别名)。
设计函数时,根据需要决定参数传递的方式。
1.4.7顺序表的简单应用
头文件代码:
#include <iostream>
using namespace std;
#define MaxSize 100
typedef int ElemType; //声明元素类型
typedef struct {
ElemType data[MaxSize]; //存放线性表数据
int length;
} SqList; // SqList为用户定义的线性表类型
//初始化空线性表
void InitList(SqList &L);
//判断线性表是否为空
bool ListEmpty(SqList L);
//求出线性表长度
int ListLength(SqList L);
//向线性表指定位置插入一个新元素
bool ListInsert(SqList &L, int pos, ElemType item);
//从线性表中删除第一个与指定值匹配的元素
bool ListDelete(SqList &L, int pos, ElemType &item);
//获取顺序表中指定位置上的数据元素
bool GetElem(SqList L, int pos, ElemType &item);
//从线性表中查找元素,返回第一个与指定值匹配元素位置
int Find(SqList L, ElemType item);
//遍历输出线性表
void TraverseList(SqList L);
源文件代码:
//初始化空线性表
void InitList(SqList &L)
{
L.length = 0;
}
//判断线性表是否为空
bool ListEmpty(SqList L)
{
if (L.length == 0)
return true;
else
return false;
}
//求出线性表长度
int ListLength(SqList L)
{
return L.length;
}
//向线性表指定位置插入一个新元素
bool ListInsert(SqList &L, int pos, ElemType item)
{ //pos为插入的(逻辑)位置,item为待插入的数据元素
int i;
if (L.length == MaxSize) { //判表满
cout << "顺序表满,无法插入!" << endl;
return false;
}
if (pos < 1 || pos > L.length + 1) { //判位置
cout << "插入位置无效!" << endl;
return false;
}
for (i = L.length - 1; i >= pos - 1; i--) //向后移动元素
L.data[i + 1] = L.data[i];
L.data[pos - 1] = item; //插入
L.length++; //表长增一
return true;
}
//从线性表中删除指定位置的元素
bool ListDelete(SqList &L, int pos, ElemType &item)
{ //pos为删除的(逻辑)位置,用item返回被删元素
int i;
if (ListEmpty(L)) { //判表空
cout << "顺序表为空表,无法删除!" << endl;
return false;
}
if (pos < 1 || pos > L.length) { //判位置
cout << "删除位置无效!" << endl;
return false;
}
item = L.data[pos - 1]; //删除元素前,把元素的值通过指针传递给外部,备用
for (i = pos; i < L.length; i++) //向前移动元素
L.data[i - 1] = L.data[i];
L.length--; //表长减一
return true;
}
//获取顺序表中指定位置上的数据元素
bool GetElem(SqList L, int pos, ElemType &item)
{ //pos为指定位置,item用于返回找到的数据元素
if (ListEmpty(L))
return false;
if (pos < 1 || pos > L.length) {
cout << "位置无效" << endl;
return false;
}
item = L.data[pos - 1]; //把元素的值通过指针传递给外部
return true;
}
//从线性表中查找元素,返回第一个与指定值匹配元素位置
int Find(SqList L, ElemType item)
{ //item为待查找的数据元素
int i = 0; // i表示当前查找的位置,从头开始
if (ListEmpty(L)) {
cout << "顺序表为空表,无法查找!" << endl;
return 0;
}
//从头到尾比较线性表中的元素,当未超出线性表的末尾,且未找到时,i向后移
while (i < L.length && L.data[i] != item)
i++;
if (i < L.length) //如果未超出线性表的末尾,说明找到
return i + 1; //返回逻辑位置
else
return 0; //超出线性表的末尾,则说明找不到
}
//遍历输出线性表
void TraverseList(SqList L)
{
int i;
for (i = 0; i < L.length; i++) //从头到尾输出线性表的每一个元素
cout << L.data[i] << " ";
cout << endl;
}