顺序表C语言实现

1.顺序表的特性

存储的数据类型相同;
存储单元的物理地址连续;
支持根据下标随机访问;

2.顺序表的类型

1)静态顺序表

存储的数据个数有上限,一般是用一个大小固定的数组实现,实用性不高;

2)动态顺序表

数据的存储空间可以随着元素个数的增加而调整,当数据满了就会增容;

3.顺序表模拟实现

1)静态顺序表

数据结构如下:

//顺序表大小
#define MAXSZ 8
typedef int DataType;	//数据元素类型

typedef struct StaticList
{
	DataType data[MAXSZ];			//数据域
	int size;		//有效元素个数
}StaticList;
重要的接口:
初始化顺序表

设置当前有效元素个数为0

void Init(StaticList* lst)
{
	lst->size = 0;
}
插入

将待插入位置和其后面的元素都往后移动一位,再将数据放入插入位置,有效元素个数加1

bool Insert(StaticList* lst, int pos, DataType val)
{
	//检查位置的有效性
	if (pos < 0 || pos >= MAXSZ)
	{
		return false;
	}

	//检查空间是否足够
	if (lst->size + 1 > MAXSZ)
		return false;

	//移动元素
	for (int i = MAXSZ - 1; i > pos; --i)
	{
		lst->data[i] = lst->data[i - 1];
	}

	//插入数据,更新有效元素个数
	lst->data[pos] = val;
	lst->size++;

	return true;
}
删除

将待删除位置后面的所有元素都往前移动一位,有效元素个数减1

bool Erase(StaticList* lst, int pos)
{
	//检查位置的有效性
	if (pos < 0 || pos >= MAXSZ)
		return false;

	//尾删不需要移动元素
	//不是尾删需要移动元素
	if (pos != MAXSZ - 1)
	{
		//移动元素
		for (int i = pos; i < MAXSZ - 1; i++)
		{
			lst->data[i] = lst->data[i + 1];
		}
	}

	//更新有效元素个数
	lst->size--;
	return true;
}
源码

StaticList.h:

#pragma once
//静态顺序表

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h> //INT_MIN
#include <stddef.h>		//int

//顺序表大小
#define MAXSZ 8
typedef int DataType;

typedef struct StaticList
{
	DataType data[MAXSZ];			//数据域
	int size;		//有效元素个数
}StaticList;

//初始化
void Init(StaticList* lst);

//插入
bool Insert(StaticList* lst, int pos, DataType val);

//删除
bool Erase(StaticList* lst, int pos);

//修改
bool SetValue(StaticList* lst, int pos, DataType val);

//获取元素
DataType getValue(StaticList* lst, int pos);

//查找
int Search(StaticList* lst, DataType val);

//头插
bool Push_front(StaticList* lst, DataType val);

//尾插
bool Push_back(StaticList* lst, DataType val);

//头删
bool Pop_front(StaticList* lst);

//尾删
bool Pop_back(StaticList* lst);

//有效元素个数
int getSize(StaticList* lst);

//顺序表是否为空
bool isEmpty(StaticList* lst);

//顺序表是否已满
bool isFull(StaticList* lst);

//打印顺序表内容
void PrintList(StaticList* lst);

StaticList.c:

#include "StaticList.h"


//初始化
void Init(StaticList* lst)
{
	lst->size = 0;
}

//插入
bool Insert(StaticList* lst, int pos, DataType val)
{
	//检查位置的有效性
	if (pos < 0 || pos >= MAXSZ)
	{
		return false;
	}

	//检查空间是否足够
	if (lst->size + 1 > MAXSZ)
		return false;

	//移动元素
	for (int i = MAXSZ - 1; i > pos; --i)
	{
		lst->data[i] = lst->data[i - 1];
	}

	//插入数据,更新有效元素个数
	lst->data[pos] = val;
	lst->size++;

	return true;
}

//删除
bool Erase(StaticList* lst, int pos)
{
	//检查位置的有效性
	if (pos < 0 || pos >= MAXSZ)
		return false;

	//尾删不需要移动元素
	//不是尾删需要移动元素
	if (pos != MAXSZ - 1)
	{
		//移动元素
		for (int i = pos; i < MAXSZ - 1; i++)
		{
			lst->data[i] = lst->data[i + 1];
		}
	}

	//更新有效元素个数
	lst->size--;
	return true;
}

//修改
bool SetValue(StaticList* lst, int pos, DataType val)
{
	//检查位置的有效性
	if (pos < 0 || pos >= MAXSZ)
		return false;

	lst->data[pos] = val;

	return true;
}

//获取元素
DataType getValue(StaticList* lst, int pos)
{
	if (pos < 0 || pos >= MAXSZ)
		return INT_MIN;

	return lst->data[pos];
}

//查找
int Search(StaticList* lst, DataType val)
{
	int ret = -1;
	for (int i = 0; i < MAXSZ; ++i)
	{
		if (lst->data[i] == val)
		{
			ret = i;
			break;
		}
	}
	return ret;
}

