C语言实现基础数据结构——顺序表

本文详细介绍了顺序表的数据结构,包括静态顺序表和动态顺序表的概念、底层实现、增删改查操作,以及如何将其应用到通讯录管理系统中,包括初始化、添加、删除和查找等功能。
摘要由CSDN通过智能技术生成

目录

顺序表

顺序表和数组

顺序表的分类

静态顺序表

动态顺序表

静态顺序表和动态顺序表的比较

动态顺序表的实现

主要实现功能

顺序表的初始化

顺序表的销毁

顺序表的打印

顺序表的尾部插入

顺序表的头部插入

顺序表的尾部删除

顺序表的头部删除

顺序表的指定位置插入

顺序表的指定位置删除

顺序表中的数值查找

顺序表应用——通讯录

主要实现的功能

初始化通讯录

添加通讯录数据

展示通讯录数据

删除通讯录数据

查找通讯录数据

修改通讯录数据

销毁通讯录数据


顺序表

顺序表和数组

顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口

📌

顺序表在逻辑结构上连续,并且在物理结构上也是连续

顺序表的分类

静态顺序表

数组的大小固定的顺序表

//静态顺序表
typedef int SLDataType;
#define N 7
typedef struct SeqList_static
{
    SLDataType SeqList[N];//数组长度为7的顺序表
    int size;//有效数值的个数,此处有效数值相当于数组的下标,并且总是指向最后一个有效数值的下一位
};

动态顺序表

数组大小可以指定改变的顺序表

typedef int SLDataType;
typedef struct SeqList_dynamic
{
    SLDataType* SeqList;//指向可以修改大小的数据空间
    int size;//有效数据个数
    int capacity;//数据空间的总大小
};

静态顺序表和动态顺序表的比较

静态顺序表空间给少了不够用,给多了造成空间浪费,实际使用顺序表更多使用动态顺序表

动态顺序表的实现

主要实现功能

//初始化和销毁 
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);
//扩容 
void SLCheckCapacity(SL* ps);
//头部插⼊删除 / 尾部插⼊删除 
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
//指定位置之前插⼊/删除数据 
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
int SLFind(SL* ps, SLDataType x);

顺序表的初始化

//顺序表的初始化
void SLInit(SL_d* ps)
{
    assert(ps);//确保没有传入空指针
    ps->SeqList = NULL;
    ps->size = 0;
}

顺序表的销毁

//顺序表的销毁
void SLDestroy(SL_d* ps)
{
    assert(ps);

    if (ps->SeqList)
    {
        free(ps->SeqList);
    }
    
    ps->SeqList = NULL;
    ps->size = 0;
    ps->capacity = 0;
}

顺序表的打印

//顺序表的打印
void SLPrint(SL_d* ps)
{
    assert(ps);
    assert(ps->SeqList);

    for (int i = 0; i < ps->size; i++)
    {
        printf("%d ", ps->SeqList[i]);
    }
    putchar('\n');
}

顺序表的尾部插入

基本思路:判断是否需要扩容再进行尾部插入

    1. 当顺序表有足够的空间插入时(包括有内容和顺序表为空):直接在顺序表尾部插入
    2. 当顺序表空间已满时:扩容后再插入

//顺序表的扩容 
void SLCheckCapacity(SL_d* ps)
{
    assert(ps);
    
    SLDataType* temp = NULL;
    if (ps->size == ps->capacity)
    {
        int newCapacity = ps->capacity;
        temp = (SLDataType*)realloc(ps->SeqList, (newCapacity =  (ps->capacity == 0) ? 4 : (ps->capacity * 2)) * sizeof(SLDataType));//扩容规则:成倍数增加(一般1.5倍或2倍)
        assert(temp);
        ps->SeqList = temp;
        ps->capacity = newCapacity;
        temp = NULL;
    }
}

//顺序表的尾部插入
//当顺序表有足够的空间插入时(包括有内容和顺序表为空)
void SLPushBack(SL_d* ps, SLDataType x)
{
    assert(ps);
    
    //顺序表的扩容 
    SLCheckCapacity(ps);//确保SeqList指针不为空之后判断容量是否足够

    //当顺序表有足够的空间插入时(包括有内容和顺序表为空)
    ps->SeqList[ps->size] = x;
    ps->size++;

    //当顺序表空间已满时
    //先进行扩容操作
    //再进行插入
}

