[数据结构]----顺序表

目录

1.线性表的介绍

2.顺序表

2.1顺序表的概念及结构

2.2静态顺序表

2.3动态顺序表

2.3.1动态顺序表的定义

2.3.2动态顺序表的初始化

2.3.3动态循序表的销毁

2.3.4检查动态顺序表空间,满了则增容

2.3.5动态顺序表的尾插和尾删

2.3.6动态顺序表的头插和头删

2.3.7在动态顺序表中查找某个数

2.3.8动态顺序表在pos位置插入x

2.3.9动态顺序表删除pos位置的值


 

1.线性表的介绍

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...


线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组链式结构的形式存储 

2.顺序表

顺序表是数据结构中给的单独的名字,严格来说顺序表就是数组

2.1顺序表的概念及结构

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

注:顺序表要求数据是连续存储 、

2.2静态顺序表

使用定长数组存储元素

我们可以用宏(define)来控制数组大小,方便修改数组大小

因为要控制数组是连续存储的 我们需要用size来控制存储顺序

 

 

下面是静态顺序表的定义

#define N 100
typedef int DataType
typedef struct StaticSeqList
{
	DataType a[N];
	int size;// 记录存储多少个有效数据
}SSL;

静态顺序表的增删查改就是数组的移动

静态顺序表的初始化:

void init_SSL(SSL* slt)
{
	slt->size = 0;
}

静态顺序表的后插:
 

void insert_SSL(SSL* slt, DataType x)
{
    if (slt->size == N)
    {
        printf("顺序表是满的!"); exit(1);
    }
    slt->a[slt->size] = x;
    slt->size = slt->size + 1;
}

静态顺序表的打印:

void print_SSL(SSL slt)
{
    int i;
    if (!slt.size)
        printf("\n顺序表是空的!");
    else
    for (i = 0; i < slt.size; i++)
        printf("%5d", slt.a[i]);
}

但由于静态顺序表的N是规定死的,就导致它具有局限性,存储数据满的时候会造成越界,所以静态顺序表不太实用,用的很少,所以这里不展示更多的静态顺序表的算法

2.3动态顺序表

使用动态开辟的数组存储

静态顺序表只适用于确定知道需要存多少数据的场景。

静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。

所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表 

 2.3.1动态顺序表的定义

typedef struct Seqlist
{
	Datatype* a; // 指向动态开辟的数组
	int size;    // 有效数据个数
	int capacity;// 容量空间的大小
}SL;

2.3.2动态顺序表的初始化

注:我们在传递动态顺序表时,不要传结构体变量,而应该传结构体指针 

原因:传结构体变量会导致函数内部创建一个新局部结构体变量 ,而初始化完后,局部变量被销毁,形参的改变不会影响实参,所以我们需要传地址

 函数接口声明:

void SeqlistInit(SL* phead);

函数接口定义:  

void SeqlistInit(SL* phead)
{
	assert(phead);//断言空指针
	phead->a = NULL;
	phead->capacity = phead->size = 0;
}

2.3.3动态循序表的销毁

释放掉realloc申请的内存

再将指向数组首地址的指针置空 

 函数接口声明: 

void SeqlistDestroy(SL* phead);

函数接口定义:  

void SeqlistDestroy(SL* phead)
{
	assert(phead);
	free(phead->a);
	phead->a = NULL;
	phead->capacity = phead->size = 0;
}

 2.3.4检查动态顺序表空间,满了则增容

在我们进行顺序表的增删查改之前,我们应该想到静态顺序表的缺点,就是不能自动增容顺序表,而在动态顺序表中我们进行这些操作之前需要进行空间的检查

 函数接口声明: 

void CheckCapacity(SL* phead)

在动态顺序表第一次进行开辟空间时,我们通过realloc函数开辟4个int类型的空间,此后每当容量满时,新容量就扩大二倍

在动态开辟数组时,我们用到realloc函数,realloc函数将参数中的指针进行扩容,但有可能扩容失败返回空指针(扩容内存很大),此时我们需要检查一下

void CheckCapacity(SL* phead)
{
	if (phead->size == phead->capacity)
	{
		int newcapacity = phead->capacity == 0 ? 4 : 2 * phead->capacity;
		Datatype* tmp = (Datatype*)realloc(phead->a, newcapacity * sizeof(Datatype));
		if (tmp == NULL)
		{
			perror("realloc fail\n");
			exit(-1);
		}
		phead->a = tmp;
		phead->capacity = newcapacity;
	}
}