//头插
bool Push_front(StaticList* lst, DataType val)
{
	return Insert(lst, 0, val);
}

//尾插
bool Push_back(StaticList* lst, DataType val)
{
	return Insert(lst, lst->size, val);
}

//头删
bool Pop_front(StaticList* lst)
{
	return Erase(lst, 0);
}

//尾删
bool Pop_back(StaticList* lst)
{
	return Erase(lst, lst->size - 1);
}

//有效元素个数
int getSize(StaticList* lst)
{
	return lst->size;
}

//顺序表是否为空
bool isEmpty(StaticList* lst)
{
	return lst->size == 0;
}
 
//顺序表是否已满
bool isFull(StaticList* lst)
{
	return lst->size == MAXSZ - 1;
}

//打印顺序表内容
void PrintList(StaticList* lst)
{
	for (int i = 0; i < lst->size; ++i)
	{
		printf("%d ", lst->data[i]);
	}
	printf("\n");
}

2)动态顺序表

数据结构的定义
typedef int DataType_D;	//数据元素类型

//动态顺序表
typedef struct DynamicList
{
	DataType_D* data;		//数据
	int size;			//有效元素个数
	int capacity;		//最大容纳元素个数
}DynamicList;

重要接口
初始化顺序表

开辟固定大小的空间,为元素个数和容量赋初值;
起始开辟一定大小的空间,可以通过宏来设置

//初始化
bool InitList(DynamicList* lst)
{
	if (lst == NULL)
		return false;
	
	//startCapacity:起始容量
	lst->data = (DataType_D*)malloc(sizeof(DataType_D)* startCapacity);
	lst->size = 0;
	lst->capacity = startCapacity;
	return true;
}

销毁顺序表

释放堆空间,防止内存泄漏

bool DestroyList(DynamicList* lst)
{
	if (lst == NULL || lst->data == NULL)
		return true;
	free(lst->data);
	lst->data = NULL;
	return true;
}
检查容量

当顺序表满了,就重新开辟空间,并将原空间的数据拷贝过去,更新容量

//检查容量
void checkCapacity(DynamicList* lst)
{
	if (lst == NULL || lst->data == NULL || lst->size != lst->capacity)
		return;

	int newC = lst->capacity * 2;
	//重新开辟空间并拷贝原空间的数据
	lst->data = (DataType_D*)realloc(lst->data, newC * sizeof(DataType_D));

	/*
		//另一种重开空间并拷贝
		DataType_D* newData = (DataType_D*)malloc(sizeof(DataType_D) * newC);
		memcpy(newData, lst->data, sizeof(DataType_D) * lst->capacity());
		free(lst->data);
		lst->data = newData;
	*/

	//更新
	lst->capacity = newC;
}
插入

第一步:检查容量;
第二步:将待插入位置和它后面的元素都往后移动一位;
第三步:插入数据;
第四步:更新元素个数

//插入
bool InsertList(DynamicList* lst, int pos, DataType_D val)
{
	if (lst == NULL || lst->data == NULL || pos < 0 || pos > lst->capacity)
		return false;

	//检查容量
	checkCapacity(lst);

	if (pos > lst->size)
		pos = lst->size;

	//移动数据
	int idx = lst->size - 1;
	while (idx >= pos)
	{
		lst->data[idx + 1] = lst->data[idx];
		idx--;
	}

	//插入数据
	lst->data[pos] = val;

	//更新
	++lst->size;

	return true;
}
删除

将待删除位置后面的元素都往前移动一位,并更新元素个数

bool EraseList(DynamicList* lst, int pos)
{
	if (lst == NULL || lst->data == NULL || pos < 0 || pos >= lst->capacity)
		return false;

	//移动元素
	int idx = pos;

	while (idx < lst->size - 1)
	{
		lst->data[idx] = lst->data[idx + 1];
		idx++;
	}

	//更新
	--lst->size;

	return true;
}
源码

DynamicList.h:

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>		//INT_MAX

typedef int DataType_D;	//数据元素类型
#define startCapacity 10	//起始容量

//动态顺序表
typedef struct DynamicList
{
	DataType_D* data;		//数据
	int size;			//有效元素个数
	int capacity;		//最大容纳元素个数
}DynamicList;

//初始化
bool InitList(DynamicList* lst);

//销毁顺序表,主要是释放堆上申请的空间
bool DestroyList(DynamicList* lst);

//检查容量
void checkCapacity(DynamicList* lst);

//插入
bool InsertList(DynamicList* lst, int pos, DataType_D val);

//删除
bool EraseList(DynamicList* lst, int pos);

//头插
bool pushFront(DynamicList* lst, DataType_D val);

//尾插
bool pushBack(DynamicList* lst, DataType_D val);

//头删
bool popFront(DynamicList* lst);

//尾删
bool popBack(DynamicList* lst);

//判空
bool IsEmpty(DynamicList* lst);

//打印顺序表
void printList(DynamicList* lst);