顺序表的头部插入

基本思路:判断容量是否足够再进行头部插入

    1. 当顺序表有足够的空间插入时(包括有内容和顺序表为空):直接在顺序表尾部插入
    2. 当顺序表空间已满时:扩容后再插入
//顺序表的扩容 
void SLCheckCapacity(SL_d* ps)
{
    assert(ps);
    
    SLDataType* temp = NULL;
    if (ps->size == ps->capacity)
    {
        int newCapacity = ps->capacity;
        temp = (SLDataType*)realloc(ps->SeqList, (newCapacity =  (ps->capacity == 0) ? (ps->capacity) : (ps->capacity * 2)) * sizeof(SLDataType));//扩容规则:成倍数增加(一般1.5倍或2倍)
        assert(temp);
        ps->SeqList = temp;
        ps->capacity = newCapacity;
        temp = NULL;
    }
}

//顺序表的头部插入
void SLPushFront(SL_d* ps, SLDataType x)
{
    assert(ps);

    //顺序表的扩容
    SLCheckCapacity(ps);//确保SeqList指针不为空之后判断容量是否足够

    //顺序表有足够的空间插入时(包括有内容和顺序表为空)
    for (int i = ps->size - 1; i >= 0; i--)
    {
        ps->SeqList[i + 1] = ps->SeqList[i];//ps->SeqList[0] = ps->SeqList[1]
    }
    ps->SeqList[0] = x;
    ps->size++;

    //当顺序表空间已满时
    //先进行扩容操作
    //再进行插入
}

顺序表的尾部删除

基本思路:将有效数值变量前移达到“看不见即删除”的效果

//顺序表的尾部删除
void SLPopBack(SL_d* ps)
{
    assert(ps);
    assert(ps->size);//确保顺序表内不为空
    ps->size--;
}

顺序表的头部删除

基本思路:将后面的值一一往前覆盖,并且有效数值变量前移

//顺序表的头部删除
void SLPopFront(SL_d* ps)
{
    assert(ps);
    assert(ps->size);

    for (int i = 0; i < ps->size; i++)
    {
        ps->SeqList[i] = ps->SeqList[i + 1];
    }
    ps->size--;
}

顺序表的指定位置插入

基本思路:以插入位置(第一个数值位置为1)为标准,将插入位置后面的内容向后移动,并且有效数值变量后移

//顺序表的指定位置插入
void SLInsert(SL_d* ps, int pos, SLDataType x)
{
    assert(ps);
    
    for (int i = ps->size - 1; i >= pos - 1; i--)
    {
        ps->SeqList[i + 1] = ps->SeqList[i];
    }
    ps->SeqList[pos - 1] = x;
    ps->size++;
}

顺序表的指定位置删除

基本思路:以删除位置(第一个数值位置为1)为标准,将删除位置之后的数值覆盖删除位置的数值,并且有效数值前移

//顺序表的指定位置删除
void SLErase(SL_d* ps, int pos)
{
    assert(ps);

    for (int i = pos; i < ps->size ; i++)
    {
        ps->SeqList[i - 1] = ps->SeqList[i];
    }
    ps->size--;
}

顺序表中的数值查找

基本思路:遍历顺序表查找

//使用遍历顺序表在顺序表中找指定数值
int SLFind(SL_d* ps, SLDataType x)
{
    assert(ps);
    for (int i = 0; i < ps->size; i++)
    {
        if (ps->SeqList[i] == x)
        {
            return i + 1;
        }
    }
    return 0;
}

顺序表应用——通讯录

主要实现的功能

  1. 至少能够存储100个⼈的通讯信息
  2. 能够保存用户信息:名字、性别、年龄、电话、地址等
  3. 增加联系⼈信息
  4. 删除指定联系⼈
  5. 查找制定联系⼈
  6. 修改指定联系⼈
  7. 显示联系⼈信息
