顺序表(数据结构)

目录

头插,头删

尾插 尾删

在特定位置插入,删除

查找


首先,什么是顺序表呢?

顺序表是线性表的一种,那么线性表是什么呢?

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

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

顺序表要求是连续存储的。

话不多说,直接来写代码:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

#define N 10

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	int  size;
	int capicity;
}SL;

//初始化
void SLInit(SL *ps);
//打印
void SLPrint(SL* ps);
//销毁
void SLDestory(SL* ps);
//尾插
void SLPushBack(SL* ps ,SLDateType x);
// 尾删
void SLPopBack(SL* ps);
//检查内存是否够、
void SLCheckCapicity(SL* ps);
//头插
void SLPushFront(SL* ps, SLDateType x);
//头删
void SLPopFront(SL* ps);
// 顺序表查找
int SLFind(SL* ps, SLDateType x);
// 顺序表在pos位置插入x
void SLInsert(SL* ps, size_t pos, SLDateType x);
// 顺序表删除pos位置的值
void SLErase(SL* ps, size_t pos);

typedef int SLDateType;
typedef struct SeqList
{
    SLDateType* a;
    int  size;
    int capicity;
}SL;

这一段代码的意义是:定义一个顺序表的结构体采用动态存储,SLDateType是将int类型重定义,方便后续修改类型。

第一步,毋庸置疑是代码的初始化:

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

由于是动态内存开辟,所以我们需要检查内存是否足够。

void SLCheckCapicity(SL* ps)
{
	if (ps->size == ps->capicity)
	{
		int newcapicity = ps->capicity == 0 ? 4 : ps->capicity * 2;
		SLDateType* ret = (SLDateType)realloc(ps->a, newcapicity * sizeof(SLDateType));
		if (ret == NULL)
		{
			perror(realloc);
			return;
		}
		ps->a = ret;
		ps->capicity = newcapicity;
	}
}

做完这些,该考虑如何增删查改了。

头插,头删

//头插
void SLPushFront(SL* ps, SLDateType x)
{
	assert(ps);
	//扩容
	SLCheckCapicity(ps);
	//第一种 for循环
	//ps->a[ps->size] = x;
	//int tt=0;
	创建中间变量来交换数值
	//int i = 0;
	//for ( i = ps->size; i > 0; i--)
	//{
	//	tt = ps->a[i - 1];
	//	ps->a[i - 1] = ps->a[i];
	//	ps->a[i] = tt;
	//}
	//ps->size++;
	//第二种 SLInsert。
	SLInsert(ps, 0, x);
}


//头删
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);
	//第一种 for循环
	for (int j = 0; j < ps->size-1; j++)
	{
		ps->a[j] = ps->a[j + 1];
	}
	ps->size--;
	//pos位置删
	SLErase(ps, 0);
}

这里可以使用while循环也可以用for循环看个人喜好。

尾插 尾删

//尾插
void SLPushBack(SL* ps,SLDateType x)
{
	assert(ps);
	//扩容
	SLCheckCapicity(ps);
	//第一种
	ps->a[ps->size] = x;
	ps->size++;
	//第二种
	SLInsert(ps, ps->size, x);
}

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

在特定位置插入,删除

// 顺序表在pos位置插入x
void SLInsert(SL* ps, size_t pos, SLDateType x)
{
	//第一种
	int j = 0;
	for (j = ps->size-1; j >= pos; j--)
	{
		ps->a[j + 1] = ps->a[j];
	}
	ps->a[j] = x;
	ps->size++;
	//第二种
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}

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



// 顺序表删除pos位置的值
void SLErase(SL* ps, size_t pos)
{
	assert(ps);
	assert(pos >= 0);
	assert(pos <= ps->size);
	int j = 0;
	//第一种
	for (j = pos-1; j < ps->size; j++)
	{
		ps->a[j] = ps->a[j + 1];
	}
	ps->size--;

	//第二种
	// 挪动数据覆盖
	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;

}

上面的头插,头删之类的也可以使用以上代码,是第二种方法,详细见上边的代码。

查找

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

由于本人比较懒,所以将测试代码写在了一起,宝子们凑合看看吧。

