顺序表结构示意图如下:
顺序表特性:
- 顺序表,也叫线性表。顺序表是一种顺序存储结构,实际就是一个可以动态分配的一维数组。
- 顺序表的方便之处在于,可以根据下标,进行随机访问。
- 顺序表在实现头插操作时,要注意判断容量是否足够,不够的话要重新开辟足够大的空间,并将原来的数据拷贝过去,然后释放掉原来的空间,再挪动数据,进行头插操作。
- 顺序表在实行尾插操作时同样也要进行容量的判断。
- 顺序表的删除操作要记得判断该顺序表是否为空。
- 顺序表随机访问时,要判断下标是否合法。
顺序表主要实现模块如下
/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之间的比较
②关于运算符+与>>的优先级问题