【数据结构】顺序表的实现

顺序表结构示意图如下:
在这里插入图片描述
顺序表特性:

  1. 顺序表,也叫线性表。顺序表是一种顺序存储结构,实际就是一个可以动态分配的一维数组。
  2. 顺序表的方便之处在于,可以根据下标,进行随机访问。
  3. 顺序表在实现头插操作时,要注意判断容量是否足够,不够的话要重新开辟足够大的空间,并将原来的数据拷贝过去,然后释放掉原来的空间,再挪动数据,进行头插操作。
  4. 顺序表在实行尾插操作时同样也要进行容量的判断。
  5. 顺序表的删除操作要记得判断该顺序表是否为空。
  6. 顺序表随机访问时,要判断下标是否合法。

顺序表主要实现模块如下

/seqlist.h
//定义顺序表的结构
#define SEQLIST_SIZE 8
#define DateType int
typedef struct SeqList
{
	DateType* base;//指向数据的指针
	size_t _capacity;
	size_t _size;
}SeqList;
void Swap(DateType* a, DateType* b)
{
	DateType tmp = *a;
	*a = *b;
	*b = tmp;
}
bool IsFull(SeqList* pList);
bool IsEmpty(SeqList* pList);
void SeqListShow(SeqList* pList);
bool _Inc(SeqList* pList, size_t new_capacity);//扩容操作
void SeqListInit(SeqList* pList);
void SeqListDestory(SeqList* pList);
void SeqListPushBack(SeqList* pList, DateType x);
void SeqListPushFront(SeqList* pList, DateType x);
void SeqListPopBack(SeqList* pList);
void SeqListPopFront(SeqList* pList);
void SeqListInsertByPos(SeqList* pList, size_t pos, DateType x);
void SeqListInsertByVal(SeqList* pList, DateType val);
void SeqListEraseByPos(SeqList* pList, size_t pos);
void SeqListEraseByVal(SeqList* pList, DateType val);
size_t SeqListFind(SeqList* pList, DateType val);
size_t SeqListLength(SeqList* pList);
size_t SeqListCapacity(SeqList* pList);
void SeqListSort(SeqList* pList);
void SeqListClean(SeqList* pList);
void SeqListReverse(SeqList* pList);
DateType SeqListFront(SeqList* pList);
DateType SeqListBack(SeqList* pList);
size_t SeqListBinarySearch(SeqList* pList, DateType val);
void SeqListEraseAll(SeqList* pList);
//
bool IsFull(SeqList* pList)
{
	assert(pList != NULL);
	return pList->_capacity == pList->_size;
}
bool IsEmpty(SeqList* pList)
{
	assert(pList != NULL);
	return pList->_size == 0;
}
void SeqListShow(SeqList* pList)
{
	assert(pList != NULL);
	for (size_t i = 0; i < pList->_size; ++i)
	{
		printf("%d ", pList->base[i]);
	}
	printf("\n");
}
bool _Inc(SeqList* pList, size_t new_capacity)//扩容操作
{
#if 0
	assert(pList != NULL && new_capacity > pList->_capacity);
	DateType* newbase = (DateType*)realloc(pList->base, sizeof(DateType) * new_capacity);
	//realloc包含了以下的前三个步骤
	if (newbase == NULL)
		return false;
	pList->base = newbase;
	pList->_capacity = new_capacity;
	return true;
#endif
	assert(pList != NULL && new_capacity > pList->_capacity);
	//① 开辟新空间
	DateType* newbase = (DateType*)malloc(sizeof(DateType) * new_capacity);
	if (newbase == NULL)
		return false;
	//② 拷贝原有数据
	memcpy(newbase, pList->base, sizeof(DateType) * pList->_capacity);
	//③ 释放旧空间
	free(pList->base);
	//④ 指向新空间,改变新容量
	pList->base = newbase;
	pList->_capacity = new_capacity;
	return true;
}
void SeqListInit(SeqList* pList)
{
	pList->_capacity = SEQLIST_SIZE;
	pList->base = (DateType*)malloc(pList->_capacity * sizeof(DateType));
	pList->_size = 0;
}
void SeqListDestory(SeqList* pList)
{
	assert(pList != NULL);
	free(pList->base);
	pList->_capacity = pList->_size = 0;
	pList->base = NULL;
}
void SeqListPushBack(SeqList* pList, DateType x)
{
	assert(pList != NULL);
	if (IsFull(pList) && !_Inc(pList,pList->_capacity*2))
	{
		printf("顺序表已满,元素%d无法正常插入\n",x);
	}
	else
	{
		pList->base[pList->_size++] = x;
	}
}
void SeqListPushFront(SeqList* pList, DateType x)
{
	assert(pList != NULL);
	if (IsFull(pList) && !_Inc(pList, pList->_capacity * 2))
		printf("该顺序表已满\n");
	else
	{
		for (int i = pList->_size-1; i >= 0; --i)
		{
			pList->base[i + 1] = pList->base[i];
		}
		pList->base[0] = x;
		++pList->_size;
	}
}
void SeqListPopBack(SeqList* pList)
{
	assert(pList != NULL);
	if(IsEmpty(pList))
		printf("该顺序表为空,无法正常尾删\n");
	else
		--pList->_size;
}
void SeqListPopFront(SeqList* pList)
{
	assert(pList != NULL);
	if (IsEmpty(pList))
	{
		printf("该顺序表为空,无法正常头删\n");
	}
	else if(pList->_size > 1)
	{
		for (int i = 1; i < pList->_size; ++i)
		{
			pList->base[i - 1] = pList->base[i];
		}
		--pList->_size;
	}
	else
	{
		SeqListPopBack(pList);//只有一个元素的情况下等于尾删
	}
}
void SeqListInsertByPos(SeqList* pList, size_t pos, DateType x)
{
	assert(pList != NULL && pos <= pList->_size);
	if (IsFull(pList) && !_Inc(pList, pList->_capacity * 2))
		printf("顺序表已满,无法正常进行插入\n");
	else
	{
		for (int i = pList->_size - 1; i >= (int)pos; --i)
		{
			pList->base[i + 1] = pList->base[i];
		}
		pList->base[pos] = x;
		++pList->_size;
	}
}
void SeqListInsertByVal(SeqList* pList, DateType val)
{
	assert(pList != NULL);
	if(IsFull(pList) && !_Inc(pList, pList->_capacity * 2))
		printf("顺序表已满,无法正常进行插入\n");
	else
	{
		size_t end = pList->_size - 1;
		while (end >= 0 && pList->base[end] > val)
		{
			pList->base[end + 1] = pList->base[end];
			--end;
		}
		pList->base[end + 1] = val;
		++pList->_size;
	}
}
void SeqListEraseByPos(SeqList* pList, size_t pos)
{
	assert(pList != NULL && pos < pList->_size);
	if(IsEmpty(pList))
		printf("该顺序表为空,无法正常尾删\n");
	else
	{
		for (int i = pos; i < pList->_size-1; ++i)
		{
			pList->base[i] = pList->base[i + 1];
		}
		--pList->_size;
	}
}
size_t SeqListFind(SeqList* pList, DateType val)
{
	assert(pList != NULL);
	size_t pos = -1;
	for (int i = 0; i < pList->_size; ++i)
	{
		if (pList->base[i] == val)
		{
			pos = i;
			break;
		}
	}
	return pos;
}