2.3.5动态顺序表的尾插和尾删

尾插

尾插很简单,就是在顺序表size的位置插入,插入后size++注意在插入前对动态顺序表进行容量的检查,防止空间溢出

 函数接口声明: 

void SeqlistPushBack(SL* phead,Datatype x);

函数接口定义:  

void SeqlistPushBack(SL* phead, Datatype x)
{
	assert(phead);

	CheckCapacity(phead);
	phead->a[phead->size] = x;
	(phead->size)++;
}

尾删

这里就直接把size-1让顺序表访问不到这个位置就行,注意在尾删前,检查断言指针不为空

 函数接口声明: 

void SeqlistPopBack(SL* phead);

函数接口定义:  

void SeqlistPopBack(SL* phead)
{
	assert(phead);

	assert(phead->size);
	phead->size--;
}

2.3.6动态顺序表的头插和头删

头插:

头插需要先在头插前 先进行顺序表的容量检查,其次需要先移动整个顺序表,把顺序表每个位置的值向后移动一位,然后再在0的位置插入值

 函数接口声明: 

void SeqlistPushFront(SL* phead, Datatype x);

函数接口定义:  

void SeqlistPushFront(SL* phead, Datatype x)
{
	assert(phead);

	CheckCapacity(phead);
	for (int i = phead->size; i > 0; i--)
	{
		phead->a[i] = phead->a[i - 1];
	}
	phead->a[0] = x;
	phead->size++;
}

头删:

 头删则需要先检查顺序表是否为空然后再把顺序表中1-size-1的数据向前移动一位,最后size再--

 函数接口声明: 

void SeqlistPopFront(SL* phead);

函数接口定义:  

void SeqlistPopFront(SL* phead)
{
	assert(phead);

	assert(phead->size);
	for (int i = 1; i < phead->size; i++)
	{
		phead->a[i - 1] = phead->a[i];
	}
	phead->size--;
}

2.3.7在动态顺序表中查找某个数

断言指针不为空

直接遍历顺序表,找到值则返回元素下标,找不到则说明

 函数接口声明: 

void SeqlistFind(SL* phead, Datatype x);

函数接口定义:  

void SeqlistFind(SL* phead, Datatype x)
{
	assert(phead);
	for (int i = 0; i < phead->size; i++)
	{
		if (phead->a[i] == x)
		{
			printf("找到了,是顺序表的第%d个元素\n",i+1);
			return;
		}
	}
	printf("没找到,无此数字\n");
}

2.3.8动态顺序表在pos位置插入x

首先判断pos的值小于size,并且进行判空操作

再将pos及pos之后的位置的值向后移动一位,移动前判容量

最后直接将值插在pos位置,size++

 函数接口声明: 

void SeqlistInsert(SL* phead, size_t pos, Datatype x);

函数接口定义:  

void SeqlistInsert(SL* phead, size_t pos, Datatype x)
{
	assert(phead);
	assert(pos <= phead->size);
	CheckCapacity(phead);

	size_t end = phead->size;
	while (end > pos)
	{
		phead->a[end] = phead->a[end - 1];
		end--;
	}
	phead->a[pos] = x;
	phead->size++;
}

2.3.9动态顺序表删除pos位置的值

首先判断pos的值小于size,并且进行判空操作

再将pos后面的值(不包括pos位置),向前移动一位(这样原本pos位置的值就被覆盖)

再size--

 函数接口声明: 

void SeqlistErase(SL* phead, size_t pos);

函数接口定义:  

void SeqlistErase(SL* phead, size_t pos)
{
	assert(phead);
	assert(pos < phead->size);
	for (int i = pos; i < phead->size-1; i++)
	{
		phead->a[i] = phead->a[i + 1];
	}
	phead->size--;
}

2.3.10改变动态顺序表pos位置的值

首先判断pos的值小于size,并且进行判空操作

然后直接修改值即可

 函数接口声明: 

void SeqlistModify(SL* phead, size_t pos, Datatype x);

函数接口定义: 

void SeqlistModify(SL* phead, size_t pos, Datatype x)
{
	assert(phead);
	assert(pos < phead->size);
	phead->a[pos] = x;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值