数据结构之顺序表(C语言代码及注释)

一、顺序表的特点

顺序表存储数据,预先申请一整块足够大的存储空间,然后将数据按照次序逐一存储,数据之间紧密贴合,不留一丝空隙。

优点:在O(1)时间内查找元素;存储密度高。
缺点:扩容不方便;插入和删除元素不方便。

二、代码实现

头文件:SeqList.h

#ifndef SEQLIST_H_INCLUDED
#define SEQLIST_H_INCLUDED

#include <stdio.h>      //C语言标准库函数:用于输入和输出的函数、类型和宏。声明文件指针的FILE。常用的类型是size_t和fpos_t。
#include <malloc.h>     //是动态存储分配函数头文件,当对内存区进行操作时,调用相关函数。
#include <assert.h>     //assert函数像if判断语句中一样,然后如果该值为真则正常运行,否则报错,并调用abort(),产生异常中断,exit出来。
#include <stdbool.h>    //MDK的编译器中不能使用bool类型,是因为没有包含stdbool.h头文件。

#define SEQLIST_INIT_SIZE 8     //定义默认顺序表总长大小为8
typedef int ElemType;           //用将int宏替换为ElemType

//学数据结构最重要的内容
typedef struct SeqList
{
    ElemType *base;     //指向一个真实开辟的空间
    int capacity;       //容量:容量是数据表的总长度
    int size;           //大小:大小是数据表的当前长度
}SeqList;               //由于typedef,可用Seqlist来宏替换struct SeqList

bool Inc(SeqList *list);                     //声明扩容函数
void InitSeqList(SeqList *List);             //声明初始化函数
void push_back(SeqList *list,ElemType x);    //声明尾部插入函数
void push_front(SeqList *list,ElemType x);   //声明头部插入函数
void show_list(SeqList *list);               //声明显示函数
void pop_back(SeqList *list);                //声明尾部删除函数
void pop_front(SeqList *list);               //声明头部删除函数
void insert_pos(SeqList *list,int pos,ElemType x);   //声明按位置插入函数
int find(SeqList *list,ElemType key);        //声明查找元素函数
int length(SeqList *list);                   //声明查数据表的长度函数
void delete_pos(SeqList *list,int pos);      //声明删除特定位置的函数
void delete_val(SeqList *list,ElemType key); //声明删除特定元素的函数
void sort(SeqList *list);                    //声明排序函数
void resver(SeqList *list);                  //声明逆置函数
void clear(SeqList *list);                   //声明清除函数
void destroy(SeqList *list);                 //声明摧毁数据表函数

#endif // SEQLIST_H_INCLUDED

功能实现函数文件:SeqList.c

#include "SeqList.h"    //引入头文件

bool Inc(SeqList *list)   //扩容函数的实现
{
    ElemType *newbase = (ElemType*)realloc(list->base,sizeof(ElemType)*(list->capacity*2));//realloc更改已经配置的内存空间,将list->base所指的空间改为原来的两倍
    if(newbase == NULL)
    {
        printf("增配空间失败,内存不足。");
        return false;
    }
    list->base = newbase;
    list->capacity *= 2;    //容量变为原来的2倍
    return true;
}

void InitSeqList(SeqList *list)     //初始化函数的实现
{
    list->base = (ElemType *)malloc(sizeof(ElemType)*SEQLIST_INIT_SIZE);//使用malloc函数开辟一片int型连续的内存空间,并强制转换为int型指针,将这个指针地址交给base去管理
    assert(list->base != NULL);          //提示所指空间不能为空
    list->capacity = SEQLIST_INIT_SIZE;  //容量大小为8
    list->size = 0;                      //当前实际长度为0
}

void push_back(SeqList *list,ElemType x)    //尾插函数的实现:上一个元素的尾部插入
{
    if(list->size >= list->capacity && !Inc(list))        //判断数据表的空间是否已满,若满了则扩容,扩容失败则显示不能插入的值
    {
        printf("顺序表空间已满,不能在尾部插入%d。\n",x);
        return;
    }
    list->base[list->size] = x;   //在空间base的size位置处插入数据x
    list->size++;                 //当插入完成后size加一
}

