顺序表的基本概念和代码详解

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

顺序标的基本概念和代码详解

1.基本概念

在这里插入图片描述
在这里插入图片描述
也就是说顺序表在结构和逻辑上都连续。>>>典型的数组结构
不允许其中有空的地址,未存取数据

2.结构体定义

2.1 顺序表静态存储

在这里插入图片描述
静态特点:如果满了就不让插入 缺点:给多少的合适呢?这个很难确定
N给小了不够用,N给大了浪费

2.2 顺序表动态存储

// 动态顺序表
typedef int SLDataType;//如果数据类型不为int,方便随时变更

typedef struct SeqList
{
	SLDataType* a;  //可以采用relloc扩容,指向存储数据的空间
	int size;      // 表示数组中存储了多少个数据
	int capacity;  // 数组实际能存数据的空间容量是多大 
}SL;

注意:顺序表都是存储在结构体的SLDataType* a的这份空间中的,有relloc来开辟。
这份空间估且叫A空间吧,A空间在申请时,不够会一次申请n个字节,所以其容量和有效数据的个数不等。决定当前顺序表有多少个有效数据的为结构体的size的值。

3.顺序表的初始化、增删改查、和检测容量并扩容等重要功能。

3.1 顺序表初始化

为什么需要这个呢?这个对于顺序表动态存储来使用的,因为动态可以采用relloc扩容,然后在扩容时(SeqListCheckCapacity()函数中),根据扩容的空间给ps->size和ps->capacity赋值,进入扩容之前,以初始化的 ps->a = NULL; ps->size = ps->capacity = 0;为前提来执行后面的逻辑的。
这样:所有任意长度的数据都可以采用初始化。
在这里插入图片描述

void SeqListInit(SL* ps)
{
	ps->a = NULL;
	ps->size = ps->capacity = 0;
}

3.2 顺序表检测容量并扩容

void SeqListCheckCapacity(SL* ps)
	
{
	// 如果没有空间或者空间不足,那么我们就扩容
	if (ps->size == ps->capacity)
	{
		//初始化后,第一次进入时,capacity=size=0
		//容量满了,capacity=size  不等于0

		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		//当第一次进入时,容量赋值为4,之后如果容量不满了,容量扩容为原来的2倍
		
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity*sizeof(SLDataType));
		//realloc申请的地址类型为char*  以字节为单位
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}

		ps->a = tmp;
		ps->capacity = newcapacity;
	}
}

3.3 顺序表删除

删除数据前需要检测是否无数据。

3.3.1 顺序表指定下标pos删除

//逻辑上认为应该先删除再挪动数据的
//但是其实直接挪动数据,覆盖即可
//删除其实就说size(有效数据)的减小。
void SeqListDelet(SL* ps, int pos)//删除指定pos位置数据
{
	assert(ps->size > 0);     //需要检测是否无数据。
	assert((pos <= ps->size - 1)//可以删除的位置  0<=pos<=size-1   
		   && (pos>=0));        //&& 且
	//挪动数据
	int begin = pos;
	while (begin<=ps->size-2)//当pos为size-1,尾删时,不会进入循环  头删可以进入循环
	{
		ps->a[begin] = ps->a[begin+1];
		begin++;
	}
	ps->size--;
}

怎么理解呢?挪动的理解

向前挪动的二种方法:
方法一:
//挪动数据
	int begin = pos;
	while (begin<=ps->size-2)
	{
		ps->a[begin] = ps->a[begin+1];
		begin++;
	}
	ps->size--;

在这里插入图片描述
在这里插入图片描述

方法二:推荐此方法
//挪动数据
	int begin = pos+1;
	while (begin<=ps->size-1)
	{
		ps->a[begin-1] = ps->a[begin];
		begin++;
	}
	ps->size--;

在这里插入图片描述

3.3.2 顺序表尾部删除

尾部删除无需移动数据

void SeqListPopBack(SL* ps)
{
	// 温柔处理方式
	//if (ps->size > 0)
	//{
	//	//ps->a[ps->size - 1] = 0;
	//	ps->size--;
	//}

	// 暴力处理方式
	assert(ps->size > 0);//需要检测是否无数据。
	ps->size--;
}

3.3.3 顺序表头部删除

void SeqListPopFront(SL* ps)//逻辑上认为应该先删除再挪动数据的
//但是其实直接挪动数据,覆盖即可
//但是删除其实就说size的减小。
{
	assert(ps->size > 0);
	 /*挪动数据*/
	int begin = 0;
	while (begin < ps->size-1)
	{
		ps->a[begin ] = ps->a[begin+1];
		++begin;
	}
	ps->size--;
}

3.4. 顺序表增加数据

都应该在增加数据之前检查一下是否数据满了,

3.4.1 顺序表指定下标插入数据

void SeqListInsert(SL* ps, int pos, SLDataType x)
{
	assert(pos>=0 && pos >=ps->size);//  插入数据时   pos范围为  0<=pos<=size
	
	SeqListCheckCapacity(ps);//检查一下是否数据满了
	int end = ps->size-1;
	while (end >= pos)//当pos为size,尾插时,不会进入循环 执行挪动数据
	// 头插可以进入循环
	{
		ps->a[end +1] = ps->a[end];
		--end;
	}
	ps->a[pos] = x;
	ps->size++;
}

为什么pos范围为[0,size]呢?
pos为0时,会把在第0位的数据挤到后面,pos插完在第0位,即头插
pos为size时,直接在尾部插入数据,即尾差

向后挪动二种方法:
方法一:推荐此方法
int end = ps->size-1;
	while (end >= pos)
	{
		ps->a[end +1] = ps->a[end];
		--end;
	}
	ps->a[pos] = x;
	ps->size++;

在这里插入图片描述

方法二:
int end = ps->size;
	while (end >= pos+1)
	{
		ps->a[end] = ps->a[end-1];
		--end;
	}
	ps->a[pos] = x;
	ps->size++;

在这里插入图片描述

注意:插入数据和删除数据,的下标范围不一样

插入数据 可以在数据后面插入一个数据, 0<=pos<=size
而且这样弄好之后,初始化之后,size=capacity=0,也都符合这个范围

那既然能在尾部插入,那应该也能在头部插入数据 此时pos应该为-1,
如果这样理解就错了,pos值是指插入数据后,该数据在数组上的位置。
即pos=0,时就头插,会把原来的数据向后挤

删除数据 只能有数据的下标上删除 0<=pos<=size-1

3.4.2 顺序表尾部插入数据

void SeqListPushBack(SL* ps, SLDataType x)
{
	SeqListCheckCapacity(ps);

	ps->a[ps->size] = x;
	ps->size++;
}

3.4.3 顺序表头部增加数据

void SeqListPushFront(SL* ps, SLDataType x)
{
	SeqListCheckCapacity(ps);

	// 挪动数据
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	ps->a[0] = x;
	ps->size++;
}

3.5 向前挪动数据和向后挪动数据的区别

3.5.1 a[b]=a[b+1] 增加 向前挪动 减少 a[b]=a[b-1]向后挪动

3.5.2 向前挪动,前面的数据先挪动 向后挪动,后面的数据先挪动

3.6 销毁顺序表

void SeqListDestory(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}

3.6 打印顺序表中现有数据

void SeqListPrint(SL* ps)
{
	for (int i = 0; i < ps->size; ++i)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值