顺序表及malloc、calloc、realloc简介介绍

11 篇文章 0 订阅
文章详细介绍了顺序表的定义和实现,包括使用结构体定义顺序表、初始化、尾部插入、删除、打印、旋转、头部插入和删除、查找、位置插入和删除以及销毁等操作。特别强调了动态内存管理的重要性,如malloc、realloc和free的使用,以及防止内存泄漏和动态扩容策略。
摘要由CSDN通过智能技术生成

顺序表

前序,先简单认识一下顺序表的物理图
在这里插入图片描述

1.顺序表的定义

顺序表是在计算机内存中已数组形式保存的线性表

1.1 使用结构体来定义一个顺序表
typedef int SLDateType;

typedef struct SeqList
{
	SLDateType * a;//a定义为指针类型是为了更好的动态扩容
	int size;//目前有多少个元素
	int capacity;//一共有多大的空间
}SeqList;
1.2 初始化顺序表
//初始化结构体顺序表
void SeqListInit(SeqList* ps)
{
	ps->a = (SLDateType*)malloc(sizeof(SLDateType) * 4);//为结构体ps里的指针变量a申请动态空间内存
	if (ps->a == NULL)
	{
		printf("INIT Seqlist Err");//如果申请失败指针变量a的值会为NULL
		return;
	}
	ps->size = 0;//初始化目前元素为0个
	ps->capacity = 4;//动态内存总空间为4,也就是说指针变量a的空间只能存放四个
}

如果这里不用动态申请,而使用静态的,当顺序表存满的时候,静态数组是无法二次扩容的,而把它定义为动态的是可以进行二次或更多次扩容的,唯一注意的是使用完动态内存后, 要记得释放,要不会出现内存泄漏的问题。

1.3 结构体顺序表尾部插入
//结构体尾部插入
void SeqListPushBack(SeqList* ps,SLDateType x)
{
	assert(ps);
	if (ps->size == ps->capacity)
	{
		SeqList* tmp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * ps->capacity * 2);
		if (tmp == NULL)
		{
			printf("realloc err");
			return;
		}
		ps->a = tmp;
		ps->capacity*=2;
	}
	ps->a[ps->size] = x;
	ps->size++;
}

assert简称断言,这里引用他是为了防止你传进来的值为空。
if语句的作用是,判断你目前要插入的动态空间是否已经满了,如果条件符合,将会进行扩容,扩容到原来的二倍,如果扩容成功将会把扩容好的地址赋值给a,并将capacity的空间扩容为2倍,如果扩容失败返回NULL,将会提示报错并结束程序。

动态开辟空间malloc和realloc的区别,以及calloc
首先我们先看一下这三个函数的参数分别是什么
头文件均为 #include <stdlib.h>,返回均值为void*,是为了更方便的转换成自己所需要的值。
在这里插入图片描述
malloc函数的作用是申请一块连续的空间,并且返回,如果申请成功,会返回这块申请好的连续空间,如果申请失败,会返回NULL
在这里插入图片描述

当申请的空间为0时,malloc不会返回空值,且申请好的0个空间也是不可用的。
当用完这段动态内存是,切记要free释放掉,且设置为空,要不会出现内存泄漏和野指针的问题。
在这里插入图片描述
这里简单了解一下free的作用,当使用完动态内存后,需要把所分配的地址内存还给系统,并且设置为空,如果你不释放且不设置为空,就会出现内存泄漏或者野指针的问题,就像你分手后,还不跟人家断了联系,那么下一个女朋友知道后会很麻烦,并且你脑子里的女朋友家地址也得忘记,如果不忘记将会很麻烦。

在这里插入图片描述
realloc函数的作用是将原目标的空间扩容到size大小,可大可小,并且申请的空间大小也是连续的,如果申请空间过大,它会跳过目前的内存,然后重找适合自己内存大小的位置,申请成功后返回这段空间,申请失败后返回NULL
在这里插入图片描述

同样使用完这段动态内存后也是需要free释放的。0

在这里插入图片描述

calloc函数的作用是申请num个size大小的字节空间(为连续空间),并且返回一个指向起始开辟空间的void* 类型的指针。
该函数会对申请的空间的数值做初始化,将每个字节的空间的数值赋值为0。
当空间申请失败时会返回一个空指

1.4顺序表尾部删除
//顺序表从尾部删除
void SeqListPoBack(SeqList* ps)
{
	assert(ps->size>0);
	ps->a[ps->size - 1] = 0;
	ps->size--;
}

断言看顺序表里头是否有元素,如果没有直接暴力结束程序,如果有运行下面的代码。
把顺序表最后一个元素设为0,并且记录元素个数的size减一,来完成尾删。

1.5 顺序表打印
//输出结构体顺序表内容
void SeqListprint(SeqList* ps)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

断言,如果a为空就结束程序
size为元素个数。

1.6 顺序表旋转及头部插入
//翻转顺序表
void reverse(SLDateType * a, int left, int size)
{
	SLDateType tmp;
	int right = size - 1;
	while (left<right)
	{
		tmp = a[left];
		a[left] = a[right];
		a[right] = tmp;
		left++;
		right--;
	}
}

//从顺序表头部插入
void SeqListPushFront(SeqList* ps,SLDateType x)
{
	assert(ps);
	if (ps->size == ps->capacity)
	{
		SeqList* tmp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * ps->capacity * 2);
		if (tmp == NULL)
		{
			printf("realloc err");
			return;
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
	ps->a[ps->size] = x;
	ps->size++;
	reverse(ps->a,0,ps->size);
	reverse(ps->a,1,ps->size);
}

顺序表头插,插入时,要检查传过来的数组是否为空,如果为空结束程序,接的检查动态空间是否够用,如果不够,引用realloc函数,将他扩容到原空间大小的二倍。
这里我们进行的是尾插,然后通过调用翻转函数 reverse 进行翻转,使尾插的元素旋转到第一个。

1.7顺序表表头删除
//从顺序表头部删除
void SeqListPoFront(SeqList* ps)
{
	assert(ps);
	for (int i = 0; i < ps->size-1; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}

顺序表头删,依次将后面的数据挪动到自己前面的一个位置,完成后元素个数减减。

1.8 顺序表查找
//顺序表查找
void SeqListFind(SeqList* ps, SLDateType x)
{
	assert(ps);
	int left = 0;
	int right = ps->size-1;
	while (left<right)
	{
		int num = (left + right) / 2;
		if (ps->a[num]>x)
		{
			right = num - 1;
		}
		else
		{
			if (ps->a[num] < x)
			{
				left = num + 1;
			}
			else
			{
				if (ps->a[num] == x)
				{
					printf("找到了,下标为:%d\n", num);
					return;
				}
			}
		}
	}
	printf("没有找到\n");
}

这里引用了折半查找法

1.9 顺序表pos位置插入
//在指定的pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x)
{
	assert(ps);
	SeqListPushBack(ps, x);
	reverse(ps->a,pos, ps->size);
	reverse(ps->a, pos+1, ps->size);
}

尾插后,从pos位置到尾部旋转,然后跳过pos位置选择pos位置之后的元素,来完成pos位置插入

1.10 顺序表pos位置删除
//顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos)
{
	assert(ps);
	if (pos<0 || pos>ps->size)
	{
		printf("Erase Err");
		return;
	}
	for (int i = pos; i < ps->size-1; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}
1.11 顺序表销毁
//销毁结构体顺序表动态空间
void SeqListDestroy(SeqList* ps)
{
	free(ps);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

当使用完动态空间后,要进行free释放,并且置空。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值