顺序表

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储
顺序表一般有两种:

  • 静态顺序表 : 使用定长数组存储
  • 动态顺序表 : 使用动态开辟的数组存储

下面是动态顺序表的实现以及一些接口函数

定义

typedef int SLDataType;	// 顺序表存储的数据类型

// 顺序表
typedef struct SeqList
{
	//SLDataType data[1024];	// 静态顺序表
	SLDataType *_data;		// 动态顺序表
	size_t _size;			// 有效元素个数
	size_t _cap;			// 容量
} SeqList, *SeqListPtr;

初始化

// 将slp初始化为容量大小为cap的顺序表
void InitSeqList(SeqListPtr slp, size_t cap)
{
	assert(slp);	// slp是否存在
	slp->_data = (SLDataType *)malloc(cap * sizeof(SLDataType));	// 初始化存储空间
	if (slp->_data == NULL)		// 检查是否申请成功
	{
		perror(strerror(errno));
		return;
	}
	slp->_size = 0;
	slp->_cap = cap;
}

销毁

// 销毁顺序表
void DestroySeqList(SeqListPtr slp)
{
	assert(slp);
	if (slp->_data != NULL)
	{
		free(slp->_data);	// 释放内存
		slp->_data = NULL;	// 指针置空
		slp->_size = 0;		// 有效元素清零
		slp->_cap = 0;		// 容量清零
	}
}

扩容

// 改变顺序表的容量
void ReCapSeqList(SeqListPtr slp, size_t cap)
{
	assert(slp);
	if (cap <= slp->_size)	// 修改容量小于有效数据
	{
		return;
	}
	SLDataType *newdata = (SLDataType *)malloc(cap * sizeof(SLDataType));	// 重新开辟内存
	if (newdata == NULL)
	{
		perror(strerror(errno));
		return;
	}
	for (size_t i = 0; i < slp->_size; ++i)	// 拷贝元素
	{
		newdata[i] = slp->_data[i];
	}
	free(slp->_data);	// 释放旧存储空间
	slp->_data = newdata;	// 指向新的存储空间
	slp->_cap = cap;	// 新的容量
}

插入

// 在pos位置插入data
void InsertSeqList(SeqListPtr slp, size_t pos, SLDataType data)
{
	assert(slp);
	if (pos > slp->_size)	// pos位置合法性检测
	{
		return;
	}
	if (slp->_size == slp->_cap)	// 存储空间已满
	{
		ReCapSeqList(slp, 2 * slp->_cap);
	}
	for (size_t i = slp->_size; i > pos; --i)	// 将pos之后的元素向后移动
	{
		slp->_data[i] = slp->_data[i - 1];
	}
	slp->_data[pos] = data;	// 将data赋给pos位置
	++slp->_size;
}

删除

// 删除pos位置的元素
void EraseSeqList(SeqListPtr slp, size_t pos)
{
	assert(slp);
	if (pos >= slp->_size)	// pos位置合法性检测
	{
		return;
	}
	for (size_t i = pos; i < slp->_size - 1; ++i)	// 将pos之后的元素向前移
	{
		slp->_data[i] = slp->_data[i + 1];
	}
	--slp->_size;
}

打印

// 打印顺序表的元素
void PrintSeqList(SeqListPtr slp)
{
	assert(slp);
	for (size_t i = 0; i < slp->_size; ++i)
	{
		printf("%d ", slp->_data[i]);
	}
	printf("\n");
}

尾插&尾删

依靠插入和删除完成

// 在顺序表的尾部插入数据
void PushBackSeqList(SeqListPtr slp, SLDataType data)
{
	assert(slp);
	InsertSeqList(slp, slp->_size, data);
}

// 删除顺序表尾部数据
void PopBackSeqList(SeqListPtr slp)
{
	assert(slp);
	EraseSeqList(slp, slp->_size - 1);
}

头插&头删

依靠插入和删除完成

