本文详解顺序表的实现,便于读者朋友们对数据结构的学习建立信心
顺序表是最简单的数据结构,可能有些读者朋友因为对C语言的基础不牢或是
学校老师从不带学生敲代码实现各种功能导致不能很好掌握,希望看完这
篇文章后可以有些收获。
定义:
- L 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
- 顺序表:可动态增长的数组,要求数据是连续存储的
给一个顺序表开辟空间,size表示数据个数,capacity表示容量,a表示元素首地址
void SLInit(SL* psl)
{
assert(psl);
psl->a = (SLDatatype*)malloc(sizeof(SLDatatype) * 4);
if (psl->a == NULL)
{
perror("malloc fail");
return;
}
psl->capacity = 4;
psl->size = 0;
}
随着数据的不断输入,空间不够,所以需要不断开辟空间满足需求,一般都是给现有的数据开辟两倍的大小
void SLCheckCapacity(SL* psl)
{
assert(psl);
if (psl->size == psl->capacity)
{
SLDatatype* tmp = (SLDatatype*)realloc(psl->a, sizeof(SLDatatype) * psl->capacity * 2);
if (tmp == NULL)
{
perror("realloc fail");
return;
}
psl->a = tmp;
psl->capacity *= 2;
}
}
void SLPushBack(SL* psl, SLDatatype x)
{
assert(psl);
psl->a[psl->size] = x;
psl->size++;
SLCheckCapacity(psl);
psl->a[psl->size++] = x;
/*SLInsert(psl, psl->size, x);*/
}
向顺序表头部插入一个数据,相当于生活中的排队,队伍中插队一个人,其他人应该都向后退,那么,应该最后一个人最先后退,否则没有空间供道德败坏者插入,在数据结构也是这样
图解:
代码实现:
void SLPushFront(SL* psl, SLDatatype x)
{
assert(psl);
SLCheckCapacity(psl);
// 挪动数据
int end = psl->size - 1;
while (end >= 0)
{
psl->a[end + 1] = psl->a[end];
--end;
}
psl->a[0] = x;
psl->size++;
/*SLInsert(psl, 0, x);*/
}
void SLPopBack(SL* psl)
{
assert(psl);
// 暴力检查
//assert(psl->size > 0);
温柔的检查
if (psl->size == 0)
return;
psl->a[psl->size - 1] = 0;
psl->size--;
/*SLErase(psl, psl->size - 1);*/
}
该问题可以和头插类比,还是经典的排队问题,头部删除一个数据,相当于第一位排队的顾客离开队伍,那么队伍就要前进一个身位,要实现此操作,则离开的顾客的下一个位置的顾客需要上前一个身位,这样第3位顾客可接替第2位顾客的位置,这样第4位顾客可接替第3位顾客的位置,反复直至最后一位顾客向前一个身位,头删问题轻松搞定.
图解:
void SLPopFront(SL* psl)
{
assert(psl);
// 暴力检查
assert(psl->size > 0);
/*int start = 0;
while (start < psl->size-1)
{
psl->a[start] = psl->a[start + 1];
start++;
}*/
int start = 1;
while (start < psl->size)
{
psl->a[start-1] = psl->a[start];
start++;
}
psl->size--;
//SLErase(psl, 0);
}
该操作是我们日常生活中使用较频繁的功能。
比如:在QQ群聊里搜索某人的信息
代码实现
int SLFind(SL* psl, SLDatatype x)
{
assert(psl);
for (int i = 0; i < psl->size; i++)
{
if (psl->a[i] == x)
{
return i;
}
}
return -1;
}
该功能使用场景较少,读者朋友们了解即可
void SLModify(SL* psl, int pos, SLDatatype x)
{
assert(psl);
assert(0 <= pos && pos < psl->size);
psl->a[pos] = x;
}
虽然以上操作是正确的,但是头插和尾插都是两个特殊位置,功能不完全,代码有一些冗余,可读性较差,针对此现象,可以对插入操作编写一个函数,可以实现顺序表任意位置的插入数据。
图解:
代码实现:(pso为数据插入的位置)
void SLInsert(SL* psl, int pos, SLDatatype x)
{
assert(psl);
//assert(0 <= pos <= psl->size);
assert(0 <= pos && pos <= psl->size);
SLCheckCapacity(psl);
int end = psl->size - 1;
while (end >= pos)
{
psl->a[end + 1] = psl->a[end];
--end;
}
psl->a[pos] = x;
psl->size++;
}
增加定位删除功能,通过下标pos来确定删除数据的位置
图解:
代码实现:
void SLErase(SL* psl, int pos)
{
assert(psl);
assert(0 <= pos && pos < psl->size);
//assert(psl->size > 0);
int start = pos + 1;
while (start < psl->size)
{
psl->a[start - 1] = psl->a[start];
++start;
}
psl->size--;
}
顺序表的玩法实际上就是对数组的操作,希望读者朋友们很好地掌握!
我追,一个成年人在一群尖叫的孩子中奔跑。但我不在乎。
我追,风拂过我的脸颊,我唇上挂着一个像潘杰希尔峡谷那样大大的微笑。
我追。
——————————————————————————————————《追风筝的人》