数据结构:线性表-详解顺序表

《详解顺序表》

目录:

一、顺序表的定义及其特点

二、顺序表的运算(概述)

三、顺序表的实现

四、完整的Demo

五、小结

六、参考文献

 

一、顺序表的定义及其特点

  顺序表又称顺序存储结构,是线性表的一种,专门存储逻辑关系为“一对一”的数据。顺序表是在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素、使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系。

二、顺序表的运算(概述)

  1.初始化

    顺序表的初始化时除了要申请足够大小的物理空间之外,为了方便后续的数据处理,应当还有实时记录下顺序表申请的存储容量顺序表的长度即数据元素个数。

  2.查找

    顺序表的查找运算是查找表中元素$a_ i$ 的值。顺序表具有随机存取的特点,因此数据元素$a_i$的值可以直接通过数组下标定位取得。

  3.插入

    顺序表的插入运算是在顺序表L的元素$a_i$之后插入新的元素x。若i = -1,则表示将新的元素插入顺序表的最前面。首先需要对i是否越界、顺序表存储空间是否已满进行判断。新元素x插入到顺序表之前,需要将下标之后的所有元素依次向后移动一个位置。

  4.删除

    顺序表的删除运算的功能是将元素$a_i$删除。须先对i是否越界、顺序表是否为空进行判断。在顺序表中,逻辑上相邻的数据元素在物理位置上也需相邻,因此不能直接简单删除元素$a_i$,而需将下标之后的所有元素依次向前移动一个位置。

  5.输出

    顺序表的输出运算是将顺序表的元素依次输出。

三、顺序表的实现

  代码实现:

    0.声明:

      首先需要新建一个.h文件,在其中进行结构与方法的声明。结构体“SequenceList”中使用定义的“ListType”类型与常量“MAXSIZE”,声明了一个数组。该数组申请的物理存储大小为“MAXSIZE”决定,存储元素类型为“ListType”决定。同时为了后续的数据操作,还声明了一个整形“length”用于存储元素下标。结构体声明之外为顺序表功能方法声明具体代码如下:

/*
    SequenceLsist.h 顺序表 
*/
#define MAXSIZE 598//顺序表最大长度 
typedef int ListType;//顺序表存储的数据类型,在此定义别名以方便变更存储类型 

typedef struct SequenceList{
    
    ListType data[MAXSIZE];//定义用于存储的数组及其长度 
    int length;//当前顺序表数据下标 
    
}SeqList;

/*
    函数声明 
*/

int init(SeqList *L);//初始化顺序表 

int getSize(SeqList *L);//获取当前存储的数据长度 

int isEmpty(SeqList *L);//顺序表判空 

int isFull(SeqList *L);//顺序表判满 

int insert(SeqList *L, int site, ListType data); //顺序表插入,site为位置,data为需要插入的数据 

int update(SeqList *L, int site, ListType data);//变更顺序表元素 

int expurgate(SeqList *L, int site);//移除site上的数据 

int check(SeqList *L, int site, int state);//操作位置合法性判断(state为1时为插入操作) 

ListType get(SeqList *L, int site);//获取第site上的数据 

int find(SeqList *L, ListType data);//查找顺序表中是否存在该元素 

void clear(SeqList *L); //清空顺序表 

void print(SeqList *L);//打印顺序表 
View Code

 

    1.实现部分:

      在完成声明部分后,再新建一个.c文件,引入刚才声明的.h文件并实现。具体代码在完整Demo部分。

    2.交互部分:

      启动时先打印一个图形进行展示:

    char *patterning[] = {
    "                                    \n",
    "                                             4&(\n",
    "                                           ` ~&&\\yM#1\n",
    "                                            ,_'Q!!NMW&\n",
    "                                            WCb 7N@4D Q%,,\n",
    "                                            PM'*MDk#M0p,\n",
    "                                                ]@J0&e~~4r' ,+bQEQ\n",
    "                                                 F8I&#'   _&B$$bW#&$\n",
    "                                                  &0A1   L#DE&E~!Q&Q,\n",
    "                                     _=,        ,#0RN1  _T@0$'   ZN$Q.   grNq5\n",
    "                                     ^ 'd     ,0K0pK^  g*Q0g'    #Q4p&,/g9X*&#,_/ (q\n",
    "                                      TA1   ,sDQWh4^  x&NM0` _   #FQ#K#fA#   `*K#XWP~-\n",
    "                                       ^&p,wNMM0qD: /HE#EN' ..#g)~ '@NG0Qx,    `=X*\n",
    "                                      '  '43$'hEk##m0D04f_g  ~^ ~   `-00**0\n",
    "                                               =0#ONq2W0BF^#, _            p,,\n",
    "                                                 `  ^''~    ~b''        **R3`\n",
    "                                                          ow,F         +#F~'\n",
    "                                                          /-9!          `\ \n",
    "                                                           R\n"
    };
    

    for(int i = 0;i < 19;i++){
        printf("%s",patterning[i]);
    }