void push_front(SeqList *list,ElemType x)  //头插函数的实现:在0位置插入一个数
{
    if(list->size >= list->capacity && !Inc(list))        //判断数据表的空间是否已满
    {
        printf("顺序表空间已满,不能在头部插入%d。\n",x);
        return;
    }
    for(int i = list->size;i>0;--i)       //将i赋值为size,比实际size大一个数
    {
        list->base[i] = list->base[i-1];  //将数据从尾部依次向后移动,将0号位空出来
    }
    list->base[0] = x;        //将所要头插的元素放入0号位
    list->size++;           //当插入完成后size加一
}

void show_list(SeqList *list)       //数据表显示函数的实现
{
    for(int i=0;i<list->size;++i)   //通过循环打印出size个数
    {
        printf("%d ",list->base[i]);
    }
    printf("\n");
}

void pop_back(SeqList *list)    //尾删函数的实现:将尾部的那一个数据删除
{
    if(list->size==0)   //空的数据表不能做删除操作
    {
        printf("顺序表为空,不能尾部删除数据。\n");
        return;
    }
    list->size--;      //size--代表有效数据减1,实际上最后一位的数据还在内存中,等待下一次写入数据将其覆盖
}

void pop_front(SeqList *list)   //头删函数的实现:将头部的那一个数删除
{
    if(list->size==0)   //空的数据表不能做删除操作
    {
        printf("顺序表为空,不能尾部删除数据。\n");
        return;
    }
    for(int i=0;i<list->size;i++)
    {
        list->base[i] = list->base[i+1];      //用后一个数据覆盖前一个数据
    }
    list->size--;       //实际长度减一
}

void insert_pos(SeqList *list,int pos,ElemType x)   //插入函数的实现
{
    if(pos<0 || pos>list->size)         //检验插入位置是否合法
    {
        printf("插入的数据非法,不能插入数据。\n");
        return;
    }
    if(list->size >= list->capacity && !Inc(list))        //判断数据表的空间是否已满
    {
        printf("顺序表空间已满,不能插入%d。\n",x);
        return;
    }
    for(int i=list->size;i>pos;i--)     //将要插入位置的后边的数向后移动
    {
        list->base[i] = list->base[i-1];
    }
    list->base[pos] = x;
    list->size++;
}

int find(SeqList *list,ElemType key)  //查找函数的实现
{
    for(int i=0;i<=list->size;i++)    //遍历顺序表查找是否有key值
    {
        if(list->base[i] == key)
        {
            return i;
        }
    }
    return -1;
}

int length(SeqList *list)     //数据表长度函数的实现
{
    return list->size;
}

void delete_pos(SeqList *list,int pos)
{
    if(pos<0 || pos>=list->size)         //检验插入位置是否合法
    {
        printf("删除的数据位置非法,不能删除数据。\n");
        return;
    }
    for(int i=pos;i<list->size-1;i++)
    {
        list->base[i]=list->base[i+1];  //直接向前覆盖元素
    }
    list->size--;
}

void delete_val(SeqList *list,ElemType key)     //顺序表删除特定元素函数的实现
{
    int pos = find(list,key);     //通过find函数查找是否有这个元素,若有则返回其位置
    if(pos==-1)
    {
        printf("要删除的数据不存在。");
        return;
    }
    delete_pos(list,pos);      //根据返回的位置值删除该元素,在该函数中有size--操作
}

void sort(SeqList *list)        //顺序表排序的实现
{
    for(int i=0;i<list->size-1;i++)             //冒泡排序
    {
        for(int j=0;j<list->size-i-1;j++)
        {
            if(list->base[j]>list->base[j+1])
            {
                ElemType tmp=list->base[j];
                list->base[j]=list->base[j+1];
                list->base[j+1]=tmp;
            }
        }
    }
}

void resver(SeqList *list)          //顺序表逆置函数的实现
{
    if(list->size==0 || list->size==1)
    {
        return;
    }
    int low = 0;                //低位指针
    int high = list->size-1;    //高位指针
    ElemType tmp;               //交换的辅助空间
    while(low<high)    //当高位指针等于或小于低位指针时,逆置完成
    {
        tmp = list->base[low];
        list->base[low] = list->base[high];
        list->base[high] = tmp;   //借助辅助空间进行数据交换

        low++;       //低位指针向右移
        high--;      //高位指针向左移
    }
}

void clear(SeqList *list)   //清除函数的实现
{
    list->size = 0;         //将有效长度置0,原有的元素就无法访问了,相当于被清除。
}

void destroy(SeqList *list)  //摧毁函数的实现
{
    free(list->base);      //free函数释放list-base
    list->base = NULL ;
    list->capacity = 0;
}

主函数文件:main.c

