顺序表
回顾数组
基本概念
1)根据空间分,可分为栈区数组和堆区数组
栈区数组:系统自动管理
堆区数组:我们自己管理malloc/free new/delete
基本操作
节点装的是数据
创建与初始化节点
栈区:int a[4] = {0,1,2,3};
堆区:int *p = (int*)malloc(sizeof(int)*4); free(p);
改、查节点
a.下标运算:[ ]
b.指针运算:*(p+n) = p[n]
增加节点
数组尾部增加
1)数组没空间了,怎么添加?
a.申请时申请足够大的空间
有点浪费空间、用空间换时间
b.动态申请空间(malloc
)
思路:再申请一个更大的空间把之前小空间的数组中的数据复制进来,新数据在后面加
优劣:用时间换空间
空间利用率高,但速度慢(涉及 新的申请空间的过程,又涉及到释放原空间,复制原空间的过程)
2)动态空间申请多大?
每次申请空间的时候,就多申请一些。不必申请复制很多次,提高运行速度
3)申请过程
初始化
a.记录首地址malloc
时记录首地址
b.记录可存储的数据总量,即容量
c.记录已存储的数据总量:数量,下标记录
这三个元素,就可以用结构体装一起,并初始化:
通过函数修改外部变量的值,就要传递变量的地址
要传地址,参数就要定义成对应类型的指针,如下:
#include<stdio.h>
#include<stdlib.h>
struct DynamicArr
{
int* Head; //数组头指针,装首地址
unsigned int Cap;//容量
unsigned int Num;//已存储的数量
};
//定义函数,将结构体传入赋值初始化
void iniArr(struct DynamicArr * pArr) //结构体指针
{
pArr->Head =(int*) malloc(sizeof(int)*pArr->Cap );
pArr->Num = 0; //以后每次添加都加一,Num++
pArr->Cap = 5;
}
int main(void)
{
struct DynamicArr Arr;
iniArr(&Arr);//传地址进行赋值初始化
//释放空间
free(Arr.Head);
system("pause");
return 0;
}
添加元素
添加元素,创建函数封装特定功能
这里要传的是结构体指针(用于指向成员)和增加的数
void Add(struct DynamicArr * pArr, int AddNum) {}
进到函数,先判断容量和数量是否相等,相等即装满。装满就要进行操作来申请空间:
//判断是否装满
if (pArr->Cap == pArr->Num ){}
a.容量变大
//容量变大 一定是先增加空间,再malloc,,不然还是不变
pArr->Cap += 10;
b.申请空间
//容量变大 一定是先增加空间,再malloc,,不然还是不变
pArr->Cap += 10;
//申请指针变量装这个新空间,此时的cap是变大的新空间
int *ptemp = (int*)malloc(sizeof(int*)*pArr->Cap);
c.将原数据赋值进新空间
//将原数据复制新空间
for (unsigned int i = 0; i < pArr->Cap; i++)//从0开始,到容量最大
{
ptemp[i] = pArr->Head[i]; //Head是数组头指针装首地址
}
d.释放原空间
//释放原空间
free(pArr->Head);
e.将数组头指针指向新空间
//将数组头指针指向新空间
pArr->Head = ptemp; //将ptemp的新空间赋给Head
f.Head数组指向最后一个元素
//Head[pArr->Num]是指向最后一个元素 将新数据装入最后
pArr->Head[pArr->Num] = AddNum;
//每增加一个元素,就累加一次
pArr->Num++;//累加元素的数量
g.主函数部分
//调用5次依然不会增加空间,在调用第6次的时候才会增加空间
Add(&Arr, 3);
Add(&Arr, 3);
Add(&Arr, 3);
Add(&Arr, 3);
Add(&Arr, 3);
Add(&Arr, 3);
printf("%u,%u\n",Arr.Cap ,Arr.Num );//输出容量和数量
for (int i = 0; i < Arr.Num;i++)
{
printf("%d",Arr.Head [i]); //输出数组中的元素
}
调用5次输出
5,5
3 3 3 3 3
调用6次输出
15,6
3 3 3 3 3 3
整体代码如下:
#include<stdio.h>
#include<stdlib.h>
struct DynamicArr
{
int *Head; //数组头指针
unsigned int Cap;//容量
unsigned int Num;//已存储的数量
};
//定义函数,将结构体传入赋值
//通过函数修改外部变量的值,就要传递变量的地址了
//要传地址,参数就要定义成对应类型的指针
void iniArr(struct DynamicArr *pArr) //结构体指针
{
pArr->Cap = 5;
pArr->Head = (int*)malloc(sizeof(int)*pArr->Cap);
pArr->Num = 0; //以后每次添加都加一,Num++
}
//参数:一个是结构体指针,一个是要添加的数据
void Add(struct DynamicArr * pArr, int AddNum)
{
//判断是否装满
if (pArr->Cap == pArr->Num )
{
//容量变大 一定是先增加空间,再malloc,,不然还是不变
pArr->Cap += 10; //装满就再申请空间
//申请中间指针变量装这个空间
int *ptemp = (int*)malloc(sizeof(int)*pArr->Cap);
//将原数据复制新空间
for (unsigned int i = 0; i < pArr->Num ; i++)
{
ptemp[i] = pArr->Head[i];
}
//释放原空间
free(pArr->Head );
//将数组头指针指向新空间
pArr->Head = ptemp;
}
//Head[pArr->Num]是指向最后一个元素 将新数据装入最后
pArr->Head[pArr->Num] = AddNum;
pArr->Num++;//累加元素的数量
}
int main(void)
{
struct DynamicArr Arr;
iniArr(&Arr);
//调用
Add(&Arr, 3);
Add(&Arr, 3);
Add(&Arr, 3);
Add(&Arr, 3);
Add(&Arr, 3);
Add(&Arr, 3);
//这里可以封装函数
printf("%u,%u\n",Arr.Cap ,Arr.Num );
for (int i = 0; i < Arr.Num;i++)
printf("%d ",Arr.Head [i]); //输出数组中的元素
free(Arr.Head);
system("pause");
return 0;
}
输出封装
//输出封装
void print(struct DynamicArr *Arr)
{
if (NULL == Arr) //判断是否为NULL,是就返回
{
printf("输出错误\n");
return;
}
printf("%u,%u\n", Arr->Cap, Arr->Num);
for (int i = 0; i < Arr->Num; i++)
{
printf("%d ", Arr->Head[i]); //输出数组中的元素
}
}
//主函数调用
print(&Arr);