目录
一、线性表的定义和基本操作
1.线性表的定义
2.线性表的基本操作
“带回来”解释:
在main函数中传入x=1,但是在test函数中又改成了1024,实际上在内存中这个等于1024的是另一个x,然后在main函数中再次输出的时候输出的还是1,因为根本就没有改变x=1这个内存中的x的值
二、顺序表的定义
1.顺序表的定义
2.顺序表的实现
(1)、静态分配
在执行SqList L的时候就会给顺序表分配他所需要的空间
如果不设置默认值的话后两个数就会出现很奇怪的值
产生奇怪值的原因是在这个存储空间分配给这个顺序表之前存储了其他数据,所以会有脏数据,但是为什么说考研省略设置默认值的步骤,这是因为我们这里用的fo循环打印全部的内存本来就是违规的,而应该按照顺序表的长度打印。
在声明顺序表时,刚开始把他的length值设为0是必须做的。
(2)、动态分配
*data指针指向了顺序表中第一个数据元素的位置
malloc函数申请一整片连续的存储空间,free函数用来释放空间。
malloc函数会返回指向这一整片存储空间开始地址的一个指针。
分析动态实现的背后过程:
声明顺序表的数据元素类型是int类型,data指向数据表中的第一个元素。
然后实现一个InitList函数用于初始化一个动态分配方式实现的顺序表
然后实现一个函数拥有动态的增加顺序表的长度。
最后在main函数里调用相关的操作。
执行完这句后计算机会在内存中开辟这样一小块空间。
执行完第二句代码之后data应该指向了malloc函数申请的空间的第一个位置
之后这里写的main函数省略了将数据填入顺序表的过程
然后执行增加动态数组长度。
然后开辟了新的空间,现在可以多存五个数据
因为malloc开辟了新的空间,之前存的数据都不在新的空间,所以需要一个for循环把数据存入新的空间。
由于增加了五个空间,所以要把最大空间增大5,最后调用free函数把之前创建的已经被新空间代替的p空间释放掉。
代码演示:
#include<stdio.h>
#include<stdlib.h>//malloc、free函数的头文件
#define InitSize 3 //默认的最大长度
typedef int ElemType;
//动态分配
typedef struct {
//data是指示动态分配数组的指针,指向了顺序表中第一个元素的位置
ElemType* data;
int MaxSize;//顺序表的最大容量
int length;//顺序表的当前长度
}SeqList;//顺序表的类型定义
//初始化一个动态分配方式实现的顺序表
void InitList(SeqList& L) {
/*
用malloc函数申请一片连续的存储空间
malloc函数会返回指向这一整片存储空间开始地址的一个指针
这个返回的指针需要强转为你定义的数据元素类型指针
malloc函数的参数需要指明分配多大的连续内存空间
InitSize等于10时,分配的内存空间为10乘以sizeof(int)=10×4=40
*/
L.data = (int*)malloc(InitSize * sizeof(int));
L.length = 0;
L.MaxSize = InitSize;
}
/*
实现一个函数用于动态的增加顺序表的长度
&L获取L的地址
*/
void IncreaseSize(SeqList& L, int len) {
int* p = L.data;
L.data = (int*)malloc((L.MaxSize + len) * sizeof(int));
for (int i = 0; i < L.length; i++)
{
L.data[i] = p[i];//将数据复制到新区域
}
L.MaxSize = L.MaxSize + len;//顺序表最大长度增加len
free(p);//释放原来的内存空间
}
//再main函数里调用相关的操作
int main() {
SeqList L;//声明一个顺序表
InitList(L);//初始化顺序表
//往顺序表里随便加几个元素
L.data[0] = 1;
L.data[1] = 2;
L.data[2] = 3;
L.length = 3;
//扩大顺序表的容量
IncreaseSize(L, 5);
//遍历顺序表
for (int i = 0; i < L.length; i++)
{
printf("%d\n",L.data[i]);
}
return 0;
}
3.顺序表的插入删除
(1)、插入
要把C插入,就要把后边的全都往后移一格。
当在位置9插入3时,运行代码之后3会插到data[8],但是位置7和8都是空的,
所以这个代码不够健壮
所以插入的比较好的代码应该写成:
代码演示:
#include<stdio.h>
#define MaxSize 3 //定义最大长度
typedef struct {
int data[MaxSize]; //用静态“数组”来存数据元素
int length; //顺序表的当权长度
}SqList; //属性表的类型定义
bool ListInsert(SqList& L, int i, int e) {
if (i<1 || i>L.length+1) {//判断i的范围是否有效
printf("因为i范围无效插入失败!\n");
return false;
}
if (L.length >= MaxSize) //当前存储空间已满
{
printf("因为存储空间已满插入失败!\n");
return false;
}
for (int j = L.length; j >= i; j--) //将第i个元素及之后的元素后移
{
L.data[j] = L.data[j - 1];
}
L.data[i - 1] = e;//再位置i处放e
L.length++;//长度加1
return true;
}
void main() {
SqList L;
L.data[0] = 0;
L.data[1] = 1;
L.data[2] = 2;
L.length = 3;
ListInsert(L,3,8);
printf("当前顺序表的内容为:\n");
for (int i = 0; i < L.length; i++)
{
printf("L.data[%d]=%d\n",i,L.data[i]);
}
}
插入操作的时间复杂度:
(2)、删除
删除之后需要把后边的全部往前移一位,同时要把length的值减一
代码实现:
&L:是删除哪个顺序表
i:要删除第几个数据元素
&e:用这个元素把此次删除的数据元素返回
代码演示:
#include<stdio.h>
#define MaxSize 10
typedef struct {
int data[MaxSize];
int length;
}SqList;
void InitList(SqList &L) {
L.length = 0;
}
bool ListDelete(SqList& L, int i, int& e) {
if (i<1||i>L.length) //判断i的范围是否有效
{
return false;
}
e = L.data[i - 1]; //将被删除的元素赋值给e
for (int j = i; j < L.length; j++)//将第i个元素前移
{
L.data[j - 1] = L.data[j];
}
L.length--; //线性表长度减一
return true;
}
int main() {
SqList L; //声明一个顺序表
InitList(L); //初始化顺序表
//插入几个元素
L.data[0] = 1;
L.data[1] = 2;
L.data[2] = 3;
L.data[3] = 4;
L.length = 4;
int e = -1; //用变量e把删除的元素带回来
if (ListDelete(L, 3, e)) {
printf("已删除第3个元素,删除元素的值为=%d\n",e);
}
else
{
printf("位序i不合法,删除失败\n");
}
for (int i = 0; i < L.length; i++)
{
printf("L[%d]=%d\n",i,L.data[i]);
}
}
删除操作的时间复杂度:
4.顺序表的查找
1.按位查找
(1)静态分配
(2)动态分配
按位查找的时间复杂度:
2.按值查找
结构类型的数据元素不能这样
按值查找的时间复杂度: