zoukankan      html  css  js  c++  java
  • 【数据结构】线性表 顺序存储结构

    本文收录自【C语言数据结构】思想+代码集】

    【数据结构】线性表

    思想

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

    代码

    头文件及函数定义 SqList.h

    /*=============================
     * 线性表的顺序存储结构(顺序表)
     *
     * 包含算法: 2.3、2.4、2.5、2.6
     =============================*/
    
    #ifndef SQLIST_H
    #define SQLIST_H
    
    #include <stdio.h>
    #include <stdlib.h>     // 提供malloc、realloc、free、exit原型
    #include "Status.h"     //**▲01 绪论**//
    
    /* 宏定义 */
    #define LIST_INIT_SIZE 100  // 顺序表存储空间的初始分配量
    #define LISTINCREMENT  10   // 顺序表存储空间的分配增量
    
    /* 顺序表元素类型定义 */
    typedef int ElemType;
    
    /*
     * 顺序表结构
     *
     * 注:elem在使用前需要先为其分配内存,且元素从elem[0]处开始存储
     */
    typedef struct {
        ElemType* elem;     // 顺序表存储空间的基址(指向顺序表所占内存的起始位置)
        int length;   // 当前顺序表长度(包含多少元素)
        int listsize; // 当前分配的存储容量(可以存储多少元素)
    } SqList;
    
    
    /*
     * ████████ 算法2.3 ████████
     *
     * 初始化
     *
     * 初始化成功则返回OK,否则返回ERROR。q 
     */
    Status InitList(SqList* L);
    
    /*
     * 销毁(结构)
     *
     * 释放顺序表所占内存。
     */
    Status DestroyList(SqList* L);
    
    /*
     * 置空(内容)
     *
     * 只是清理顺序表中存储的数据,不释放顺序表所占内存。
     */
    Status ClearList(SqList* L);
    
    /*
     * 判空
     *
     * 判断顺序表中是否包含有效数据。
     *
     * 返回值:
     * TRUE : 顺序表为空
     * FALSE: 顺序表不为空
     */
    Status ListEmpty(SqList L);
    
    /*
     * 计数
     *
     * 返回顺序表包含的有效元素的数量。
     */
    int ListLength(SqList L);
    
    /*
     * 取值
     *
     * 获取顺序表中第i个元素,将其存储到e中。
     * 如果可以找到,返回OK,否则,返回ERROR。
     *
     *【备注】
     * 教材中i的含义是元素位置,从1开始计数,但这不符合编码的通用约定。
     * 通常,i的含义应该指索引,即从0开始计数。
     */
    Status GetElem(SqList L, int i, ElemType* e);
    
    /*
     * ████████ 算法2.6 ████████
     *
     * 查找
     *
     * 返回顺序表中首个与e满足Compare关系的元素位序。
     * 如果不存在这样的元素,则返回0。
     *
     *【备注】
     * 元素e是Compare函数第二个形参
     */
    int LocateElem(SqList L, ElemType e, Status(Compare)(ElemType, ElemType));
    
    /*
     * 前驱
     *
     * 获取元素cur_e的前驱,
     * 如果存在,将其存储到pre_e中,返回OK,
     * 如果不存在,则返回ERROR。
     */
    Status PriorElem(SqList L, ElemType cur_e, ElemType* pre_e);
    
    /*
     * 后继
     *
     * 获取元素cur_e的后继,
     * 如果存在,将其存储到next_e中,返回OK,
     * 如果不存在,则返回ERROR。
     */
    Status NextElem(SqList L, ElemType cur_e, ElemType* next_e);
    
    /*
     * ████████ 算法2.4 ████████
     *
     * 插入
     *
     * 向顺序表第i个位置上插入e,插入成功则返回OK,否则返回ERROR。
     *
     *【备注】
     * 教材中i的含义是元素位置,从1开始计数
     */
    Status ListInsert(SqList* L, int i, ElemType e);
    
    /*
     * ████████ 算法2.5 ████████
     *
     * 删除
     *
     * 删除顺序表第i个位置上的元素,并将被删除元素存储到e中。
     * 删除成功则返回OK,否则返回ERROR。
     *
     *【备注】
     * 教材中i的含义是元素位置,从1开始计数
     */
    Status ListDelete(SqList* L, int i, ElemType* e);
    
    /*
     * 遍历
     *
     * 用visit函数访问顺序表L
     */
    void ListTraverse(SqList L, void (Visit)(ElemType));
    
    #endif
    
    

    函数源码SqList.cpp

    
    /*=============================
     * 线性表的顺序存储结构(顺序表)
     *
     * 包含算法: 2.3、2.4、2.5、2.6
     =============================*/
    
    #include "SqList.h"
    
    /*
     * ████████ 算法2.3 ████████
     *
     * 初始化
     *
     * 初始化成功则返回OK,否则返回ERROR。
     */
    Status InitList(SqList* L) {
        // 分配指定容量的内存,如果分配失败,则返回NULL
        (*L).elem = (ElemType*) malloc(LIST_INIT_SIZE * sizeof(ElemType));
        if((*L).elem == NULL) {
            // 存储内存失败
            exit(OVERFLOW);
        }
    
        (*L).length = 0;                    // 初始化顺序表长度为0
        (*L).listsize = LIST_INIT_SIZE;     // 顺序表初始内存分配量
    
        return OK;                          // 初始化成功
    }
    
    /*
     * 销毁(结构)
     *
     * 释放顺序表所占内存。
     */
    Status DestroyList(SqList* L) {
        // 确保顺序表结构存在
        if(L == NULL || (*L).elem == NULL) {
            return ERROR;
        }
    
        // 释放顺序表内存
        free((*L).elem);
    
        // 释放内存后置空指针
        (*L).elem = NULL;
    
        // 顺序表长度跟容量都归零
        (*L).length = 0;
        (*L).listsize = 0;
    
        return OK;
    }
    
    /*
     * 置空(内容)
     *
     * 只是清理顺序表中存储的数据,不释放顺序表所占内存。
     */
    Status ClearList(SqList* L) {
        // 确保顺序表结构存在
        if(L == NULL || (*L).elem == NULL) {
            return ERROR;
        }
    
        (*L).length = 0;
    
        return OK;
    }
    
    /*
     * 判空
     *
     * 判断顺序表中是否包含有效数据。
     *
     * 返回值:
     * TRUE : 顺序表为空
     * FALSE: 顺序表不为空
     */
    Status ListEmpty(SqList L) {
        return L.length == 0 ? TRUE : FALSE;
    }
    
    /*
     * 计数
     *
     * 返回顺序表包含的有效元素的数量。
     */
    int ListLength(SqList L) {
        return L.length;
    }
    
    /*
     * 取值
     *
     * 获取顺序表中第i个元素,将其存储到e中。
     * 如果可以找到,返回OK,否则,返回ERROR。
     *
     *【备注】
     * 教材中i的含义是元素位置,从1开始计数,但这不符合编码的通用约定。
     * 通常,i的含义应该指索引,即从0开始计数。
     */
    Status GetElem(SqList L, int i, ElemType* e) {
        // 因为i的含义是位置,所以其合法范围是:[1, length]
        if(i < 1 || i > L.length) {
            return ERROR;                    //i值不合法
        }
    
        *e = L.elem[i - 1];
    
        return OK;
    }
    
    /*
     * ████████ 算法2.6 ████████
     *
     * 查找
     *
     * 返回顺序表中首个与e满足Compare关系的元素位序。
     * 如果不存在这样的元素,则返回0。
     *
     *【备注】
     * 元素e是Compare函数第二个形参
     */
    int LocateElem(SqList L, ElemType e, Status(Compare)(ElemType, ElemType)) {
        int i;
        ElemType* p;
    
        // 确保顺序表结构存在
        if(L.elem == NULL) {
            return ERROR;
        }
    
        /*
         * i的初值为第1个元素的位序
         *
         * 其实,更自然的写法是将i初始化为第1个元素的索引
         * 但由于教材中是按位序计数的,所以这里仍写作位序
         */
        i = 1;
    
        // p的初值为第1个元素的存储位置
        p = L.elem;
    
        // 遍历顺序表
        while(i <= L.length && !Compare(*p++, e)) {
            ++i;
        }
    
        if(i <= L.length) {
            return i;
        } else {
            return 0;
        }
    }
    
    /*
     * 前驱
     *
     * 获取元素cur_e的前驱,
     * 如果存在,将其存储到pre_e中,返回OK,
     * 如果不存在,则返回ERROR。
     */
    Status PriorElem(SqList L, ElemType cur_e, ElemType* pre_e) {
        int i;
    
        // 确保顺序表结构存在,且最少包含两个元素
        if(L.elem == NULL || L.length < 2) {
            return ERROR;
        }
    
        // 这里的i初始化为第1个元素的【索引】
        i = 0;
    
        // 从第1个元素开始,查找cur_e的位置
        while(i < L.length && L.elem[i] != cur_e) {
            ++i;
        }
    
        // 如果cur_e是首个元素(没有前驱),或者没找到元素cur_e,返回ERROR
        if(i==0 || i >= L.length) {
            return ERROR;
        }
    
        // 存储cur_e的前驱
        *pre_e = L.elem[i - 1];
    
        return OK;
    }
    
    /*
     * 后继
     *
     * 获取元素cur_e的后继,
     * 如果存在,将其存储到next_e中,返回OK,
     * 如果不存在,则返回ERROR。
     */
    Status NextElem(SqList L, ElemType cur_e, ElemType* next_e) {
        int i;
    
        // 确保顺序表结构存在,且最少包含两个元素
        if(L.elem == NULL || L.length < 2) {
            return ERROR;
        }
    
        // 这里的i初始化为第1个元素的【索引】
        i = 0;
    
        // 从第1个元素开始,查找cur_e的位置
        while(i < L.length-1 && L.elem[i] != cur_e) {
            ++i;
        }
    
        // 如果cur_e是最后1个元素(没有前驱),或者没找到元素cur_e,返回ERROR
        if(i >= L.length-1) {
            return ERROR;
        }
    
        // 存储cur_e的前驱
        *next_e = L.elem[i + 1];
    
        return OK;
    }
    
    /*
     * ████████ 算法2.4 ████████
     *
     * 插入
     *
     * 向顺序表第i个位置上插入e,插入成功则返回OK,否则返回ERROR。
     *
     *【备注】
     * 教材中i的含义是元素位置,从1开始计数
     */
    Status ListInsert(SqList* L, int i, ElemType e) {
        ElemType* newbase;
        ElemType* p, * q;
    
        // 确保顺序表结构存在
        if(L == NULL || (*L).elem == NULL) {
            return ERROR;
        }
    
        // i值越界
        if(i < 1 || i > (*L).length + 1) {
            return ERROR;
        }
    
        // 若存储空间已满,则增加新空间
        if((*L).length >= (*L).listsize) {
            // 基于现有空间扩容
            newbase = (ElemType*) realloc((*L).elem, ((*L).listsize + LISTINCREMENT) * sizeof(ElemType));
            if(newbase == NULL) {
                // 存储内存失败
                exit(OVERFLOW);
            }
    
            // 新基址
            (*L).elem = newbase;
            // 存的存储空间
            (*L).listsize += LISTINCREMENT;
        }
    
        // q为插入位置
        q = &(*L).elem[i - 1];
    
        // 1.右移元素,腾出位置
        for(p = &(*L).elem[(*L).length - 1]; p >= q; --p) {
            *(p + 1) = *p;
        }
    
        // 2.插入e
        *q = e;
    
        // 3.表长增1
        (*L).length++;
    
        return OK;
    }
    
    /*
     * ████████ 算法2.5 ████████
     *
     * 删除
     *
     * 删除顺序表第i个位置上的元素,并将被删除元素存储到e中。
     * 删除成功则返回OK,否则返回ERROR。
     *
     *【备注】
     * 教材中i的含义是元素位置,从1开始计数
     */
    Status ListDelete(SqList* L, int i, ElemType* e) {
        ElemType* p, * q;
    
        // 确保顺序表结构存在
        if(L == NULL || (*L).elem == NULL) {
            return ERROR;
        }
    
        // i值越界
        if(i < 1 || i > (*L).length) {
            return ERROR;
        }
    
        // p为被删除元素的位置
        p = &(*L).elem[i - 1];
    
        // 1.获取被删除元素
        *e = *p;
    
        // 表尾元素位置
        q = (*L).elem + (*L).length - 1;
    
        // 2.左移元素,被删除元素的位置上会有新元素进来
        for(++p; p <= q; ++p) {
            *(p - 1) = *p;
        }
    
        // 3.表长减1
        (*L).length--;
    
        return OK;
    }
    
    /*
     * 遍历
     *
     * 用visit函数访问顺序表L
     */
    void ListTraverse(SqList L, void(Visit)(ElemType)) {
        int i;
    
        for(i = 0; i < L.length; i++) {
            Visit(L.elem[i]);
        }
    
        printf("
    ");
    }
    
    

    main函数

    #include <stdio.h>
    #include "SqList.h"                                //**02 线性表**//
    
    // 判断data>e是否成立
    Status CmpGreater(ElemType data, ElemType e) {
        return data > e ? TRUE : FALSE;
    }
    
    // 测试函数,打印元素
    void PrintElem(ElemType e) {
        printf("%d ", e);
    }
    
    
    int main(int argc, char** argv) {
        SqList L;   // 待操作的顺序表
    
        int i;
        ElemType e;
    
        printf("████████ InitList 
    ");
        {
            printf("█ 初始化顺序表 L ...
    ");
            InitList(&L);
        }
        PressEnterToContinue();
    
    
        printf("████████ ListEmpty 
    ");
        {
            if(ListEmpty(L) == TRUE) {
                printf("█ L 为空!!
    ");
            } else {
                printf("█ L 不为空!
    ");
            }
        }
        PressEnterToContinue();
    
    
        printf("████████ ListInsert 
    ");
        {
            for(i = 1; i <= 8; i++) {
                printf("█ 作为示范,在 L 第 %d 个位置插入 "%d"...
    ", i, 2 * i);
                ListInsert(&L, i, 2 * i);
            }
        }
        PressEnterToContinue();
    
    
        printf("████████ ListTraverse 
    ");
        {
            printf("█ L 中的元素为:L = ");
            ListTraverse(L, PrintElem);
        }
        PressEnterToContinue();
    
    
        printf("████████ ListLength 
    ");
        {
            i = ListLength(L);
            printf("█ L 的长度为 %d 
    ", i);
        }
        PressEnterToContinue();
    
    
        printf("████████ ListDelete 
    ");
        {
            printf("█ 删除前的元素:L = ");
            ListTraverse(L, PrintElem);
    
            printf("█ 尝试删除 L 中第 6 个元素...
    ");
    
            if(ListDelete(&L, 6, &e) == OK) {
                printf("█ 删除成功,被删除元素是:"%d"
    ", e);
            } else {
                printf("█ 删除失败,第 6 个元素不存在!
    ");
            }
    
            printf("█ 删除后的元素:L = ");
            ListTraverse(L, PrintElem);
        }
        PressEnterToContinue();
    
    
        printf("████████ GetElem 
    ");
        {
            GetElem(L, 4, &e);
            printf("█ L 中第 4 个位置的元素为 "%d" 
    ", e);
        }
        PressEnterToContinue();
    
    
        printf("████████ LocateElem 
    ");
        {
            i = LocateElem(L, 7, CmpGreater);
            printf("█ L 中第一个元素值大于 "7" 的元素是 "%d" 
    ", L.elem[i - 1]);
        }
        PressEnterToContinue();
    
    
        printf("████████ PriorElem 
    ");
        {
            ElemType cur_e = 6;
    
            if(PriorElem(L, cur_e, &e) == OK) {
                printf("█ 元素 "%d" 的前驱为 "%d" 
    ", cur_e, e);
            } else {
                printf("█ 元素 "%d" 的前驱不存在!
    ", cur_e);
            }
        }
        PressEnterToContinue();
    
    
        printf("████████ NextElem 
    ");
        {
            ElemType cur_e = 6;
    
            if(NextElem(L, cur_e, &e) == OK) {
                printf("█ 元素 "%d" 的后继为 "%d" 
    ", cur_e, e);
            } else {
                printf("█ 元素 "%d" 的后继不存在!
    ", cur_e);
            }
        }
        PressEnterToContinue();
    
    
        printf("████████ ClearList 
    ");
        {
            printf("█ 清空 L 前:");
            if(ListEmpty(L) == TRUE) {
                printf(" L 为空!!
    ");
            } else {
                printf(" L 不为空!
    ");
            }
    
            ClearList(&L);
    
            printf("█ 清空 L 后:");
            if(ListEmpty(L) == TRUE) {
                printf(" L 为空!!
    ");
            } else {
                printf(" L 不为空!
    ");
            }
        }
        PressEnterToContinue();
    
    
        printf("████████ DestroyList 
    ");
        {
            printf("█ 销毁 L 前:");
            if(L.elem != NULL) {
                printf(" L 存在!
    ");
            } else {
                printf(" L 不存在!!
    ");
            }
    
            DestroyList(&L);
    
            printf("█ 销毁 L 后:");
            if(L.elem != NULL) {
                printf(" L 存在!
    ");
            } else {
                printf(" L 不存在!!
    ");
            }
        }
        PressEnterToContinue();
    
    
        return 0;
    }
    
    
  • 相关阅读:
    golang linux安装
    vscode 插件
    windows访问eks pods
    go mod包管理
    beego创建项目
    Atcoder ARC-125
    AtCoder AGC003 简要题解
    Python 字符串转成变量名
    13_Go基础(binary)
    12_Go基础(iota)
  • 原文地址:https://www.cnblogs.com/SiriusZHT/p/14310788.html
Copyright © 2011-2022 走看看