//根据值查找下标
int findIdx(DynamicList* lst, DataType_D val);

//根据下标查找值
DataType_D GetValue(DynamicList* lst, int pos);

//修改指定位置的值
bool setValue(DynamicList* lst, int pos, DataType_D val);

//获取有效元素个数
int getEleSize(DynamicList* lst);

//清空数据
void clearList(DynamicList* lst);

DynamicList.c:

#include "DynamicList.h"

//初始化
bool InitList(DynamicList* lst)
{
	if (lst == NULL)
		return false;
	
	//startCapacity:起始容量
	lst->data = (DataType_D*)malloc(sizeof(DataType_D)* startCapacity);
	lst->size = 0;
	lst->capacity = startCapacity;
	return true;
}

//销毁顺序表,主要是释放堆上申请的空间
bool DestroyList(DynamicList* lst)
{
	if (lst == NULL || lst->data == NULL)
		return true;
	free(lst->data);
	lst->data = NULL;
	return true;
}

//检查容量
void checkCapacity(DynamicList* lst)
{
	if (lst == NULL || lst->data == NULL || lst->size != lst->capacity)
		return;

	int newC = lst->capacity * 2;
	//重新开辟空间并拷贝原空间的数据
	lst->data = (DataType_D*)realloc(lst->data, newC * sizeof(DataType_D));

	/*
		//另一种重开空间并拷贝
		DataType_D* newData = (DataType_D*)malloc(sizeof(DataType_D) * newC);
		memcpy(newData, lst->data, sizeof(DataType_D) * lst->capacity());
		free(lst->data);
		lst->data = newData;
	*/

	//更新
	lst->capacity = newC;
}

//插入
bool InsertList(DynamicList* lst, int pos, DataType_D val)
{
	if (lst == NULL || lst->data == NULL || pos < 0 || pos > lst->capacity)
		return false;

	//检查容量
	checkCapacity(lst);

	if (pos > lst->size)
		pos = lst->size;

	//移动数据
	int idx = lst->size - 1;
	while (idx >= pos)
	{
		lst->data[idx + 1] = lst->data[idx];
		idx--;
	}

	//插入数据
	lst->data[pos] = val;

	//更新
	++lst->size;

	return true;
}

//删除
bool EraseList(DynamicList* lst, int pos)
{
	if (lst == NULL || lst->data == NULL || pos < 0 || pos >= lst->capacity)
		return false;

	//移动元素
	int idx = pos;

	while (idx < lst->size - 1)
	{
		lst->data[idx] = lst->data[idx + 1];
		idx++;
	}

	//更新
	--lst->size;

	return true;
}

//头插
bool pushFront(DynamicList* lst, DataType_D val)
{
	return InsertList(lst, 0, val);
}

//尾插
bool pushBack(DynamicList* lst, DataType_D val)
{
	return InsertList(lst, lst->size, val);
}

//头删
bool popFront(DynamicList* lst)
{
	return EraseList(lst, 0);
}

//尾删
bool popBack(DynamicList* lst)
{
	return EraseList(lst, lst->size);
}

//判空
bool IsEmpty(DynamicList* lst)
{
	return lst == NULL || lst->data == NULL || lst->size == 0;
}

//打印顺序表
void printList(DynamicList* lst)
{
	for (int i = 0; i < lst->size; ++i)
	{
		printf("%d ", lst->data[i]);
	}
	printf("\n");
}

//根据值查找下标:返回-1表示没找到
int findIdx(DynamicList* lst, DataType_D val)
{
	if (lst == NULL || lst->data == NULL)
		return -1;

	for (int i = 0; i < lst->size; ++i)
	{
		if (lst->data[i] == val)
		{
			return i;
		}
	}
	return -1;	
}

//根据下标查找值
//约定没找到返回INT_MAX

DataType_D GetValue(DynamicList* lst, int pos)
{
	if (lst == NULL || lst->data == NULL)
		return INT_MAX;

	if (pos < 0 || pos >= lst->size)
		return INT_MAX;
	return lst->data[pos];
}

//修改指定位置的值
bool setValue(DynamicList* lst, int pos, DataType_D val)
{
	if (lst == NULL || lst->data == NULL || pos < 0 || pos >= lst->size)
		return false;
	lst->data[pos] = val;
	return true;
}


//获取有效元素个数
int getEleSize(DynamicList* lst)
{
	if (lst == NULL || lst->data == NULL)
		return 0;
	return lst->size;
}

//清空数据
void clearList(DynamicList* lst)
{
	lst->size = 0;
}

4.顺序表的优缺点

优点:
尾插尾删效率高,时间复杂度为O(1);
支持按照下标随机访问;
空间连续,不会造成内存碎片;
增容代价高,需要开辟新空间和拷贝数据;

缺点:
头部和中间位置的插入和删除操作都需要移动元素,时间复杂度为O(N);
空间利用率不高,顺序表的空间可能会因为元素个数较小而被浪费

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值