View Code

      而后打印程序名称、菜单列表与操作提示:

        printf("<----------------------------------------------------顺序表演示程序--------------------------------------------------->\n");
        printf("0. 退出程序\n");    
        printf("1. 初始化顺序表\n");
        printf("2. 打印顺序表\n");
        printf("3. 插入元素\n");
        printf("4. 删除元素\n");
        printf("5. 查找元素\n");
        printf("6. 变更元素\n");
        printf("7. 获取元素\n");
        printf("8. 顺序表判空\n");
        printf("9. 顺序表判满\n");
        printf("10. 顺序表长度查询\n");
        printf("11. 清空顺序表\n");
        printf("12. 帮助\n");
        printf("请输入操作选项(0~11,0为退出):"); 
View Code

      通过scanf函数读取操作并使用switch函数对操作进行判断。同时使用do-while函数包裹以上代码,只有用户输入退出标记时才会结束程序。

    3.顺序表的初始化:

      调用处:

                if(!init(&L)){
                    printf("初始化完成\n\n");
                } else {
                    printf("初始化失败\n\n");
                }
View Code

      实现处:

int init(SeqList *L) {
    
    L->length = -1;
    
    return 0;
}
View Code

      实际操作为将传入的结构体指针中用于记录下标的变量指向-1。

    4.获取顺序表的当前长度:

      调用处:

        printf("该位置的元素为:%d", getSize(&L));

      实现处:

        int getSize(SeqList *L) {
            return (L->length + 1);
        } 

      将结构体指针的下标变量+1即为长度,将其返回。

    5.顺序表判空:

      调用处:

             if(isEmpty(&L)){
                 printf("顺序表为空\n\n");
             } else {
                 printf("顺序表不为空\n\n");
             }

      实现处:

        int isEmpty(SeqList *L) {
             return (L->length + 1) == 0 ? 1 : 0;
        }

      判断下标是否为-1,下标-1即代表顺序表为空。

    6.顺序表判满:

      调用处:

             if(isFull(&L)){
                printf("顺序表已满\n\n");
             } else {
                printf("顺序表未满\n\n");
             }

      实现处:

        int isFull(SeqList *L) {
             return (L->length + 1) >= MAXSIZE ? 1 : 0;
        }

       判断下标+1是否大于等于最大长度。

    7.插入元素:

      调用处:

             printf("请输入插入位置与插入数据(以逗号间隔):");
             scanf("%d,%d", &site,&data);
             insert(&L, site, data);

      实现处:

int insert(SeqList *L, int site, ListType data) {
    
    if(!isFull(L)){//判断是否已满 
        
        if(check(L, site, 1)){//合法性判断 
            
            for(int i = (L->length);i > (site - 1);i--){//将插入位置之后的元素向后移 

                L->data[i + 1] = L->data[i];
            }
            
            L->data[site - 1] = data;//插入元素
            L->length++;
            return 1;
        } else {
            
            printf("插入位置不合法!\n\n"); 
            return 0;
        } 

    } else {
        
        printf("顺序表已满!\n\n"); 
        return 0;
    } 
}
View Code

       首先判断顺序表是否已满,再判断操作位置合法性,验证通过后使用循环将插入位置之后的元素遍历并向后移动一位,将元素插入指定位置最后将下标+1,完成操作。

    8.元素变更:

      调用处:

             printf("请输入更新位置与更新元素(以逗号间隔):");
             scanf("%d,%d", &site, &data);
             update(&L, site, data);

      实现处:

