数据结构与算法:线性表之顺序表
最近开始学习数据结构与算法,可能是因为刚开始接触,觉得很迷茫,学得非常不顺利,这篇文章只是一些简单的总结。如有错误,欢迎私信!
一、数据结构的一些基本概念
1、数据:数据是信息的载体,是描述客观事物属性的数、字符以及所有能输入到计算机中并被程序识别和处理的符号的集合。
2、数据元素:数据元素是数据的基本单位,通常作为一个整体进行考虑和处理。一个数据元素可由若干数据项组成,数据项是构成数据元素的不可分割的最小单位。例如,学生记录就是一个数据元素,它由学号、姓名、性别等数据项组成。
3、数据对象:数据对象是具有相同性值的数据元素的集合,是数据的一个子集。
4、数据类型:数据类型是一个值的集合和定义再此集合上的一组操作的总称。
1)原子类型。其值不可再分的数据类型。如bool 和int 类型。
2)结构类型。其值可以再分解为若干成分(分量)的数据类型。
3)抽象数据类型。抽象数据组织及与之相关的操作。
5、数据结构:数据结构是相互之间存在一种或多种特定关系的数据元素的集合。
6、时间复杂度:一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数f(n),算法的时间量度记作T(n)=O(n),它表示随问题规模n的增大而增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐近时间复杂度,简称时间复杂度。
7、空间复杂度:算法的空间复杂度S(n)定义为该算法所耗费的存储空间,它是问题规模n的函数。记为S(n)=O(g(n))。
二、线性表中的顺序表
定义:线性表是具有相同数据类型的n(n>0)个数据元素的有限序列,其中n为表长,当n=0时线性表是一个空表。
在线性表的顺序存储结构(即数组)中,其任意一个元素的存储位置可以通过计算得到,因此其数据读取的时间复杂度为 O(1)。
(一)、顺序表的分配方式
1、静态分配
//顺序表的实现——静态分配储存地址
/*
编译环境:
win10专业版
DEV C++ 5.11
TDM-GCC 4.9.2 64bit
*/
#include<stdio.h>
#define MaxSize 10 //定义表的最大长度
//创建表
typedef struct{
int data[MaxSize];//用静态的"数组"存放数据元素
int length; //顺序表的当前长度
}SqList; //顺序表的类型定义(静态分配方式)
//初始化
void InitList(SqList L){
L.length = 0;
printf("初始化成功\n");
}
int main(){
SqList L;//声明一个顺序表
InitList(L);//初始化一个顺序表
for(int j = 0;j < MaxSize;j++){
L.data[j]= j;
}
for(int i = 0;i < MaxSize; i++){
printf("data[%d]=%d\n",i,L.data[i]);
}
return 0;
}
2、动态分配
//顺序表的实现——静态分配储存地址
/*
编译环境:
win10专业版
DEV c++ 5.11
TDM-GCC 4.9.2 64bit
*/
/*
编译环境:
win10专业版
DEV c++ 5.11
TDM-GCC 4.9.2 64bit
*/
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 5
//线性表储存空间的分配增量
//创建表
typedef struct{
int *data; //存储空间基址
int length; //当前表长
int listsize;
//当前分配的存储容量
}SqList;
void CreateList(SqList *L){
//ElemType的类型根据实际情况而定,这里假定为in
//L->data = (ElenType *)malloc(InitSize * sizeof(ElemType);
L->data = (int *)malloc(MaxSize* sizeof(int));
if(!L->data)
return;
L->listsize = MaxSize;
printf("请输入这个表的长度:");
printf("\n");
scanf("%d",&L->length);
printf("请输入%d个数字\n",L->length);
for(int i = 1;i <=L->length;i++){
scanf("%d",&L->data[i]);
}
printf("初始化成功!\n");
}
void listprintf(SqList *L){
printf("表中的数据为:");
for(int i = 1;i <= L->length;i++){
printf("%d ",L->data[i]);
}
printf("\n");
}
int main(){
SqList L;
CreateList(&L);
listprintf(&L);
return 0;
}
(二)、顺序表的基本操作
1、构造一个空的线性表
//构造一个空的线性表
int InitList(SqList *L){
L->data = (int *)malloc( MaxSize* sizeof(int)); //首元素的地址
if(!L->data){ //如果存储空间分配失败,L.data为NULL
printf("存储空间分配失败\n");
return 0;
}
L->length = 0; //当前线性表为空表,即线性表长度为0
L->listsize = MaxSize; //给线性表分配初始容量
printf("一个空的线性表已经构建成功\n"); //输出空线性表构建成功的提示消息
return 1;
}
2、插入操作
//插入某个元素
void Listinsert(SqList *L){
int i;int e;
printf("输入要插入位置及元素\n");
scanf("%d%d",&i,&e);
printf("在顺序线性表中第%d个位置之前插入新的元素%d。\n",i,e);
//在顺序线性表L中第i个位置之前插入新的元素e
if(i<1||i>L->length+1)return;
// 1<=i<=listlength(L)+1;
int *p,*q;
q=&(L->data[i-1]);
for(p=&(L->data[L->length-1]);p >= q;--p) *(p+1)=*p;
*q=e;
++L->length;
return ;
}
3、销毁操作
//删除线性表某一位置的元素
int DeleteList(SqList *L){
int *p,*q;
int i;
printf("请输入要删除的元素的位置:\n");
scanf("%d",&i);
if(i < 1 || i > L->length){ //如果要删除的位置不合法
printf("请输入一个有效数字\n");
return 0;
}
p = &(L->data[i - 1]); //p为被删除元素的位置
q = L->data + L->length - 1; //将表尾元素的位置赋值给q
for(++p;p <= q;p++)
*(p - 1) = *p; //被删除的元素之后的元素全部左移
--L->length; //表长减1
printf("第%d个元素删除成功\n",i);
return 1;
}
4、查找操作
1)按值查找
//获取线性表某一位置对应的元素
int GetElem(SqList *L){
int Num,index;
printf("请输入要查找的元素:\n");
scanf("%d",&index);
int i;
for(i = 0;i <L->length;i++){
if(index==L->data[i]){
printf("该元素的位置是第%d个元素\n",i);
return 1;
}
}
if(index != L->data[i])
printf("这个元素不存在!");
return 1;
}
2)按位查找
//获取线性表某一位置对应的元素
int GetElem(SqList *L){
int Num,index;
printf("请输入要查找的位置:\n");
scanf("%d",&index);
if(index <= 0 || index > L->length){ //如果要获取元素的位置是否出界
printf("请输入一个有效的数字\n");
return 0;
}
else
Num = L->data[index - 1];
printf("第%d个位置的元素为:%d\n",index,Num);
return 1;
}
5、清除操作
//对线性表进行重置
int ClearList(SqList &L){
if(L->data){ //如果线性表存在
L->length = 0; //将线性表的元素个数重置为0
printf("线性表已重置\n");
return 1;
}
else
printf("线性表不存在,无法重置\n");
return 1;
}
6、删除操作
//对线性表进行销毁
int DistoryList(SqList *L){
if(!L->data){
printf("您还未建立线性表,请先建立线性表\n");
return 0;
}
free(L->data); //使用free函数,将之前动态分配的内存还给系统
L->data = NULL; //重置elem的值为Null
L->length = 0; //将线性表的元素个数重置为0
L->listsize = 0; //将线性表的存储容量重置为0
printf("线性表已经销毁\n");
return 1;
}
7、判断是否为空的操作
//判断线性表是否为空
Status ListEmpty(SqList *L){
if(L->data){ //判断线性表是否为空的前提是线性表存在,当首元素地址即L.elem存在时说明线性表存在
if(L->length != 0){ //如果线性表中元素为0,即L.length的值为0时说明线性表是空表
printf("线性表不是空表\n");
return 0;
}
else
printf("线性表是空表\n");
return 1;
}
else
printf("线性表不存在,无法判断\n");
return 1;
}
8、获取线性表的长度
//获取线性表的长度
Status ListLength(SqList *L){
if(L->data){ //判断当前线性表存在
int K;
K = L->length; //将线性表的元素个数赋值给K
printf("线性表长度为%d\n",K);
return 1;
}
else
printf("线性表不存在,无法判断\n");
return 1;
}
(三)、源码
/*
编译环境:
win10专业版
DEV c++ 5.11
TDM-GCC 4.9.2 64bit
*/
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 5
#define elsesize 10
//线性表储存空间的分配增量
//创建表
typedef struct{
int *data; //存储空间基址
int length; //当前表长
int listsize;
//当前分配的存储容量
}SqList;
//构造一个空的线性表
int InitList(SqList *L){
L->data = (int *)malloc( MaxSize* sizeof(int)); //L.elem为首元素的地址
if(!L->data){ //如果存储空间分配失败,L.elem为NULL
printf("存储空间分配失败\n");
return 0;
}
L->length = 0; //当前线性表为空表,即线性表长度为0
L->listsize = MaxSize; //给线性表分配初始容量
printf("一个空的线性表已经构建成功\n"); //输出空线性表构建成功的提示消息
return 1;
}
//对线性表进行赋值
int ValueList(SqList *L){
int i,j;
printf("请输入线性表元素的个数:");
scanf("%d",&i);
if(i > L->listsize) //如果当要输入的元素个数大于内存大小时
{
while(1) //一直开辟新空间,直到开辟的空间大于需要的空间为止
{
if(i > L->listsize){
L->data = (int *)realloc(L->data, elsesize * sizeof(int));
L->listsize += elsesize;
/*realloc()函数:重新分配空间
参数:原空间基址,现需空间大小
返回:1.成功:新空间地址(本质上是一个数值)
2.失败:Null
*/
}
else
break;
}
}
printf("请输入元素:\n");
for(j = 0;j < i;j++){
scanf("%d",&L->data[j]);
}
L->length = i; //赋值完成后,修改并保存线性表的长度
printf("赋值成功\n");
return 1;
}
void listprintf(SqList *L){
printf("表中的数据为:");
for(int i = 0;i < L->length;i++){
printf("%d ",L->data[i]);
}
printf("\n");
}
//插入某个元素
void Listinsert(SqList *L){
int i;int e;
printf("输入要插入位置及元素\n");
scanf("%d%d",&i,&e);
printf("在顺序线性表中第%d个位置之前插入新的元素%d。\n",i,e);
//在顺序线性表L中第i个位置之前插入新的元素e
if(i<1||i>L->length+1)return;
// 1<=i<=listlength(L)+1;
int *p,*q;
q=&(L->data[i-1]);
for(p=&(L->data[L->length-1]);p >= q;--p) *(p+1)=*p;
*q=e;
++L->length;
return ;
}
//删除线性表某一位置的元素
int DeleteList(SqList *L){
int *p,*q;
int i;
printf("请输入要删除的元素的位置:\n");
scanf("%d",&i);
if(i < 1 || i > L->length){ //如果要删除的位置不合法
printf("请输入一个有效数字\n");
return 0;
}
p = &(L->data[i - 1]); //p为被删除元素的位置
q = L->data + L->length - 1; //将表尾元素的位置赋值给q
for(++p;p <= q;p++)
*(p - 1) = *p; //被删除的元素之后的元素全部左移
--L->length; //表长减1
printf("第%d个元素删除成功\n",i);
return 1;
}
//获取线性表某一位置对应的元素
int GetPlace(SqList *L){
int Num,index;
printf("请输入要查找的位置:\n");
scanf("%d",&index);
if(index <= 0 || index > L->length){ //如果要获取元素的位置是否出界
printf("请输入一个有效的数字\n");
return 0;
}
else
Num = L->data[index - 1];
printf("第%d个位置的元素为:%d\n",index,Num);
return 1;
}
//获取线性表某一位置对应的元素
int GetElem(SqList *L){
int Num,index;
printf("请输入要查找的元素:\n");
scanf("%d",&index);
int i;
for(i = 0;i <L->length;i++){
if(index==L->data[i]){
printf("该元素的位置是第%d个元素\n",i);
return 1;
}
}
if(index != L->data[i])
printf("这个元素不存在!");
return 1;
}
//对线性表进行重置
int ClearList(SqList *L){
if(L->data){ //如果线性表存在
L->length = 0; //将线性表的元素个数重置为0
printf("线性表已重置\n");
return 1;
}
else
printf("线性表不存在,无法重置\n");
return 1;
}
//对线性表进行销毁
int DistoryList(SqList *L){
if(!L->data){
printf("您还未建立线性表,请先建立线性表\n");
return 0;
}
free(L->data); //使用free函数,将之前动态分配的内存还给系统
L->data = NULL; //重置elem的值为Null
L->length = 0; //将线性表的元素个数重置为0
L->listsize = 0; //将线性表的存储容量重置为0
printf("线性表已经销毁\n");
return 1;
}
//获取线性表的长度
int ListLength(SqList *L){
if(L->data){ //判断当前线性表存在
int K;
K = L->length; //将线性表的元素个数赋值给K
printf("线性表长度为%d\n",K);
return 1;
}
else
printf("线性表不存在,无法判断\n");
return 1;
}
//判断线性表是否为空
int ListEmpty(SqList *L){
if(L->data){ //判断线性表是否为空的前提是线性表存在,当首元素地址即L.elem存在时说明线性表存在
if(L->length != 0){ //如果线性表中元素为0,即L.length的值为0时说明线性表是空表
printf("线性表不是空表\n");
return 0;
}
else
printf("线性表是空表\n");
return 1;
}
else
printf("线性表不存在,无法判断\n");
return 1;
}
int main(){
SqList L;
InitList(&L);//初始化一个空表
ValueList(&L);//赋值
listprintf(&L);//打印
DeleteList(&L);//删除元素
listprintf(&L);//打印
GetPlace(&L);//按位查找
GetElem(&L);//按值查找
ListLength(&L);//获取其长度
ClearList(&L);//清空表
ListEmpty(&L);//判断是不是空表
DistoryList(&L);//销毁表
ListEmpty(&L);//判断是不是空表
return 0;
}
三、总结
这里只是我的一些总结,可能不太完整,所以最后附上一些大神的博客方便大家学习和理解: