《数据结构》线性表之顺序表的实现(C语言)

152 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情


实现目标

1.初始化顺序表

2.头插,尾插

3.头删,尾删

4.打印顺序表

初识顺序表

顺序表作为一种数据结构,它本质上就是一个数组。

我们所做的操作就是在这个数组上实现增删查改等功能。

我所做的是一个动态顺序表。

不用静态是因为静态顺序表的问题:给少了不够用,给多了用不完,不能灵活控制。

因为涉及到动态,就会用到动态内存开辟。

因为涉及到动态内存开辟,我们在写顺序表的时候,就要检查咱们的内存是否够,因此之后我们要写一个函数,关于检查开辟内存是否够用的。

顺序表等接口函数的实现

宏定义以及结构体

typedef int SQDataType;   这个宏定义就是把int类型改名,新名字叫SQDataType。目的是为了方便操作,比如我需要改成double类型,只需要将int改为double就行,增强代码维护性。

顺序表的结构体类型定义如下:

typedef struct SeqList
{
    SQDataType* a;
    int size;   //有效数据的个数
    int capacity; //容量
}SL;

这里我定义了一个结构体类型,用typedef重命名为SL。


初始化顺序表

void SeqListInit(SL* ps)  //初始化顺序表
{
    ps->a = NULL;
    ps->size = 0;
    ps->capacity = 0;
}

检查开辟内存是否够用

void SeqListCheckCapacity(SL* ps)
{
    if (ps->size == ps->capacity)
    {
        int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
        SQDataType* tmp = (SQDataType*)realloc(ps->a, newcapacity * sizeof(SQDataType));
        if (tmp == NULL)
        {
            printf("realloc fail\n");
            exit(-1);
        }
        else
        {
            ps->a = tmp;
            ps->capacity = newcapacity;
        }
    }
}

头插和尾插

void SeqListPushFront(SL* ps, SQDataType x) //头插
{
    //1.初始条件
    //2.结束过程
    //3.迭代过程
    SeqListCheckCapacity(ps);
    int end = ps->size - 1;
    while (end >= 0)
    {
        ps->a[end + 1] = ps->a[end];
        --end;
    }
    ps->a[0] = x;
    ps->size++;
}

void SeqListPushBack(SL* ps, SQDataType x) //尾插

{
    //检查顺序表是否满,满了就要扩容
    SeqListCheckCapacity(ps);
    ps->a[ps->size] = x;
    ps->size++;

}

头删和尾删

void SeqListPopFront(SL* ps)  //头删
{
    assert(ps->size > 0);
    int start = 1;
    while (start < ps->size)
    {
        ps->a[start - 1] = ps->a[start];
        ++start;
    }
    ps->size--;
}
void SeqListPopBack(SL* ps)  //尾删

{

    assert(ps->size > 0);  //断言

    ps->a[ps->size - 1] = 0;

    ps->size--;

}

打印顺序表

void SeqListPrint(SL* ps)  //打印顺序表
{
    for (int i = 0; i < ps->size; ++i)
    {
        printf("%d", ps->a[i]);
    }
    printf("\n");
}

assert函数介绍

在头删和尾删的时候,我使用了assert函数,他是断言函数。

比如我在头删中使用的是assert(ps->size > 0);

这就表示这条语句以下的所有语句的执行条件必须是 ps->size > 0 ,剩下的语句才能够执行。

断言是比较暴力的方法~

头文件 #include <assert.h>


int SeqListFind(SL* ps, SQDataType x)
{
    for (int i = 0; i < ps->size; ++i)
    {
        if (ps->a[i] == x)
        {
            return i;
        }
    }
    return -1;
}

void SeqListModity(SL* ps, int pos, SQDataType x)
{
    assert(pos < ps->size);
    ps->a[pos] = x;
}

释放内存

void SeqListDestory(SL* ps)
{
    free(ps->a);
    ps->a = NULL;
    ps->capacity = ps->size = 0;
}

部分菜单

void menu()
{
    printf("************************************************\n");
    printf("1.尾插数据,  2.头插数据\n");
    printf("3.尾删数据,  4.头删数据\n");
    printf("5.打印数据,  -1.退出\n"); 
    printf("************************************************\n");
    printf("请输入你操作选项:");
 
}