int update(SeqList *L, int site, ListType data) {
    
    int flag = 0;
        
    if(isEmpty(L)){//判空 
        printf("顺序表为空!\n\n"); 
    } else {
        if(check(L, site, 0)){
            L->data[site - 1] = data;
            flag = 1;
        } else {
            printf("更新位置不合法!\n\n"); 
        }
    }
    
    return flag; 
} 
View Code

       先对顺序表判空,再判断操作位置合法性,验证通过后替换元素完成操作。

    9.移除指定位置的数据:

      调用处:

             printf("请输入删除位置:");
             scanf("%d", &site);
             expurgate(&L, site);

      实现处:

int expurgate(SeqList *L, int site) {
    
        if(!isEmpty(L)){//判断是否为空 
        
            if(check(L, site, 0)){//合法性判断 
            
                for(int i = (site - 1);i <= (L->length);i++){
                    L->data[i - 1] = L->data[i];
                }
                
                L->length--;    
                return 1;
            } else {
                
                printf("删除位置不合法!\n\n"); 
                return 0;
            } 
    
        } else {
            
            printf("顺序表为空!\n\n"); 
            return 0;
        } 
} 
View Code

       判空与合法性检查,验证通过后使用循环遍历将该位置之后的所有元素并向前移动一位,覆盖数据 ,最后将下标-1完成操作。

    10.清空顺序表:

      调用处:

            clear(&L);

      实现处:

       void clear(SeqList *L) {
           L->length = -1;
       }

       将下标重新指定为-1,让后续数据从头开始录入。

    11.打印顺序表:

      调用处:

           print(&L);

      实现处:

void print(SeqList *L){
    if(isEmpty(L)){
        printf("顺序表为空!\n\n"); 
        
        return ;
    }  else {
        printf("当前顺序表为: [");
        for(int i = 0;i <= L->length;i++){
            printf("%d", L->data[i]);
            
            if(i == L->length){
                printf("]\n\n");
            } else{
                printf(", ");
            }
        }

    }
} 
View Code

       判空,而后遍历元素并打印。

    12.其他: 

          printf("本应用程序为数据结构-顺序表演示程序,用于课程实践与研究。由季文天老师指导,史恒珲开发。\n\n");

       帮助。

    13.运行截图:

 

四、完整的Demo

  函数与结构体声明(SequenceList.h):

/*
    SequenceLsist.h 顺序表 
*/
#define MAXSIZE 598//顺序表最大长度 
typedef int ListType;//顺序表存储的数据类型,在此定义别名以方便变更存储类型 

typedef struct SequenceList{
    
    ListType data[MAXSIZE];//定义用于存储的数组及其长度 
    int length;//当前顺序表数据下标 
    
}SeqList;

/*
    函数声明 
*/

int init(SeqList *L);//初始化顺序表 

int getSize(SeqList *L);//获取当前存储的数据长度 

int isEmpty(SeqList *L);//顺序表判空 

int isFull(SeqList *L);//顺序表判满 

int insert(SeqList *L, int site, ListType data); //顺序表插入,site为位置,data为需要插入的数据 

int update(SeqList *L, int site, ListType data);//变更顺序表元素 

int expurgate(SeqList *L, int site);//移除site上的数据 

int check(SeqList *L, int site, int state);//操作位置合法性判断(state为1时为插入操作) 

ListType get(SeqList *L, int site);//获取第site上的数据 

int find(SeqList *L, ListType data);//查找顺序表中是否存在该元素 

void clear(SeqList *L); //清空顺序表 

void print(SeqList *L);//打印顺序表 
View Code

 

  函数的实现(SequenceList.c):

#include "SequenceList.h"
#include <stdio.h>

int init(SeqList *L) {
    
    L->length = -1;
    
    return 0;
}

int getSize(SeqList *L) {
    
    return (L->length + 1);
} 

int isEmpty(SeqList *L) {
    return (L->length + 1) == 0 ? 1 : 0;
}

int isFull(SeqList *L) {
    
    return (L->length + 1) >= MAXSIZE ? 1 : 0;
}