#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h"

void test()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s,1);
	SLPushBack(&s, 4);
	SLPushBack(&s, 1);
	SLPushFront(&s, 5);
	SLPushFront(&s, 5);
	SLPushFront(&s, 5);

	//头插尾插

	//查找
	SLFind(&s, 1);
	SLFind(&s, 7);

	//头删尾删
	SLPopBack(&s);
	SLPrint(&s);
	SLPopFront(&s);
	SLPrint(&s);

	//在pos位置插入
	SLInsert(&s,2,9);
	SLPrint(&s);
	SLErase(&s,2);
	SLPrint(&s);

	SLDestory(&s);
	//删除数字
	/*int pos = SLFind(&sl, 5);
	if (pos != -1)
	{
		SLErase(&sl, pos);
	}
	SLPrint(&sl);*/
}

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

总代码:

#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h"
void SLInit(SL* ps)
{
	ps->a = NULL;
	ps->size = 0;
	ps->capicity = 0;
}
void SLCheckCapicity(SL* ps)
{
	if (ps->size == ps->capicity)
	{
		int newcapicity = ps->capicity == 0 ? 4 : ps->capicity * 2;
		SLDateType* ret = (SLDateType)realloc(ps->a, newcapicity * sizeof(SLDateType));
		if (ret == NULL)
		{
			perror(realloc);
			return;
		}
		ps->a = ret;
		ps->capicity = newcapicity;
	}
}

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

void SLDestory(SL* ps)
{
	//释放
	if (ps->a)
	{
		free(ps->a);
		ps->a = NULL;
		ps->size = 0;
		ps->capicity = 0;
	}
}

//头插
void SLPushFront(SL* ps, SLDateType x)
{
	assert(ps);
	//扩容
	SLCheckCapicity(ps);
	//第一种 for循环
	//ps->a[ps->size] = x;
	//int tt=0;
	创建中间变量来交换数值
	//int i = 0;
	//for ( i = ps->size; i > 0; i--)
	//{
	//	tt = ps->a[i - 1];
	//	ps->a[i - 1] = ps->a[i];
	//	ps->a[i] = tt;
	//}
	//ps->size++;
	//第二种 SLInsert。
	SLInsert(ps, 0, x);
}
//尾插
void SLPushBack(SL* ps,SLDateType x)
{
	assert(ps);
	//扩容
	SLCheckCapicity(ps);
	//第一种
	ps->a[ps->size] = x;
	ps->size++;
	//第二种
	SLInsert(ps, ps->size, x);
}

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



//头删
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);
	//第一种 for循环
	for (int j = 0; j < ps->size-1; j++)
	{
		ps->a[j] = ps->a[j + 1];
	}
	ps->size--;
	//pos位置删
	SLErase(ps, 0);
}

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

// 顺序表在pos位置插入x
void SLInsert(SL* ps, size_t pos, SLDateType x)
{
	//第一种
	int j = 0;
	for (j = ps->size-1; j >= pos; j--)
	{
		ps->a[j + 1] = ps->a[j];
	}
	ps->a[j] = x;
	ps->size++;
	//第二种
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}

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



// 顺序表删除pos位置的值
void SLErase(SL* ps, size_t pos)
{
	assert(ps);
	assert(pos >= 0);
	assert(pos <= ps->size);
	int j = 0;
	//第一种
	for (j = pos-1; j < ps->size; j++)
	{
		ps->a[j] = ps->a[j + 1];
	}
	ps->size--;

	//第二种
	// 挪动数据覆盖
	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;

}

事物总是存在双面性,一个东西有好处肯定也会有不足,和人一样嘛!

顺序表的缺陷 :

1.空间不够,需要扩容,扩容(尤其是异地扩容是有一定代价的,还可能会有一定的空间浪费。

2.头部或中部插入删除,需要挪动数据,效率低下。

优化方案:按需申请释放,不要挪动数据。

这个涉及到我们的链表,下期来给大家分享,今天就到此为止吧。

感觉有收获的宝子们,可以点点赞和关注偶,有什么问题也可以私我

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值