文章目录
预备知识
数据结构三要素
1.数据的逻辑结构
逻辑结构是指数据元素之间的逻辑关系,即从逻辑关系上描述数据,分为线性结构与非线性结构两大类。
2.数据的存储结构
存储结构是指数据结构在计算机中的表示(又称映像),也称为物理结构。数据的存储结构是逻辑结构用计算机语言的实现。主要有:顺序存储、链式存储、索引存储和散列存储。
3.数据的运算
施加在数据上的运算包括运算的定义和实现。
运算的定义是针对逻辑结构的,指出运算的功能。
运算的实现是针对存储结构的,指出运算的具体操作步骤。
注: 在专栏中,利用C语言去实现数据结构,实质是去完成表达某种逻辑结构的存储结构,这种实现就是运算的实现,即针对数据的具体操作过程。
线性表
线性表是具有相同数据类型的若干个数据元素的有限序列。其关键操作有:初始化表,按值查找,按位查找,删除,插入,销毁等操作。
正文
顺序表
线性表的顺序存储又称为顺序表,它是用一组地址连续的存储单元,依次存储线性表中的数据元素,从而使得逻辑上相邻的两个元素在物理位置上也是相邻的。线性表是逻辑结构,而顺序表是其存储结构。
存储描述:
静态分配内存:
const int Maxsize = 100;//定义表格的最大长度
//ElemType表示存储元素的类型
typedef struct{
ElemType data[MaxSize];//顺序表中的元素
int length;//顺序表的当前长度
}Sqlist;
在静态分配内存时,由于数组的大小和空间事先已经固定,一旦空间占满,再加入新的数据将溢出,就会导致程序奔溃。为了解决这个问题,我们可以考虑动态分配内存。例如在第零篇可变数组中就运用了这一思想。
动态分配内存:
const int Initsize = 100//表的初始长度
typedef struct{
ElemType *data;//指示动态分配数组的指针
int MaxSize,length;//数组的最大容量和当前元素个数
}Seqlist;
顺序表的基本操作:
以下操作皆以动态分配内存的情况为例
且设定表中元素类型为int
1.创建顺序表
Seqlist seqlist_create(int Initsize){
Seqlist L;
L.MaxSize = Initsize;
L.length = 0;
L.data = (int*)malloc(sizeof(int)*Initsize);
return L;
}
2.扩展顺序表
当表中当前元素个数length
等于最大容量MaxSize
时,再向表中插入元素时则需要扩展顺序表容量。
void seqlist_inflate(Seqlist *L, int more_size){
//重新开辟一块内存,用作扩展之后的表的空间
int *p = (int*)malloc(sizeof(int)*(L->MaxSize + more_size));
int i;
for(i=0; i<L->length; ++i)//将表中元素复制到新内存中去
p[i] = L->data[i];
free(L->data);//释放掉旧内存空间
L->data = p;
L->MaxSize += more_size;//更改表的最大容量值
}
3.插入元素
//将e插入顺序表中第i个位置,即下标i-1处
int seqlist_insert(Seqlist *L, int i, int e){
if(i<1 || i>(L->length)+1)//插入的合法位置区间为[1,length+1]
return 0;
if(L->length >= L->MaxSize)//内存空间被用尽,则需要扩展顺序表
seqlist_inflate(L, BlockSize);
int j;
for(j=L->length; j>=i; --j)//将第i个元素及之后的元素后移
L->data[j] = L->data[j-1];
L->data[i-1] = e;
L->length++;
return 1;
}
4.删除元素
//删除顺序表中第i个元素
int seqlist_delete(Seqlist *L, int i, int *e){
if(i<1 || i>L->length)//判断要删除的位置是否合法
return 0;
int j;
*e = L->data[i-1];//将被删除的元素记录下来
for(j=i; j<L->length; ++j)//将i位置之后的所有元素向前移动一位
L->data[j-1] = L->data[j];
L->length--;
return 1;
}
5.按值查找
//查询首个元素的值为e的位置
int seqlist_found_locate(Seqlist *L, int e){
int i;
for(i=0; i<L->length; ++i){
if(L->data[i] == e)
return i+1;
}
return 0; //返回0则表示该元素不在表中
}
6.销毁顺序表
使用完顺序表后,我们需要清空这一段内存空间
void seqlist_free(Seqlist *L){
free(L->data);
L->data = NULL;
L->MaxSize = 0;
L->length = 0;
}
可执行程序实例
将上面介绍过的所有操作结合起来,展示一个完整的顺序表程序。
创建一个初始容量MaxSize=5
的顺序表,将所有空间填满后,在继续完成添加元素(添加过程中,表格容量继续扩展),删除元素,按值查找等操作。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
const int BlockSize = 5;//每次扩展的长度
typedef struct{
int *data;//指示动态分配数组的指针
int MaxSize, length;//数组的最大容量和当前元素个数
} Seqlist;
Seqlist seqlist_create(int Initsize){
Seqlist L;
L.MaxSize = Initsize;
L.length = 0;
L.data = (int*)malloc(sizeof(int)*Initsize);
return L;
}
void seqlist_inflate(Seqlist *L, int more_size){
//重新开辟一块内存,用作扩展之后的表的空间
int *p = (int*)malloc(sizeof(int)*(L->MaxSize + more_size));
int i;
for(i=0; i<L->length; ++i)//将表中元素复制到新内存中去
p[i] = L->data[i];
free(L->data);//释放掉旧内存空间
L->data = p;
L->MaxSize += more_size;//更改表的最大容量值
printf("内存空间不足,扩展完成,当前顺序表最大容量为%d\n", L->MaxSize);
}
//将e插入顺序表中第i个位置,即下标i-1处
int seqlist_insert(Seqlist *L, int i, int e){
if(i<1 || i>(L->length)+1)//插入的合法位置区间为[1,length+1]
return 0;
if(L->length >= L->MaxSize)//内存空间被用尽,则需要扩展顺序表
seqlist_inflate(L, BlockSize);
int j;
for(j=L->length; j>=i; --j)//将第i个元素及之后的元素后移
L->data[j] = L->data[j-1];
L->data[i-1] = e;
L->length++;
return 1;
}
//删除顺序表中第i个元素
int seqlist_delete(Seqlist *L, int i, int *e){
if(i<1 || i>L->length)//判断要删除的位置是否合法
return 0;
int j;
*e = L->data[i-1];
for(j=i; j<L->length; ++j)//将i位置之后的所有元素向前移动一位
L->data[j-1] = L->data[j];
L->length--;
return 1;
}
//查询首个元素的值为e的位置
int seqlist_found_locate(Seqlist *L, int e){
int i;
for(i=0; i<L->length; ++i){
if(L->data[i] == e)
return i+1;
}
return 0; //返回0则表示该元素不在表中
}
void seqlist_free(Seqlist *L){
free(L->data);
L->data = NULL;
L->MaxSize = 0;
L->length = 0;
}
int main(int argc, char const *argv[])
{
int Initsize, flag;
printf("请输入顺序表的初始最大容量:");
scanf("%d",&Initsize);
Seqlist L = seqlist_create(Initsize);
int i, num;
for(i=0; i<L.MaxSize; ++i){
printf("在第%d位插入数字:", i+1);
scanf("%d", &num);
seqlist_insert(&L, i+1, num);
}
printf("\n请在任意位置插入元素,输入-1即可停止插入\n");
int locate;
while(1){
printf("输入要插入元素的位置: ");
scanf("%d", &locate);
if(locate==-1){
printf("插入操作终止\n");
break;
}
printf("输入第%d个位置要插入的元素:", locate);
scanf("%d", &num);
if(seqlist_insert(&L, locate, num))
printf("插入成功\n");
else{
printf("插入失败,请在[1,%d]内插入元素", L.length+1);
}
}
printf("\n进入删除操作,输入-1即可停止删除\n");
while(1){
printf("请输入要删除的元素位置:");
scanf("%d", &locate);
if(locate==-1){
printf("删除操作终止\n");
break;
}
int e;
if(seqlist_delete(&L, locate, &e))
printf("成功删除第%d位上的元素%d\n", locate, e);
else{
printf("删除失败,请在[1,%d]内删除元素", L.length);
}
}
printf("\n进入按值查找,当查找的数值不存在顺序表内即终止查询\n");
printf("请输入要查找的元素值:");
while(1){
scanf("%d", &num);
flag = seqlist_found_locate(&L, num);
if(!flag){
printf("%d不存在于顺序表内,查找结束\n", num);
break;
}
else
printf("%d在顺序表中第%d个位置,查找成功,可输入其他元素值:", num, flag);
}
printf("\n所有操作完成,释放顺序表内存空间\n");
seqlist_free(&L);
return 0;
}