#include "SeqList.h"   //引入头文件

int main()
{
    SeqList mylist;         //创建了mylist结构,此时数据都是随机值
    InitSeqList(&mylist);   //初始化mylist。(1)为数据表开辟一片空间(2)为容量和大小进行填充

    ElemType Item;          //定义要放入的元素的概念
    ElemType pos;           //定义要插入的位置
    int select = 1;
    while(select)
    {
        printf("*********************************************\n");
        printf("*[1]  push_back             [2]  push_fornt *\n");    //尾插   头插
        printf("*[3]  show_list             [4]  pop_back   *\n");    //显示   尾删
        printf("*[5]  pop_list              [6]  insert_pos *\n");    //头删   任意插入
        printf("*[7]  find                  [8]  length     *\n");    //查找   求数据表长
        printf("*[9]  delete_pos            [10] delete_val *\n");    //按位置删  按数值删
        printf("*[11] sort                  [12] resver     *\n");    //排序   逆置
        printf("*[13] clear                 [14] destroy    *\n");    //清除   摧毁
        printf("*[0]  qiut_system                           *\n");    //退出系统
        printf("*********************************************\n");
        printf("请选择:>");
        scanf("%d",&select);
        if(select == 0)
            break;

        switch(select)
        {
        case 1:     //尾插
            printf("请输入要在尾部插入的数据(输入-1结束):>");
            //实现多个输入
            while(scanf("%d",&Item),Item != -1) //输入一个数Item,判断其是否为-1,不为则是真,为则是假(概念:逗号表达式)
            {
              push_back(&mylist,Item);
            }
            break;
        case 2:     //头插
            printf("请输入要在头部插入的数据(输入-1结束):>");
            //实现多个输入
            while(scanf("%d",&Item),Item != -1) //输入一个数Item,判断其是否为-1,不为则是真,为则是假(概念:逗号表达式)
            {
              push_front(&mylist,Item);
            }
            break;
        case 3:    //显示顺序表
            show_list(&mylist);
            break;
        case 4:    //尾删顺序表
            pop_back(&mylist);
            break;
        case 5:    //头删顺序表
            pop_front(&mylist);
            break;
        case 6:    //任意位置插入
            printf("请输入要插入的数据:>");
            scanf("%d",&Item);
            printf("请输入要插入的位置:>");
            scanf("%d",&pos);
            insert_pos(&mylist,pos,Item); //在mylist顺序表中的pos位置插入item
            break;
        case 7:   //查找数据
            printf("请输入要查找的数据:>");
            scanf("%d",&Item);
            pos=find(&mylist,Item);       //若查找成功则返回位置值,无查找的值则返回-1
            if(pos == -1)
                printf("查找的数据%d在顺序表中不存在。\n",Item);
            else
                printf("查找的数据%d在顺序表中的%d下标位置。\n",Item,pos);
            break;
        case 8:   //显示表当前长度
            printf("顺序表的长度为:>%d\n",length(&mylist));
            break;
        case 9:   //删除特定位置的元素
            printf("请输入要删除数据的位置:>");
            scanf("%d",&pos);
            delete_pos(&mylist,pos);
            break;
        case 10:  //删除特定值得元素
            printf("请输入要删除的数据:>");
            scanf("%d",&Item);
            delete_val(&mylist,Item);
            break;
        case 11:  //排序
            sort(&mylist);
            break;
        case 12:  //逆置
            resver(&mylist);
            break;
        case 13:  //清除数据表中的元素
            clear(&mylist);
            break;
        case 14:  //摧毁数据表:释放base指向的空间
            printf("提示:一旦摧毁顺序表后,只能退出程序。\n");
            destroy(&mylist);
            break;
        default:  //其它情况
            printf("输入的选择错误,请重新输入。\n");
            break;
        }
    }

    return 0;
}

/**
    本次编程所得:
    1.编程要画模型,光想是不行的。多动手,多模仿,多批注。
    2.前期一定要把指针和结构体搞明白(有空就去CSDN上看)。
    3.一定要明白节点中的元素含义。以及一些算法的巧妙使用。
    4.在同一工程下创建多文件:https://blog.csdn.net/weixin_43469680/article/details/103459399
*/

三、说明
编写代码的IDE是CodeBlock,主要实现了顺序表的大部分功能。
代码百度网盘链接:
链接:https://pan.baidu.com/s/1Gthj8wfCiXaKc01GxC22Zw
提取码:foys

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值