int check(SeqList *L, int site, int state) {
    
    int flag = 0; 
    
    if(state){//判断是否是插入操作 
    
        if(site > 0 && site < MAXSIZE){
            
            flag = 1;
        }
    } else {//(删除 || 读取 || 更新)位置合法判断 
    
        if (site > 0 && site <= (L->length + 1)){
            
            flag = 1;
        }
    }
    return flag;
}

int insert(SeqList *L, int site, ListType data) {
    
    if(!isFull(L)){//判断是否已满 
        
        if(check(L, site, 1)){//合法性判断 
            
            for(int i = (L->length);i > (site - 1);i--){//将插入位置之后的元素向后移 

                L->data[i + 1] = L->data[i];
            }
            
            L->data[site - 1] = data;//插入元素
            L->length++;
            printf("插入操作已完成!\n");
            return 1;
        } else {
            
            printf("Error[10004]:插入位置不合法!\n\n"); 
            return 0;
        } 

    } else {
        
        printf("Error[10003]:顺序表已满!\n\n"); 
        return 0;
    } 
}

int expurgate(SeqList *L, int site) {
    
        if(!isEmpty(L)){//判断是否为空 
        
            if(check(L, site, 0)){//合法性判断 
            
                for(int i = (site - 1);i <= (L->length);i++){
                    L->data[i - 1] = L->data[i];
                }
                
                L->length--;    
                printf("删除操作已完成!\n");
                return 1;
            } else {
                
                printf("Error[10005]:删除位置不合法!\n\n"); 
                return 0;
            } 
    
        } else {
            
            printf("Error[10002]:顺序表为空!\n\n"); 
            return 0;
        } 
} 

void clear(SeqList *L) {
    L->length = -1;
    printf("顺序表已清空!\n");
}

int get(SeqList *L, int site) {
    
    if(!isEmpty(L)){
        
        if(check(L, site, 0)){
            
            return L->data[site - 1]; 
        } else{
            
            printf("Error[10006]:读取位置不合法!\n\n"); 
        } 
    } else {
        
        printf("Error[10002]:顺序表为空!\n\n"); 
    } 
    return 0;
}

void print(SeqList *L){
    if(isEmpty(L)){
        printf("Error[10002]:顺序表为空!\n\n"); 
        
        return ;
    }  else {
        printf("当前顺序表为: [");
        for(int i = 0;i <= L->length;i++){
            printf("%d", L->data[i]);
            
            if(i == L->length){
                printf("]\n\n");
            } else{
                printf(", ");
            }
        }

    }
} 

int find(SeqList *L, ListType data){
    
    int flag = 0;
    
    for(int i = 0;i <= L->length;i++){
        if(data == L->data[i]){
            flag = 1;
            printf("元素存在,为顺序表中第%d个元素\n", (i + 1));
        }
    }
    
    return flag;
} 

