算法与数据结构
线性表的定义及实现
定义
用数据元素的有限序列表示,由n(n>=0)个数据元素a1,a2,…,ai-1,ai.ai+1,…,an组成的有限并且有序的序列。
a1为线性起点,下标是元素的序号,表示元素在表中的位置,ai-1是ai的直接前趋,ai+1 是ai的直接后继 an为线性终点
关键点: 存在有序关系,必须是按一定序列排列
基本操作
函数 | 作用 |
---|---|
List MakeEmpty() | 初始化一个新的空线性表L |
ElementType FindKth(int K,List L) | 根据指定的为序K,返回相应元素 |
int Find(ElementType X,List L) | 已知X,返回线性表L中与X相同的第一个元素的相应位序;若不存在则返回空 |
void Insert(ElementType X,int i,List L) | 在指定位序i插入一个新元素X |
void Delete(int i,List L) | 删除指定位序i的元素 |
int Length(List L) | 返回线性表L的长度 |
这些操作函数都需要自己实现,接下来将会讲到
线性表的顺序存储结构
- 按顺序方式存储数据元素称为顺序表
- 顺序表示是把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构
- 假设线性表的每个元素占用l个存储单元,线性表中第i+1个数据元素的存储位置LOC(ai+1)和第i个数据元素的存储位置LOC(ai)之间满足下列关系:
LOC(ai+1) = LOC(ai)+l - 线性表第i个数据元素ai的存储位置为:
*LOC(ai) = LOC(ai)+(i-1)l
所有元素均按一定的顺序排列,可以通过上面这个公式直接获得元素的地址,如下图
顺序表的特点: 以物理位置相邻表示逻辑关系,任一元素均可随机存取
线性表的实现
定义一个线性结构
用结构体来定义一个线性表,代码如下:
#include <iostream>
#define MAXSIZE 1000001
using namespace std;
typedef struct{
int Data[MAXSIZE];
int Last; // 当前线性表最后一个元素的下标
}LNode;
typedef LNode *List;
List L;
int main() {
return 0;
}
在这个结构中定义了一个一维数组来存放线性表的数据,同时定义了一个整型变量来记录当前线性表最后一个元素的下标。同时应满足 Last<MAXSIZE,这是因为在后续对线性表的操作中会插入数据,而数组的长度是不可变的,所以将线性表的长度设为小于一维数组的长度,方便后续插入等操作,延长线性表
访问下标为i的元素:L->Data[i];
获取线性表的长度: L->Last+1;
初始化(建立一个空的顺序表) MakeEmpty()
定义List MakeEmpty()函数来初始化一个新的空线性表L
List MakeEmpty(){
List L;
L= (List)malloc(sizeof(LNode));
L->Last=-1;
return L;
}
在这个函数中首先定义一个List变量L,再为它分配一个大小与LNode相同的存储空间。注意这里使用完malloc函数后要强制转换一下。 线性表长度先赋值为-1。
查找元素
在线性表中查找一个元素所在的位置,函数如下,传入参数为要查找的元素,以及顺序表
// 给int类型取一个别名,之后直接用别名定义整型变量的线性表元素
int Find(ElementType x,List L){
int i=0;
while(i<=L->Last && L->Data[i]!=x){
i++; // 如果当前这个i没有到最后一个元素,
//并且当前元素不等于要找的元素就i++
}
if(i>L->Last) return ERROR; // i>L->Last就是没有找到元素x
else return i; //找到元素x,返回下标
}
插入元素
在线性表中插入元素主要分为三步:
- 获得元素要插入的位置i
- 对第i个元素后面的元素进行向右移动一个位置的操作,留出一个位置
- 向留出的位置中插入给定的元素
- 修改Last指针,使线性表长度+1
这么做的主要是因为C++的数组的内存存储关系,存储地址是连续不可变的,能变的只能是地址上存的数据。
代码如下:
bool Insert(ElementType X,int i,List L){
if(L->Last ==MAXSIZE-1){
printf("表已存满,无法再插入元素");
return false;
}
if(i<1 || i>L->Last+2){
printf("插入的位置不合法,无法完成插入操作");
return false;
}
for(int j=L->Last;j>=i-1;j--){
L->Data[j+1]=L->Data[j]; //将插入位置i之后的元素向后移动
}
L->Data[i-1]=x; //插入新元素
L->Last++; // 线性表长度+1,以指向最后一个元素
return true;
}
删除元素
删除操作可以理解为插入操作的一个逆过程,步骤如下:
- 找到要删除元素的位置i
- 将第i个元素后面的所有元素都向前移动
代码如下:
bool Delete(int i,List L){
if(i<1 || i>L->Last+1){ //检查要删除的位置是否合法
printf("第%d个元素不存在",i);
return false;
}
for(int j=i;j<=L->Last;j++){
L->Data[j-1]=L->Data[j];
//将第i个元素后面的元素向前移动一格
}
L->Last--; //让Last指向最后一个元素
return true;
}
完整代码:
#include <iostream>
#include <stdio.h>
#include <malloc.h>
#include <iostream>
#define MAXSIZE 1000001
using namespace std;
typedef struct{
int Data[MAXSIZE];
int Last; // 当前线性表最后一个元素的下标
}LNode;
typedef LNode *List;
List L;
List MakeEmpty(){
List L;
L= (List)malloc(sizeof(LNode));
L->Last=-1;
return L;
}
typedef int ElementType;
// 给int类型取一个别名,之后直接用别名定义整型变量的线性表元素
int Find(ElementType x,List L){
int i=0;
while(i<=L->Last && L->Data[i]!=x){
i++; // 如果当前这个i没有到最后一个元素,
//并且当前元素不等于要找的元素就i++
}
if(i>L->Last) return -1; // i>L->Last就是没有找到元素x
else return i; //找到元素x,返回下标
}
bool Insert(ElementType x,int i,List L){
if(L->Last ==MAXSIZE-1){
printf("表已存满,无法再插入元素");
return false;
}
if(i<1 || i>L->Last+2){
printf("插入的位置不合法,无法完成插入操作");
return false;
}
for(int j=L->Last;j>=i-1;j--){
L->Data[j+1]=L->Data[j]; //将插入位置i之后的元素向后移动
}
L->Data[i-1]=x; //插入新元素
L->Last++; // 线性表长度+1,以指向最后一个元素
return true;
}
bool Delete(int i,List L){
if(i<1 || i>L->Last+1){ //检查要删除的位置是否合法
printf("第%d个元素不存在",i);
return false;
}
for(int j=i;j<=L->Last;j++){
L->Data[j-1]=L->Data[j];
//将第i个元素后面的元素向前移动一格
}
L->Last--; //让Last指向最后一个元素
return true;
}
int main() {
return 0;
}