顺序表
顺序表:用一段地址连续的存储单元依次存储数据元素的线性结构,地址连续的空间,一般情况下采用数组,但数组有静态数组和动态数组,所以顺序表分为:静态顺序表和动态顺序表。
要模拟顺序表,那么我们就要清楚顺序表有哪些功能。
首先顺序表可以对其内容进行增删改。所以我们就要考虑到如何对其进行增删改,以及在不同情况下不同的应对方式。
接下来我们说说模拟顺序表的思路。
首先,既然是顺序表,那么我们可以用数组来模拟实现,再者为了代码的可读性强,并且修改调整性好我们来定义一个结构体来达到这一目的。
#define char Seqtype
#include <stddef.h>
#define SeqListMax 1000
typedef struct SeqList{
Seqtype data[SeqListMax];
size_t size;
}SeqList;
这里我们先定义一个结构体类型SeqList便于后面对结构体的操作访问等。然后定义了顺序表的大小用SeqListMax表示,用Seqtype来定义顺序表内内容的类型char,然后用一个szie_t也就是无符号长整形来定义这个顺序表内容的个数,来防止意外溢出的问题。接下来,我们就要开始对这个顺序表进行实现了。
我们先将这个顺序表的框架进行搭建
#define char Seqtype
#define SeqListMax 1000
typedef struct SeqList{
Seqtype data[SeqListMax];//利用宏来定义这个数组大小,便于以后的扩展缩小等
size_t size;//利用无符号长整型来防止意外溢出的情况,基本上足够用了,不太可能溢出
}SeqList;//定义顺序表结构体
基本所需要的都已经定义出来,接下来就是顺序表的结构框架的搭建
void SeqListPrint(SeqList* seqlist);//顺序表的打印。首先,我们在整个过程中,必须不断的测试我们的代码,而打印顺序表正是测试的好方法,所以顺序表的打印必不可缺
//实现
void SeqListPrint(SeqList* seqlist)
{
if( NULL == seqlist)
{
return;//传过来指针首先就应该判断是否为空,才能有后续的操作,后面不再注释
}
size_t i = 0;
for( ; i < seqlist->size; ++i)
{
printf("[%c] ",seqlist->data[i]);//打印顺序表内容,即数组内容
}
printf("\n");
}
void SeqListInit(SeqList* seqlist);//顺序表的初始化
//顺序表初始化,只需要将顺序表的元素个数设置为零即可
//实现
void SeqListInit(SeqList* seqlist)
{
if( NULL == seqlist)
{
return;
}
seqlist->size = 0;
}
在实现了对顺序表初始化以及打印之后,接下来就到了对顺序表内部元素进行操作的实现了,对顺序表内元素操作,包括增加元素、删除元素、查找元素、修改元素等几个方面。我们逐步分块实现。
对顺序表尾部插入、删除元素
void SeqListPushBack(SeqList* seqlist, Seqtype value);//尾部插入
尾部插入:应该先判断顺序表是否已满, 若顺序表已满,则打印该顺序表已满,然后直接return,若顺序表没有满,则将顺序表总大小加一,并在最后的位置插入想要插入的元素即可。
//实现
void SeqListPushBack(SeqList* seqlist, Seqtype value);//尾部插入
{
if( NULL == seqlist)
{
return;
}
if( seqlist->size >= SeqListMax)
{
printf("顺序表已满\n");
}
++seqlist->size;
seqlist->data[seqlist->size-1] = value;//插入到尾部
}
void SeqListPopBack(SeqList* seqlist, Seqtype value);//尾部删除
尾部删除:首先先判断该顺序表是否为空顺序表,若为空顺序表直接返回,并打印该顺序表为空表无须删除,若顺序表不是空表,则将顺序表的总元素个数减一,即可删除最后一个元素
//实现
void SeqListPopBack(SeqList* seqlist, Seqtype value)
{
if( NULL == seqlist)
{
return;
}
if( 0 == seqlist->size)
{
printf("该顺序表为空顺序表\n");
return;
}
--seqlist->size;//尾部删除
}
对顺序表头部插入、删除元素
void SeqListPushFront(SeqList* seqlist, Seqtype value);//头部插入
头部插入:在顺序表头部插入元素时,首先应判断顺序表是否已满,若已满,直接打印该顺序表已满,并return;若没有满,则将顺序表内总元素个数加一腾出一个空位置,然后再将最后一个元素赋值给空位置,以此类推,直至将第一个元素赋值完成后,再将要插入的元素赋给第一个位置即可。如下图;
//实现
void SeqListPushFront(SeqList* seqlist, Seqtype value)//头部插入
{
if( NULL == seqlist)
{
return;
}
if( seqlist->size >= SeqListMax)
{
printf("顺序表已满\n");
return;
}
++seqlist->size;
size_t i = size - 1;
for( ; i > 0; --i)
{
seqlist->data[i] = seqlist->data[i-1];
}
seqlist->data[0] = value;//头部插入
}
void SeqListPopFront(SeqList* seqlist);//头部删除
头部删除:在进行头部删除之前,首先应该判断该顺序表是否为空表,如果为空表,则打印该顺序表为空表,并且return。若不为空表,那么从顺序表第二个元素开始,向前一个元素进行覆盖,以此类推,最后再将顺序表总大小减一即可。
如下图;
//实现
void SeqListPopFront(SeqList* seqlist, Seqtype value)//头部删除
{
if( NULL == seqlist)
{
return;
}
if( 0 == seqlist->size)
{
printf("该顺序表为空顺序表\n");
}
size_i = 0;
for( ; i < seqlist->size; ++i)
{
seqlist->data[i] = seqlist->data[i+1];
}
--seqlist->size;
}
在顺序表任意位置插入、删除元素
//任意位置插入
void SeqListInsert(SeqList* seqlist, size_t pos, Seqtype value);
任意位置插入:插入之前先判断顺序表是否已满,若顺序表已满,则直接打印顺序表已满,并直接return;接着还要判断插入位置是否合法,若不合法,则打印插入位置越界。如果pos等于0,相当于头部插入,直接调用头部插入的即可。等到所有判断完之后,再进行插入,将顺序表总大小加一,再顺序表尾部开始,将前一个元素的内容赋给后面的,以此类推,直至pos位置,再将要插入的元素赋给pos即可,如下图:
//实现
//pos位置插入
void SeqListInsert(SeqList* seqlist, size_t pos, Seqtype value)
{
if( NULL == seqlist)
{
return;
}
if( seqlist->size >= SeqListMax)
{
printf(""顺序表已满\n);
return;
}
if( pos > seqlist->size)
{
printf("插入元素越界\n");
return;
}
if ( 0 == pos)
{
SeqListPushBack(seqlist, value);
return;
}
++seqlist->size;
size_t i = seqlist->size-1;
for( ; i-1 >= pos; --i)
{
seqlist->data[i] = seqlist->data[i-1];
}
seqlist->data[pos] = value;
}
//任意位置删除
void SeqListErase(SeqList* seqlist, size_t pos);
任意位置删除:在删除之前应该先判断顺序表是否为空,若为空,直接提示并return,接着再判断删除位置是否合法,不合法的话提示并return,最后再进行删除。删除的时候,从pos位置开始,将后一个元素覆盖到前一个元素,以此类推,直至到最后一个,然后再将顺序表总元素减一即可。
//实现
//在pos位置删除
void SeqListErase(SeqList* seqlist, size_t pos)
{
if( NULL == selist)
{
return;
}
if( 0 == seqlist->size)
{
printf("该顺序表为空顺序表\n");
}
if( pos >= seqlist->size)
{
printf("删除越界\n");
}
size_t i = pos;
for( ; i+1 < seqlist->size; ++i)
{
seqlist->data[i] = seqlist->data[i+1];
}
--seqlist->size;
}
在顺序表中读取pos位置元素
//读取pos位置元素
void SeqListRead(SeqList* seqlist, size_t pos, Seqtype* value);
读取pos位置元素:读取之前先判断读取是否合法,若不合法直接提示并return,合法直接打印即可。
//实现
int SeqListRead(SeqList* seqlist, size_t pos)
{
if( NULL == seqlist)
{
return;
}
if( pos >= seqlist->size)
{
return -1;
}
*value = seqlist->data[pos];
return 1;
在顺序表中修改pos位置元素
//修改pos位置元素
void SeqListChange(SeqList* seqlist, size_t pos, Seqtype value);
修改pos位置元素:修改之前判断pos位置是否合法,若不合法,直接提示并return,若合法将value直接覆盖到pos位置即可。
//实现
void SeqListChange(SeqList* seqlist, size_t pos, Seqtype value)
{
if( NULL == seqlist)
{
return;
}
if( pos >= seqlist->size)
{
printf("修改位置越界\n");
return;
}
seqlist->data[pos] = value;
}
在顺序表中查找指定元素
//查找指定元素
size_t SeqListFind(SeqList* seqlist, Seqtype value);
查找指定元素:遍历整个顺序表,如果查到元素则返回元素下标,若未查到返回-1.
//实现
size_t SeqListFind(SeqList* seqlist, Seqtype value)
{
if( NULL == seqlist)
{
return;
}
size_t pos = 0;
for( ; pos < seqlist->size; ++pos)
{
if(seqlist->data[pos] == value)
{
return pos;
}
}
return -1;
}
在顺序表中删除value,只删除第一次出现的
//在顺序表中删除value,只删除第一次出现的
void SeqListRemove(SeqList* seqlist, Seqtype value);
实现这个功能我们可以利用之前的代码来实现。
//实现
void SeqListRemove(SeqList* seqlist, Seqtype value)
{
if( NULL == seqlist)
{
return;
}
size_t pos = SeqListFind(seqlist,value);//先利用Find函数找到
SeqListErase(seqlist,pos);//利用Erase函数删除
}
在顺序表中删除所有value
//删除所有value
void SeqListRemoveAll(SeqList* seqlist, Seqtype value);
要删除所有,只需要利用Find找到,然后逐次删除即可。
//实现
void SeqListRemoveAll(SeqList* seqlist, Seqtype value)
{
if( NULL == seqlist)
{
return;
}
size_t i = 0;
for( ; i < seqlist->size; ++i)
{
if( seqlist->data[i] == value)
{
SeqListErase(seqlist,i);
i--;
}
}
}
冒泡排序顺序表内元素
void SeqListBubbleSort(SeqList* seqlist);
只需要写一个简单的排序代码即可
//实现
void Swap(Seqtype a, Seqtype b)
{
Seqtype tmp = a;
a = b;
b = tmp;
}
void SeqListBubbleSort(SeqList* seqlist)
{
if( NULL == seqlist)
{
return;
}
size_t count = 0;
for( ; count < seqlist->size; ++count)
{
size_t cur = 0;
for( ; cur < seqlist->size-1-count; ++cur)
{
if( seqlist->data[cur] > seqlist->data[cur+1])
{
Swap(&seqlist->data[cur],&seqlist->data[cur+1]);
}
}
}
}
升级版冒泡排序,可控制升序降序,利用回调函数
typedef int (*Cmp)(Seqtype a, Seqtype b);
void SeqListBubbleSortEX(SeqList* seqlist, Cmp cmp);
//实现
int Greater(Seqtype a, Seqtype b)
{
return a>b?1:0;
}
int Less(Seqtype a, Seqtype b)
{
return a<b?1:0;
}
void Swap(Seqtype a, Seqtype b)
{
Seqtype tmp = a;
a = b;
b = tmp;
}
void SeqListBubbleSortEX(SeqList* seqlist, Cmp cmp)
{
if( NULL == seqlist)
{
return;
}
size_t count = 0;
for( ; count < seqlist->size; ++count)
{
size_t cur = 0;
for( ; cur < seqlist->size-1-count; ++cur)
{
if(cmp(seqlist->data[cur],seqlist->data[cur+1]))//利用一个函数指针指向一个函数来控制排序的升序降序。
{
Swap(&seqlist->data[cur],&seqlist->data[cur+1]);
}
}
}
}
欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!