//初始化通讯录 
void InitContact(contact* con);
//添加通讯录数据 
void AddContact(contact* con);
//删除通讯录数据 
void DelContact(contact* con);
//展示通讯录数据 
void ShowContact(contact* con);
//查找通讯录数据 
void FindContact(contact* con);
//修改通讯录数据 
void ModifyContact(contact* con);
//销毁通讯录数据 
void DestroyContact(contact* con);

初始化通讯录

//初始化通讯录
void InitContact(contact* con)
{
    SLInit(&con);
}

添加通讯录数据

//添加联系人
void AddContact(contact* con)
{
    info c = { 0 };
    printf("请输入联系人姓名:");
    scanf("%s", c.name);
    printf("请输入联系人年龄:");
    scanf("%d", &(c.age));
    printf("请输入联系人性别:");
    scanf("%s", c.gender);
    printf("请输入联系人电话:");
    scanf("%s", c.phoneNum);
    printf("请输入联系人住址:");
    scanf("%s", c.address);

    assert(con);
    SLPushBack(con, c);
}

展示通讯录数据

//显示联系人
void ShowContact(contact* con)
{
    assert(con);
    printf("姓名\t年龄\t性别\t\t电话\t住址\n");
    for (int i = 0; i < con->size; i++)
    {
        printf("%s\t%d\t%s\t\t%s\t%s\t\n", 
            con->SeqList[i].name, con->SeqList[i].age, 
            con->SeqList[i].gender, con->SeqList[i].phoneNum, 
            con->SeqList[i].address);
    }
}

删除通讯录数据

//查找联系人,以按名字查找为例
int FindContact(contact* con, char *name)
{
    assert(con);
    assert(con->SeqList);

    for (int i = 0; i < con->size; i++)
    {
        if (strcmp(con->SeqList[i].name, name) == 0)
        {
            printf("姓名\t年龄\t性别\t\t电话\t住址\n");
            printf("%s\t%d\t%s\t\t%s\t%s\t\n",
                con->SeqList[i].name, con->SeqList[i].age,
                con->SeqList[i].gender, con->SeqList[i].phoneNum,
                con->SeqList[i].address);
            return i + 1;
        }
        else
        {
            continue;
        }
        if(i == con->size - 1)
        { 
            printf("查找无此人");
            return 0;
        }
    }
}


//删除联系人
void DelContact(contact* con, char *name)
{
    assert(con);
    assert(con->SeqList);

    //删除联系人首先得有需要删除的联系人,以按名字查找为例
    if (FindContact(con, name))
    {
        SLErase(con, FindContact(con, name));
    }
}

查找通讯录数据

//查找联系人,以按名字查找为例
int FindContact(contact* con, char *name)
{
    assert(con);
    assert(con->SeqList);

    for (int i = 0; i < con->size; i++)
    {
        if (strcmp(con->SeqList[i].name, name) == 0)
        {
            printf("查找到的联系人如下:\n");
            printf("姓名\t年龄\t性别\t\t电话\t住址\n");
            printf("%s\t%d\t%s\t\t%s\t%s\t\n",
                con->SeqList[i].name, con->SeqList[i].age,
                con->SeqList[i].gender, con->SeqList[i].phoneNum,
                con->SeqList[i].address);
            return i + 1;
        }
    }
    printf("查找无此人\n");
    return 0;
}

修改通讯录数据

//修改联系人
void ModifyContact(contact* con, char* name)
{
    assert(con);
    assert(con->SeqList);
    //修改联系人前提得有需要修改的联系人
    int ret = FindContact(con, name) - 1;//函数返回的不是下标,而是当前内容所在的位置,从1开始计数
    if (ret)
    {
        printf("请输入需要修改的联系人姓名:");
        scanf("%s", con->SeqList[ret].name);
        printf("请输入需要修改的联系人年龄:");
        scanf("%d", &(con->SeqList[ret].age));
        printf("请输入需要修改的联系人性别:");
        scanf("%s", con->SeqList[ret].gender);
        printf("请输入需要修改的联系人电话:");
        scanf("%s", con->SeqList[ret].phoneNum);
        printf("请输入需要修改的联系人住址:");
        scanf("%s", con->SeqList[ret].address);    
    }
}

销毁通讯录数据

//销毁通讯录
void DestroyContact(contact* con)
{
    SLDestroy(con);
}
  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

怡晗★

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值