int update(SeqList *L, int site, ListType data) {
    
    int flag = 0;
        
    if(isEmpty(L)){//判空 
        printf("Error[10002]:顺序表为空!\n\n"); 
    } else {
        if(check(L, site, 0)){
            L->data[site - 1] = data;
            flag = 1;
            printf("更新操作已完成!\n");
        } else {
            printf("Error[10007]:更新位置不合法!\n\n"); 
        }
    }
    
    return flag; 
} 
View Code

 

  主函数(main.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SequenceList.h"

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main() {
    
    SeqList L;
    int operate;
    int site; 
    int data;
    char *patterning[] = {
    "                                    \n",
    "                                             4&(\n",
    "                                           ` ~&&\\yM#1\n",
    "                                            ,_'Q!!NMW&\n",
    "                                            WCb 7N@4D Q%,,\n",
    "                                            PM'*MDk#M0p,\n",
    "                                                ]@J0&e~~4r' ,+bQEQ\n",
    "                                                 F8I&#'   _&B$$bW#&$\n",
    "                                                  &0A1   L#DE&E~!Q&Q,\n",
    "                                     _=,        ,#0RN1  _T@0$'   ZN$Q.   grNq5\n",
    "                                     ^ 'd     ,0K0pK^  g*Q0g'    #Q4p&,/g9X*&#,_/ (q\n",
    "                                      TA1   ,sDQWh4^  x&NM0` _   #FQ#K#fA#   `*K#XWP~-\n",
    "                                       ^&p,wNMM0qD: /HE#EN' ..#g)~ '@NG0Qx,    `=X*\n",
    "                                      '  '43$'hEk##m0D04f_g  ~^ ~   `-00**0\n",
    "                                               =0#ONq2W0BF^#, _            p,,\n",
    "                                                 `  ^''~    ~b''        **R3`\n",
    "                                                          ow,F         +#F~'\n",
    "                                                          /-9!          `\ \n",
    "                                                           R\n"
    };
    

    for(int i = 0;i < 19;i++){
        printf("%s",patterning[i]);
    }

     
    do{
        printf("<----------------------------------------------------顺序表演示程序--------------------------------------------------->\n");
        printf("0. 退出程序\n");    
        printf("1. 初始化顺序表\n");
        printf("2. 打印顺序表\n");
        printf("3. 插入元素\n");
        printf("4. 删除元素\n");
        printf("5. 查找元素\n");
        printf("6. 变更元素\n");
        printf("7. 获取元素\n");
        printf("8. 顺序表判空\n");
        printf("9. 顺序表判满\n");
        printf("10. 顺序表长度查询\n");
        printf("11. 清空顺序表\n");
        printf("12. 帮助\n");
        printf("请输入操作选项(0~11,0为退出):"); 
        scanf("%d", &operate);
        
        switch (operate) {
            case 1:
                if(!init(&L)){
                    printf("初始化完成\n\n");
                } else {
                    printf("Error[10001]:初始化失败\n\n");
                }
                break;
            case 2:
                print(&L);
                break;
            case 3:
                printf("请输入插入位置与插入数据(以逗号间隔):");
                scanf("%d,%d", &site,&data);
                insert(&L, site, data);
                break;
            case 4:
                printf("请输入删除位置:");
                scanf("%d", &site);
                expurgate(&L, site);
                break;
            case 5:    

                printf("请输入查找元素:");
                scanf("%d", &data);
                if(!find(&L, data)) {
                    printf("Error[10002]:顺序表为空\n\n");
                }
                break;
            case 6:
                printf("请输入更新位置与更新元素(以逗号间隔):");
                scanf("%d,%d", &site, &data);
                update(&L, site, data);
                break;
            case 7:
                printf("请输入需要获取的位置:");
                scanf("%d", &site);
                printf("该位置元素为%d\n", get(&L, site));
                break;
            case 8:
                if(isEmpty(&L)){
                    printf("Error[10002]:顺序表为空\n\n");
                } else {
                    printf("顺序表不为空\n\n");
                }
                break;
            case 9:
                if(isFull(&L)){
                    printf("Error[10003]:顺序表已满\n\n");
                } else {
                    printf("顺序表未满\n\n");
                }
                break;
            case 10:
                printf("顺序表的长度为:%d\n", getSize(&L)); 
                break;
            case 11:
                clear(&L);
                break;
            case 12:
                printf("本应用程序为数据结构-顺序表演示程序,用于课程实践与研究。由季文天老师指导,史恒珲开发。\n\n");
                break;
            case 0:    
                return 0; 
                break;        
        }
        
    } while(operate != 0);
    
    return 0;
}
View Code

 

五、小结

  发布博客还是一次,此次通过撰写博客也算重新梳理了一下数据结构的部分知识,对于顺序表的定义与操作算是切实掌握了。总的来说这种自己写下的文字的方式,确实是比过去看他人博客、文档等方式汲取的知识更为深刻。今后的应该多试着去自己描述、记录些什么。本文主要用以学习记录,鄙人才疏学浅,文中不足之处请君斧正。最后的最后扯些闲篇吧,写下这篇博客是23.10.06的晚上,国庆假期的最后一天。代码在假期前已经完成九成,但因手头上的工作和调整状态,一直拖到收假才完成博客。也不单是写作业吧,也写给过去、当下、未来的自己:别忘了来时的路和说过的话,调整好状态做自己。

六、参考文献

  王海艳等.《数据结构(C语言)》第二版[M].北京:人民邮电出版社,2020:10~14.

 

posted @ 2023-10-07 00:23  日月同珲  阅读(314)  评论(0)    收藏  举报