void SeqListEraseByVal(SeqList* pList, DateType val)
{
	assert(pList != NULL);
	if (IsEmpty(pList))
		printf("该顺序表为空,无法正常删除\n");
	else
	{
		size_t pos = SeqListFind(pList,val);
		if (pos == -1)
			printf("该元素不存在,删除失败!\n");
		else
			SeqListEraseByPos(pList, pos);
	}
}
size_t SeqListLength(SeqList* pList)
{
	assert(pList);
	return pList->_size;
}
size_t SeqListCapacity(SeqList* pList)
{
	assert(pList);
	return pList->_capacity;
}
void SeqListSort(SeqList* pList)
{
	assert(pList != NULL);
	for (int i = 0; i < pList->_size - 1; ++i)
	{
		for (int j = 0; j < pList->_size - i - 1; ++j)
		{
			if (pList->base[j] > pList->base[j + 1])
				Swap(&pList->base[j], &pList->base[j + 1]);
		}
	}
}
void SeqListClean(SeqList* pList)
{
	assert(pList);
	pList->_size = 0;
}
void SeqListReverse(SeqList* pList)
{
	assert(pList);
	if (pList->_size == 1)
		return;
	int start = 0, end = pList->_size - 1;
	while (start < end)
	{
		Swap(&pList->base[start], &pList->base[end]);
		++start;
		--end;
	}
}
DateType SeqListFront(SeqList* pList)
{
	assert(pList != NULL);
	if (IsEmpty(pList))
		return -1;
	else
		return pList->base[0];
}
DateType SeqListBack(SeqList* pList)
{
	assert(pList != NULL);
	if (IsEmpty(pList))
		return -1;
	else
		return pList->base[pList->_size-1];
	
}
size_t SeqListBinarySearch(SeqList* pList, DateType val)
{
	assert(pList != NULL);
	int low = 0, high = pList->_size - 1;
	while (low <= high)
	{
		int mid = low + ((high - low)>>1);
		if (val < pList->base[mid])
			high = mid - 1;
		else if (val > pList->base[mid])
			low = mid + 1;
		else
		{
			return mid;
			break;
		}
	}
	return -1;
}
void SeqListEraseAll(SeqList* pList)
{
	assert(pList != NULL);
	if (IsEmpty(pList))
		return;
	pList->_size = 0;
}

主要测试各个功能模块

///test.c
#include"commen.h"
#include"seqlist.h"

int main()
{
	SeqList list;
	SeqListInit(&list);

	DateType item;
	int select = 1;
	size_t pos;
	while (select)
	{
		printf("**************************************************\n");
		printf("***********************MENU***********************\n");
		printf("*  [1]push_back                   [2]push_front  *\n");
		printf("*  [3]show_list                   [0]quit_system *\n");
		printf("*  [4]pop_back                    [5]pop_front   *\n");
		printf("*  [6]insert_pos                  [7]insert_val  *\n");
		printf("*  [8]erase_pos                   [9]erase_val   *\n");
		printf("*  [10]find                       [11]length     *\n");
		printf("*  [12]capacity                   [13]sort       *\n");
		printf("*  [14]reverse                    [15]clear      *\n");
		printf("*  [16]front                      [17]back       *\n");
		printf("*  [18]binary_search              [19]earse_all  *\n");
		printf("**************************************************\n");
		printf("请选择->\n");
		scanf("%d", &select);
		if (select == 0)
			break;
		switch (select)
		{
		case 0:
			select = 0;
			break;
		case 1:
			printf("请输入要插入的元素,若要退出,输入-1->\n");
			while (scanf("%d", &item),item != -1)
			{
				SeqListPushBack(&list, item);
			}
			break;
		case 2:
			printf("请输入要插入的元素,若要退出,输入-1->\n");
			while (scanf("%d", &item), item != -1)
			{
				SeqListPushFront(&list, item);
			}
			break;
		case 3:
			SeqListShow(&list);
			break;
		case 4:
			SeqListPopBack(&list);
			break;
		case 5:
			SeqListPopFront(&list);
			break;
		case 6:
			printf("请输入要插入的位置->\n");
			scanf("%d", &pos);
			printf("请输入要插入的元素->\n");
			scanf("%d", &item);
			SeqListInsertByPos(&list, pos, item);
			break;
		case 7:
			printf("请输入要插入的元素->\n");
			scanf("%d", &item);
			SeqListInsertByVal(&list, item);
			break;
		case 8:
			printf("请输入要删除的位置->\n");
			scanf("%d", &pos);
			SeqListEraseByPos(&list, pos);
			break;
		case 9:
			printf("请输入要删除的元素->\n");
			scanf("%d", &item);
			SeqListEraseByVal(&list, item);
			break;
		case 10:
			printf("请输入要查找的元素->\n");
			scanf("%d", &item);
			pos = SeqListFind(&list, item);
			if (pos == -1)
				printf("元素%d不存在\n",item);
			else
				printf("元素%d所在下标为%d", item, pos);
			break;
		case 11:
			printf("length = %d\n", SeqListLength(&list));
			break;
		case 12:
			printf("capacity = %d\n", SeqListCapacity(&list));
			break;
		case 13:
			SeqListSort(&list);
			break;
		case 14:
			SeqListReverse(&list);
			break;
		case 15:
			SeqListClean(&list);
			break;
		case 16:
			if(SeqListFront(&list) == -1)
				printf("该顺序表为空,无法获取其头部元素\n");
			else
				printf("头元素为%d\n", SeqListFront(&list));
			break;
		case 17:
			if (SeqListBack(&list) == -1)
				printf("该顺序表为空,无法获取其尾部元素\n");
			else
				printf("末尾元素为%d\n", SeqListBack(&list));
			break;
		case 18:
			printf("请输入要查找的元素->\n");
			scanf("%d", &item);
			pos = SeqListBinarySearch(&list, item);
			if (pos == -1)
				printf("元素%d不存在\n", item);
			else
				printf("元素%d所在下标为%d", item, pos);
			break;
		case 19:
			SeqListEraseAll(&list);
			break;
		default:
			printf("输入非法,请重新选选择->\n");
			break;
		}
		Sleep(900);
		system("cls");

	}
	
	SeqListDestory(&list);
return 0;
}

在实现过程中出现的错误,详细在以下博客中介绍:
关于size_t与int之间的比较
关于运算符+与>>的优先级问题

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值