数据结构——不定长顺序表

顺序表:将元素顺序地放在一块被开辟出来的连续的内存空间里,其逻辑相邻,物理也相邻

不定长顺序表:即是在插入某个数据时,超过了我们目前内存空间的大小,那么我们就需要对其进行扩容操作,其内存空间大小是由我们申请开辟的,不是固定的。

因为其内存空间大小是不确定的,那么我们在设计时,除了其存储空间基址外,还需要有两个变量,一个是有效数据的长度,另一个则是内存空间大小。

当有效数据长度和内存空间大小相等,而我们要进行数据插入时,就要对其进行扩容

elem(空间基址)123456...数据
012345...下标
length(有效长度)
list_size(目前空间大小)

        

              

时间复杂度: 

                         插入/删除数据时间复杂度O(n),需要挪动数据

                         尾部插入和删除时间复杂度O(1),不需要挪动数据

下边是代码实现

结构体设计

        定义其初始空间为MAX_SIZE 值为100

#define MAX_SIZE 100
typedef int ElemType;
typedef struct Sqlist {
	ElemType* elem;	//存储空间基址
	int length;	//有效长度
	int list_size;	//当前容量大小
}Sqlist,*PSqlist;

不定长顺序表  初始化

        对每个指针都要进行断言,可以使用assert (头文件 #include <assert.h>)    也可以加 if 判断,assert 只在 debug 版本有用,在release 版本就被忽视掉了,所以我这儿两个都写着。

        先通过(malloc)申请空间,其空间大小初值为MAX_SIZE 100,数据初始有效长度为0,目前空间大小也更改为申请的空间内存大小(MAX_SIZE  (100))

//初始化
void Init_sqlist(struct Sqlist* plist) {
	assert(plist != NULL);	//Debug
	if (plist == NULL) return;	//Release

	plist->elem = (ElemType*)malloc(MAX_SIZE * sizeof(ElemType));

	assert(plist->elem != NULL);
	if (plist->elem == NULL) return;

	plist->length = 0;    //初始长度为0
	plist->list_size = MAX_SIZE;    //目前空间大小为MAX_SIZE    自己宏定义的100
}

先根据思路来写,进行代码插入、删除操作,那就要进行判满和判空(插入判满,删除判空,满了需要进行扩容,因此还要有扩容操作)

判满

简写 就是 length == list_size   可以理解为存储数据的有效长度(存储数据所占用的有效空间大小) ==   目前所申请的内存空间大小

如果满了则返回为真(true)

//判满 
bool IsFull(PSqlist plist) {
	assert(plist != NULL);
	if (plist == NULL) return false;
	return plist->length == plist->list_size;
}

ps:最后一行 return plist -> length == plist -> list_size   不能写成  plist->length == MAX_SIZE; 因为如果扩容了的话那么当前容量大小就不是MAX_SIZE了

扩容

先进行判满操作,返回是真,就说明满了,则调用扩容函数

void Inc(PSqlist plist) {
	assert(plist != NULL);
    if(plist == NULL) return;

	plist->elem = (ElemType*)realloc(plist->elem, (plist->list_size * sizeof(ElemType)) * 2);	//扩容2倍
	plist->list_size *= 2;	//目前内存空间大小
}

ps:进行扩容操作,不要忘了后面 list_size 也要进行扩容修改

判空 

 链表的有效长度是否是 0(plist -> length == 0)

//判空
bool IsEmpty(PSqlist plist) {
	assert(plist != NULL);
	if (plist == NULL) return false;
	return plist->length == 0;	

}

插入 —— 按位置插入

插入位置后面的数据都向后移动

//插入
bool Insert(PSqlist plist, int pos, int val) {

	assert(plist != NULL);
	if (plist == NULL) return false;

	assert(pos >= 0 && pos <= plist->length);	
	if (pos < 0 || pos > plist->length)	return false;


	if (IsFull(plist)) {	//判满,为真,需要扩容
		Inc(plist);
	}

	for (int i = plist->length - 1; i >= pos; i--) {	// 数据后移,空出需要插入的下标
		plist->elem[i + 1] = plist->elem[i];
	}
	plist->elem[pos] = val;
	plist->length++;
	return true;
}

ps:插入后,要记得修改长度length呀~ 后面删除操作也不要忘记哦~

删除——根据下标删除    根据值删除

删除操作先是要对顺序表进行判空操作,根据值删除其实也就是通过查找要删w下标,再调用根据下标删除的函数就好了

//删除——根据下标
bool Del_pos(PSqlist plist, int pos) {
	assert(plist != NULL);
	if (plist == NULL) return false;
	assert(pos >= 0 && pos <= plist->length);
	if (pos < 0 || pos > plist->length)	return false;
	
	if (IsEmpty(plist)) {
		return false;
	}
	for (int i = pos + 1; i < plist->length; i++) {
		plist->elem[i - 1] = plist->elem[i];
	}
	plist->length--;
	return true;
}

//删除——根据值
bool Del_val(PSqlist plist, int val) {
	assert(plist != NULL);
	if (plist == NULL) return false;
	if (IsEmpty(plist)) {
		return false;
	}
	int pos = Search_val(plist, val);
	if (pos == -1) return false;
	return Del_pos(plist, pos);	//调用按下标删除的函数,直接返回就行
}

查找——根据值

int Search_val(PSqlist plist, int val) {
	assert(plist != NULL);
	if (plist == NULL) return -1;
	for (int i = 0; i < plist->length; i++) {	//遍历查找
		if (plist->elem[i] == val) {
			return i;
		}
	}
	return -1;
}

清空 —— 也就是让有效数据长度(length)为0

//清空
void Clear(PSqlist plist) {
	assert(plist != NULL);
	if (plist == NULL) return;
	plist->length = 0;
}

销毁

 这里不仅让有效数据长度为0,也要对申请出来的内存空间进行释放,释放之后,一定要让其指针重新指向空,是为了防止野指针的出现(也就是为了避免二次释放导致的异常或者崩溃)

//销毁
void Destroy(PSqlist plist) {
	plist->length = 0;
	free(plist->elem);
	plist->elem = NULL;
	plist->list_size = 0;

}

结果打印


//打印
void Show(PSqlist plist) {
	for (int i = 0; i < plist->length; i++) {
		printf("%d ", plist->elem[i]);
	}
	printf("\n");

}

测试用例:

int main() {
	struct Sqlist sq;
	Init_sqlist(&sq);
	for (int i = 0; i < 100; i++) {
		Insert(&sq, i, i + 1);
	}
	Show(&sq);
	printf("length = %d\n", sq.length);
	printf("list_size = %d\n", sq.list_size);

	Insert(&sq, 1, 1000);
	Show(&sq);
	printf("length = %d\n", sq.length);
	printf("list_size = %d\n", sq.list_size);
	
	Del_pos(&sq, 74);//74
	Del_val(&sq, 44);//44
	Show(&sq);

	printf("------------------------------------>\n");
		Clear(&sq);
		Show(&sq);
		printf("length = %d\n", sq.length);
		printf("list_size = %d\n", sq.list_size);
		
	printf("------------------------------------>\n");
		Destroy(&sq);
		Show(&sq);
		printf("length = %d\n", sq.length);
		printf("list_size = %d\n", sq.list_size);

	return 0;
}

结果打印:

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值