// 在顺序表的首部插入数据
void PushFrontSeqList(SeqListPtr slp, SLDataType data)
{
	assert(slp);
	InsertSeqList(slp, 0, data);
}

// 删除顺序表首部的数据
void PopFrontSeqList(SeqListPtr slp)
{
	assert(slp);
	EraseSeqList(slp, 0);
}

查找

// 在顺序表中查找data,找到返回data的下标,否则返回-1
int SearchSeqList(SeqListPtr slp, SLDataType data)
{
	assert(slp);
	for (size_t i = 0; i < slp->_size; ++i)	// 遍历所有数据
	{
		if (slp->_data[i] == data)	// 与待查找的数据相同
		{
			return i;
		}
	}
	return -1;
}

判空

// 顺序表是否为空
int EmptySeqList(SeqListPtr slp)
{
	assert(slp);
	if (slp->_size == 0)	// 没有有效元素
	{
		return 1;
	}
	return 0;
}

元素个数&容量

// 有效元素的个数
int SizeSeqList(SeqListPtr slp)
{
	assert(slp);
	return slp->_size;
}

// 容量大小
int CapSeqList(SeqListPtr slp)
{
	assert(slp);
	return slp->_cap;
}

清空

// 清空顺序表的所有数据
void ClearSeqList(SeqListPtr slp)
{
	assert(slp);
	slp->_size = 0;	// 有效元素为0即可
}

删除指定的值

// 删除顺序表中第一个值为data的元素
void RemoveSeqList(SeqListPtr slp, SLDataType data)
{
	assert(slp);
	// 先找到下标,再删除
	EraseSeqList(slp, SearchSeqList(slp, data));
}

冒泡排序

// 对顺序表进行冒泡排序
void BubbleSortSeqList(SeqListPtr slp)
{
	assert(slp);
	for (int end = slp->_size; end > 1; --end)	// 冒泡排序
	{
		int flag = 0;	// 是否已经有序
		for (int i = 1; i < end; ++i)
		{
			// 前一个数据比后一个数据大则交换
			if (slp->_data[i - 1] > slp->_data[i])
			{
				SLDataType tmp = slp->_data[i];
				slp->_data[i] = slp->_data[i - 1];
				slp->_data[i - 1] = tmp;
				flag = 1;
			}
		}
		if (!flag)	// 如果已经有序
		{
			return;
		}
	}
}

二分查找

// 对顺序表进行二分查找
int BinarySearchSeqList(SeqListPtr slp, SLDataType data)
{
	assert(slp);
	int left = 0;
	int right = slp->_size;
	while (left < right)
	{
		int mid = left + (right - left) / 2;	// 带查找位置的中间
		if (data == slp->_data[mid])	// 相等便返回下标
		{
			return mid;
		}
		else if (data < slp->_data[mid])	// data小于中间的元素
		{
			right = mid;	// 区间右侧移向中间
		}
		else		// data大于中间的元素
		{
			left = mid + 1;	// 区间左侧移向中间
		}
	}
	return -1;
}

删除所有与指定值相等的数据

// 移除顺序表中所有与data相等的数据
void RemoveAllSeqList(SeqListPtr slp, SLDataType data)
{
	assert(slp);
	//for (int i = 0; i < slp->_size; ++i)	// 遍历顺序表
	//{
	//	if (slp->_data[i] == data)	// 找到与data相等元素的位置
	//	{
	//		EraseSeqList(slp, i);	//删除该位置
	//		--i;	// 删除后元素向前移动
	//	}
	//}

		int count = 0;	// data的个数
	for (size_t cur = 0; cur < slp->_size; ++cur)
	{
		if (slp->_data[cur] == data)	// 是data, 个数增加
			++count;
		else	// 不是data, 将当前元素拷贝到前count个地方
		{
			slp->_data[cur - count] = slp->_data[cur];
		}
	}
	slp->_size -= count;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值