线性表之顺序表

1 线性表介绍

线性表是具有一类相同特性的数据结构的集合。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串……

类似于水果:苹果、梨、香蕉……

逻辑结构指人想象出来的数据的组织形式。线性表在逻辑结构上是线性结构,也就是连续的一条直线。

物理结构是数据在内存上的存储形式。线性表在物理结构上不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

2 顺序表介绍

2.1 概念与结构

顺序表是线性表的一种。如下表,每一格就是一个存储单元。顺序表存储单元的物理地址是连续的,存储单元中依次存储数据元素,在一般情况下用数组存储。可见顺序表的逻辑结构和物理结构都是线性的。

0123456

数组  ————  顺序表(数组+增加数据+删除数据+修改数据+……)

 2.2 分类

2.2.1 静态顺序表

静态顺序表:使用定长数组存储元素。事先无法确定数组大小情况下,静态顺序表会有缺点:给小了空间不够,给大了浪费。

//静态顺序表
typedef int SLDataType;//无法确定数据类型,在此给int起名为SLDataType,便于后续将int修改成char型 
#define N 7   //定义N的长度,固定大小为7 
typedef struct SeqList{
    SLDataType a[N];//定长数组 
    int size;       //有效数据个数 
}SL;//顺序表的名字 

2.2.2 动态顺序表

动态顺序表:按需申请。

//动态顺序表
typedef struct  SeqList  //SeqList即顺序表英文表示
{
    SLDataType* a;//不知道数组大小,用指针来代替后续可以为指针指向的空间申请空间,多大都可以,动态的申请
    int size;//有效数据个数 
    int capacity;//空间容量 
}SL; 

动态顺序表空间不够可以用realloc增容。增容一般成倍数增加,常增加两倍。

增容本身就有一定的程序性能消耗,频繁使用会使效率降低,因此不逐个增加,而是成倍数增加。

增容分两种情况:

1.连续空间足够,直接扩容

2.连续空间不够:

(1)重新找一块地址,分配足够的内存;

(2)拷贝数据到新的地址;

(3)销毁旧地址。

 3 动态顺序表的实现

3.1 定义动态顺序表的结构

typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* arr;
	int size;
	int capacity;
}SL;

3.2 顺序表的初始化

void SLInit(SL* ps);//顺序表的初始化
void SLInit(SL* ps)//形参,指针接收地址
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

3.2 顺序表的销毁

void SLDsetory(SL* ps);//顺序表的销毁
void SLDestory(SL* ps)
{
	if (ps->arr) {//判断底层数组是否为空,不为空则释放掉
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

3.3 顺序表的打印

方便后续插入删除时打印顺序表,观察是否正确。

void SLPrint(SL* ps);
void SLPrint(SL* ps)
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");
}

3.4 尾插

void SLCheckCapacity(SL* ps);
void SLPushBack(SL* ps,SLDataType x);
void SLCheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity) 
	{
		int newCapacity = ps->capacity = 0 ? 4 : 2 * ps->capacity;
		//增容
		SLDataType* temp = (SLDataType*)realloc(ps->arr, newCapacity*sizeof(SLDataType));
		if (temp == NULL) {
			perror("申请失败!");
			exit(1);
		}
		ps->arr = temp;
		ps->capacity = newCapacity;
	}
}
void SLPushBack(SL* ps,SLDataType x) 
{
	assert(ps);
	SLCheckCapacity(ps);//判断空间是否足够
	ps->arr[ps->size] = x;
	ps->size++;
}

 顺序表执行插入时,需要判断空间是否足够。足够则直接插入,不足时需要先增容。

3.5 头插 

void SLPushFront(SL* ps,SLDataType x);
void SLPushFront(SL* ps,SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	for (int i = ps->size; i >0; i--)
	{
		ps->arr[i] = ps->arr[i-1];
	}
	ps->arr[0] = x;
	ps->size++;
}

3.6 尾删

void SLPopBack(SL* ps);//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	ps->size--;
}

删除操作时顺序表内容不能为空。

3.7 头删

void SLPopFront(SL* ps);//头删
void SLPopFront(SL* ps)
{
	assert(ps->size);
	assert(ps);
	for (int i = 0; i < ps->size-1; i++)
	{
		ps->arr[i] = ps->arr[i+1];
	}
	ps->size--;
}

3.8 在指定位置之前插入

void SLInsert(SL* ps,SLDataType x,int pos);//指定位置之前插入
void SLInsert(SL* ps,SLDataType x,int pos)//pos为下标
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);
	for (int i = ps->size-1; i >=pos; i--)/
	{
		ps->arr[i+1] = ps->arr[i];
	}
	ps->arr[pos] = x;
	ps->size++;
}

3.9 删除指定位置的元素

void SLErase(SL* ps,int pos);
void SLErase(SL* ps,int pos)
{
	assert(ps);
	assert(ps->size);
	assert(pos >= 0 && pos <= ps->size);
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}ps->size--;
}

3.10 查找指定元素

int SLFind(SL* ps,SLDataType x);
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x) {
			return i;
		}
	}
	return -1;//没找到
}

3.11 测试函数

void test01()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPrint(&s);//打印顺序表,1234

	SLPushFront(&s, 5);
	SLPushFront(&s, 6);
	SLPushFront(&s, 7);
	SLPushFront(&s, 8);
	SLPrint(&s);//8765 1234

	SLPopBack(&s);//8765 123
	SLPrint(&s);

	SLPopFront(&s);
	SLPrint(&s);//765 123

	SLInsert(&s,10,0);//相当于头插
	SLPrint(&s);//10 765 123
	SLInsert(&s, 10, 3);
	SLPrint(&s);//10 76 10 5 123

	SLErase(&s, 1);//删除了7
	SLPrint(&s);//10 6 10 5123

	int find = SLFind(&s, 1);
	if (find < 0) {
		printf("没有这样的数据!\n");
	}
	else {
		printf("有这样的数据\n");
	}

}

int main()
{
	test01();
	return 0;
}

db26be6d5434417b9a0f55dd86344525.png

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值