数据结构——线性表和顺序表

1、线性表的基本概念

1.1 定义

        线性结构是简单且常用的数据结构,而线性表则是一种典型的线性结构

        存储数据,最简单,最有效的方法是吧它们存储在一个线性表中

        一个线性表是n个元素的有限序列。每个元素在不同的情况下有不同的含义,可以是整数,也可以是字符

        线性表:是具有相同数据类型的n个数据元素的有限序列

1.2 特点:围绕一对一关系进行描述

        存在唯一的第一个元素

        存在唯一的最后一个元素

        除第一个元素外,每一个元素只有一个直接前驱

        除最后一个元素外,每一个元素均只有一个直接后继

1.3 逻辑结构:线性结构 

1.4 线性表的存储结构

        顺序存储结构:顺序表

        链式存储结构:链表

1.5 操作

        表:创建、销毁

        数据: 增删改查

2、顺序表

2.1 定义

        就是把线性表中的所有元素按照其逻辑顺序依次存储到指定位置开始的一块连续的存储区域

        线性表中的第1个元素的存储位置就是指定的存储位置,第i个元素的存储位置紧接第i-1个元素的存储位置的后面

2.2 特点

        顺序表的元素是按顺序进行存储的,第i项就存在第i个位置

        对顺序表中的所有元素,既可以顺序访问,也可以随机访问,比较擅长随机访问和遍历

        不擅长插入、删除操作,需要移动大量元素

2.3 操作

        表:创建、销毁

        数据: 增删改查

2.4 顺序表的实现方式:数组、指针 

2.4.1 顺序表的数组的实现方式

顺序表和数组进行对比

        1、数组是一种特殊的顺序表

        2、顺序表是通过数组来实现的,顺序表的元素存储在一块连续的存储空间中

        3、数组的长度是不可变的,顺序表的长度是可以改变的

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Windows.h>
#include <stdlib.h>
#include <memory.h>  //需要使用memset时引用
//创建顺序表结构体类型
#define MAX_SIZE 100  //宏定义,为了维护简单
typedef int elementType;  //重命名,为了维护简单
typedef struct Order_List {
    elementType data[MAX_SIZE];  //数组:存放顺序表元素
    int lenth;  //顺序表的元素总个数
}OrderList;

void print_menu();
OrderList* create_list();
void append_List(OrderList* List, elementType val);
void print_List(OrderList* List);
void insert_List(OrderList* List, int index, elementType val);
void delete_List(OrderList* List, int index);
void edit_List(OrderList* List, int index, elementType val);
void destory_List(OrderList* List);

int main() {
    print_menu();
    int order = 0;  //存储用户输入的操作指令
    //创建顺序表变量
    //OrderList list;  //结构体变量,静态分配
    OrderList* List = NULL;  //结构体指针,动态申请,手动释放
    elementType val = 0;
    int index = 0;
    while (1) {
        printf("请输入操作指令:");
        scanf("%d", &order);
        switch (order) {
            case 1:  //创建顺序表
                //创建空表
                List = create_list();
                break;
            case 2:  //打印顺序表
                print_List(List);
                break;
            case 3:  //追加一个节点,尾部插入
                printf("请输入要追加的元素:");
                scanf(" %d", &val);
                append_List(List, val);
                break;
            case 4:  //插入一个节点,随机插入,从0开始
                printf("请输入要插入的位置:");
                scanf(" %d", &index);
                printf("请输入要插入的元素:");
                scanf(" %d", &val);
                insert_List(List, index, val);
                break;
            case 5:  //删除一个节点,从1开始
                printf("请输入要删除第几个元素:");
                scanf(" %d", &index);
                delete_List(List, index);
                break;
            case 6:  //修改顺序表元素,从1开始
                printf("请输入要修改的元素位置:");
                scanf(" %d", &index);
                printf("请输入修改后的新值:");
                scanf(" %d", &val);
                edit_List(List, index, val);
                break;
            case 7:  //销毁顺序表

                //List存放的是表的地址,需要销毁List的地址,才能销毁顺序表
                destory_List(&List);
                break;
            case 8:  //退出
                break;
            default:
                printf("输入错误,请重新输入!");
        }
        if (order == 8) {
            break;
        }
    }
    return 0;
}

//打印菜单
void print_menu() {
    system("cls");  //系统函数,用于屏幕清空
    printf("操作指令:\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");
}

//创建空表
OrderList* create_list() {
    //申请内存
    //malloc分配的内存空间不确定,一般使用memset初始化
    OrderList* List = (OrderList*)malloc(sizeof(OrderList));  
    //申请失败
    if (List == NULL) {
        printf("内存申请失败,创建失败!\n");
        return NULL;
    }
    //申请成功
    //需要导入memory.h或string.h
    memset(List, 0, sizeof(OrderList));  //功能:将指定内存设置为指定内容,一般用来进行数组清零
    List->lenth = 0;
    printf("初始化成功!\n");
    return List;
}

//追加一个节点,末尾增加
void append_List(OrderList* List, elementType val) {
    //判断是否初始化
    if (List == NULL) {  //!List
        printf("请先建表\n");
        return;
    }
    //判断表是否已满
    if (List->lenth >= MAX_SIZE) {
        printf("表已满,无法追加!\n");
        return;
    }
    //正常追加
    List->data[List->lenth] = val;
    List->lenth++;
    printf("追加成功!\n");
}

//打印顺序表
void print_List(OrderList* List) {
    //判断是否初始化
    if (List == NULL) {  //!List
        printf("请先建表\n");
        return;
    }
    
    if (List->lenth == 0) {
        printf("空表,无法打印!\n");
        return;
    }
    //正常打印
    for (int i = 0;i < List->lenth;i++) {
        printf("%d ", List->data[i]);
    }
    printf("\n");
}

//插入一个节点,随机插入
void insert_List(OrderList* List, int index, elementType val) {
    //判断是否初始化
    if (List == NULL) {  //!List
        printf("请先建表\n");
        return;
    }
    //判断表是否已满
    if (List->lenth == 0) {
        printf("空表,无法打印!\n");
        return;
    }
    //正常插入,倒序遍历,位置后移
    for (int i = List->lenth - 1;i >= index;i--) {
        List->data[i + 1] = List->data[i];
    }
    List->data[index] = val;
    List->lenth++;
    printf("插入成功!\n");
}

//删除
void delete_List(OrderList* List, int index) {
    //判断是否初始化
    if (List == NULL) {  //!List
        printf("请先建表\n");
        return;
    }
    //判断索引是否合法
    int ind = index - 1;  //要删除的元素的索引
    if (ind<0 || ind>List->lenth - 1) {
        printf("请输入合适的位置!\n");
        return;
    }
    //执行删除,元素前移
    for (int i = ind;i < List->lenth;i++) {
        List->data[i] = List->data[i + 1];
    }
    List->lenth--;
    printf("删除成功!\n");
}

//修改
void edit_List(OrderList* List, int index, elementType val) {
    //判断是否初始化
    if (List == NULL) {  //!List
        printf("请先建表\n");
        return;
    }
    //判断索引是否合法
    int ind = index - 1;  //要删除的元素的索引
    if (ind<0 || ind>List->lenth - 1) {
        printf("您要修改的元素不存在!\n");
        return;
    }
    //执行修改
    List->data[ind] = val;
    printf("修改成功!\n");
}

//销毁  注意:形参是二级指针
void destory_List(OrderList** List) {
    free(*List);  //释放内存空间
    *List = NULL;  //销毁后要置空
    printf("销毁成功!\n");
}

2.4.2 顺序表的指针的实现方式

2.4.2.1 02.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Windows.h>
#include <stdlib.h>
#include <memory.h> 
#define MAX_SIZE 100
typedef int ElementT;
//定义结构体类型
typedef struct OrderListPtr {
    ElementT* datap;  //元素类型指针,用于申请内存后,存放数组元素
    int length;  //存放数组元素的总个数
}ODP;
void print_menu();
void create_List(ODP* list);
void append_List(ODP* list, ElementT value);
void print_List(ODP list);
void insert_List(ODP* list, int index, ElementT value);
void delete_List(ODP* list, int index);
void delete_List(ODP* list, int index);
void edit_List(ODP* list, int index, ElementT value);
void destroy_List(ODP* list);

2.4.2.1 02.c

#include "02.h"
//顺序表的指针的实现方式

//如果要改datap或length的值需要传地址,不需要则传值

void fn2() {
    while (1) {
        print_menu();
        int order = 0;  //存储用户输入的操作指令
        ODP list = { NULL,0 };  //定义结构体变量
        ElementT value = 0;
        int index = 0;
        while (1) {
            printf("请输入操作指令:");
            scanf("%d", &order);
            switch (order) {
            case 1:  //创建顺序表
                //创建空表
                create_List(&list);
                break;
            case 2:  //打印顺序表
                print_List(list);
                break;
            case 3:  //追加一个节点,尾部插入
                printf("请输入要追加的元素:");
                scanf(" %d", &value);
                append_List(&list, value);
                break;
            case 4:  //插入一个节点,随机插入,从0开始
                printf("请输入要插入的元素的位置:");
                scanf(" %d", &index);
                printf("请输入要插入的元素:");
                scanf(" %d", &value);
                insert_List(&list, index, value);
                break;
            case 5:  //删除一个节点,从1开始
                printf("请输入要删除的元素的位置:");
                scanf(" %d", &index);
                delete_List(&list, index);
                break;
            case 6:  //修改顺序表元素,从1开始
                printf("请输入要修改的元素的位置:");
                scanf(" %d", &index);
                printf("请输入要修改的元素:");
                scanf(" %d", &value);
                edit_List(&list, index, value);
                break;
            case 7:  //销毁顺序表
                destroy_List(&list);
                break;
            case 8:  //退出
                break;
            default:
                printf("输入错误,请重新输入!");
            }
            if (order == 8) {
                break;
            }
        }
        return 0;
    }
}
//打印菜单
void print_menu() {
    system("cls");  //系统函数,用于屏幕清空
    printf("操作指令:\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");
}
//创建顺序表
void create_List(ODP* list) {
    //申请内存空间
    list->datap = (ElementT*)malloc(sizeof(ElementT*) * MAX_SIZE);
    if (!list->datap) {
        printf("内存申请失败!\n");
        return;
    }
    //清0
    memset(list->datap, 0, sizeof(ElementT*) * MAX_SIZE);
    list->length = 0;
    printf("初始化成功!\n");
}

//追加一个节点,尾部插入
void append_List(ODP* list, ElementT value) {
    //判断是否建过表
    if (!list->datap) {
        printf("请先建表!\n");
        return;
    }
    //判断表是否满
    if (list->length >= MAX_SIZE) {
        printf("表已满,无法追加!\n");
        return;
    }
    //正常追加
    *(list->datap + list->length) = value;  //list->datap首元素的地址
    另一种方法
    //list->datap[list->length] = value;
    list->length++;
    printf("追加成功!\n");
}

//打印顺序表
void print_List(ODP list) {
    if (!list.datap) {
        printf("请先建表!\n");
        return;
    }
    if (list.length == 0) {
        printf("空表,无法打印!\n");
        return;
    }
    for (int i = 0;i < list.length;i++) {
        printf("%d ", list.datap[i]);  //当成数组
        另一种方法
        //printf("%d ", *(list.datap + i));  //当成指针
    }
    printf("\n");
}

//插入一个节点,随机插入,从0开始
void insert_List(ODP* list, int index, ElementT value) {
    //判断是否建过表
    if (!list->datap) {
        printf("请先建表!\n");
        return;
    }
    //判断表是否满
    if (list->length >= MAX_SIZE) {
        printf("表已满,无法插入!\n");
        return;
    }
    //正常插入
    //从index位置,倒叙遍历,位置后移
    for (int i = list->length - 1;i >= index;i--) {
        list->datap[i + 1] = list->datap[i];
    }
    //判断插入的位置是否合法
    if (index<0 || index>list->length - 1) {
        printf("插入位置不合法!\n");
        return;
    }
    list->datap[index] = value;
    另一种方法
    //*(list->datap + list->length) = value;
    list->length++;
    printf("插入成功!\n");
}

//删除一个节点,从1开始
void delete_List(ODP* list, int index) {
    //判断是否建过表
    if (!list->datap) {
        printf("请先建表!\n");
        return;
    }
    if (list->length == 0) {
        printf("空表,无法删除!\n");
        return;
    }
    //判断要删除的元素的位置是否合法
    int ind = index - 1;
    if (ind<0 || ind>list->length - 1) {
        printf("您要删除的元素不存在!\n");
        return;
    }
    //正常删除,从index开始,所有元素前移
    for (int i = ind;i < list->length;i++) {
        list->datap[i] = list->datap[i + 1];
    }
    list->length--;
    printf("删除成功!\n");
}

//修改顺序表元素,从1开始
void edit_List(ODP* list, int index, ElementT value) {
    //判断是否建过表
    if (!list->datap) {
        printf("请先建表!\n");
        return;
    }
    if (list->length == 0) {
        printf("空表,无法修改!\n");
        return;
    }
    //判断要修改的元素的位置是否合法
    int ind = index - 1;
    if (ind<0 || ind>list->length - 1) {
        printf("您要修改的元素不存在!\n");
        return;
    }
    //正常修改
    list->datap[ind] = value;
    另一种方法
    //*(list->datap + ind) = value;
    printf("修改成功!\n");
}

//销毁顺序表
void destroy_List(ODP* list) {
    //判断是否建过表
    if (!list->datap) {
        printf("请先建表!\n");
        return;
    }
    free(list->datap);  //释放内存
    list->datap = NULL;
    list->length = 0;
    printf("销毁成功!\n");
}

2.4.2.1 02main.c 

#include "02.h"
int main() {
    fn2();
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/68353.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows图形界面(GUI)-QT-C/C++ - QT 窗口属性

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 标题栏 基本概念 设置窗口标题 隐藏标题栏 UI编辑器 窗口关闭事件 窗口大小调整事件 窗口移动事件 自定义标题栏 菜单栏 基本概念 设置菜单栏(API) 设置菜单栏(UI) 工具栏 …

Linux系统离线部署MySQL详细教程(带每步骤图文教程)

1、登录官网下载对应的安装包 MySQL :: Developer Zone 2、将压缩包上传到服务器上&#xff0c;这里直接上传到/usr/local路径上 使用sftp工具上传到/usr/local目录上 3、解压压缩包 tar -xf mysql-8.0.39-linux-glibc2.17-x86_64.tar.xz 4、将mysql-8.0.39-linux-glibc2.17…

网络安全技术之计算机安全

计算机安全之访问控制策略 访问控制是网络安全防范和保护的主要策略&#xff0c;它的主要任务是保证网络资源不被非法使用和非常访问。它也是维护网络系统安全、保护网络资源的重要手段。各种安全策略必须相互配合才能真正起到保护作用&#xff0c;但访问控制可以说是保证网络…

leetcode刷题记录(六十一)——73. 矩阵置零

&#xff08;一&#xff09;问题描述 73. 矩阵置零 - 力扣&#xff08;LeetCode&#xff09;73. 矩阵置零 - 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 [http://baike.baidu.com/item/%E5%8E%9F%E5%9…

QT 如何禁止QComboBox鼠标滚轮

一般情况下&#xff0c;QComboBox会相应鼠标的滚轮事件&#xff0c;即当鼠标停靠在QComboBox上方时&#xff0c;滚动鼠标滚轮&#xff0c;QComboBox的选项会发生切换。但这或许并不是我们希望所出现的&#xff0c;尤其是当QComboBox嵌入在QScrollArea中时&#xff0c;用户只是想…

【蓝桥杯】43689.包子凑数

题目描述 小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有 &#x1d441; 种蒸笼&#xff0c;其中第 &#x1d456; 种蒸笼恰好能放 &#x1d434;&#x1d456; 个包子。每种蒸笼都有非常多笼&#xff0c;可以认为是无限笼。  每当有顾客想买 &#x1d44b; 个包…

CV与NLP经典大模型解读

一。llm与lora微调策略解读 (1)文本大模型 llama:meta开源语言模型(咱们能负担得起下游任务了)。 lora:绘你模型你也得能训练的动才行(咱们也能微调下游任务)。loradiffusion。 self-instruct:下游任务得规矩些&#xff0c;输入与输出都得有一个标准格式。 peft:将上面三个…

ESP8266-01S的WIFI功能AT指令

1、ATCWMODE——设置wifi模式(STA/AP/STAAP) 设置指令&#xff1a;ATCWMODE<mode> 参数说明&#xff1a;1:station模式 2:sofAP模式 3:stationsofAP模式 查询指令&#xff1a;ATCWMODE? 参数说明&#xff1a;1:station模式 2:sofAP模式 …

Dexie.js内存管理技巧:在大型数据集操作中避免浏览器崩溃

Dexie.js 内存管理技巧&#xff1a;避免浏览器崩溃 在使用 Dexie.js 操作 大型数据集 时&#xff0c;如果不注意内存管理&#xff0c;可能会导致浏览器内存溢出&#xff08;OOM&#xff0c;Out of Memory&#xff09;或崩溃。因此&#xff0c;以下 内存管理技巧 可用于优化性能…

K8S集群常用命令

1&#xff0c;查看pod kubectl get pods -A 查看所有的pod kubectl get pods 这个只查看namespace为default下的pod&#xff0c;也就是只查看默认命名空间下的pod kubectl get pod -A -o wide 查看所有的pod&#xff0c;并且放出的信息更全&#xff08;包含了pod的ip&#xff0…

人机交互(包含推荐软件)

视觉交互、语音交互、笔式交互、触觉交互、虚拟环境交互。 主要的研究方面包括&#xff1a;人机交互界面表示模型与设计方法、可用性工程、可用性评估模型和方法、多模态智能交互技术、智能交互认知技术、语音识别交互、web界面交互设计、移动界面交互设计。 交互设计流程&am…

解锁未来情感科技:AI 机器人 Ropet 搭载的前沿智能黑科技

2025年的国际消费电子产品展览会&#xff08;CES&#xff09;上&#xff0c;一只可爱的“毛绒玩具”成了全场焦点。 当然&#xff0c;这并不是一个单纯的玩偶&#xff0c;而是和《超能陆战队》的大白一样温暖的陪伴机器人。 相信有很多人和小编一样&#xff0c;当年看完《超能…

C++ ranges

C20新增 ranges 新特性 任何可以迭代的对象都可以使用 ranges。头文件&#xff1a;#include 注&#xff1a; std::views是std::ranges::views的别名 常用方法&#xff1a; 1.遍历 正序遍历&#xff1a;for(int i:v) 逆序遍历&#xff1a;for(int i:v|reverse) 2.判断是否为空…

HarmonyOS 鸿蒙 ArkTs(5.0.1 13)实现Scroll下拉到顶刷新/上拉触底加载,Scroll滚动到顶部

HarmonyOS 鸿蒙 ArkTs(5.0.1 13)实现Scroll下拉到顶刷新/上拉触底加载 效果展示 使用方法 import LoadingText from "../components/LoadingText" import PageToRefresh from "../components/PageToRefresh" import FooterBar from "../components/…

# [游戏开发] Unity中的碰撞与触发器实现:从基础到应用

在游戏开发中,碰撞检测是一个非常普遍且关键的问题。如何判断一个物体是否碰到另一个物体,通常是通过计算物体间的距离或使用专门的物理引擎来实现。随着技术的发展,现代游戏引擎提供了更为便捷和高效的方式——触发器,它通过事件驱动机制,极大简化了碰撞检测和响应过程。…

Flink(八):DataStream API (五) Join

1. Window Join Window join 作用在两个流中有相同 key 且处于相同窗口的元素上。这些窗口可以通过 window assigner 定义&#xff0c;并且两个流中的元素都会被用于计算窗口的结果。两个流中的元素在组合之后&#xff0c;会被传递给用户定义的 JoinFunction 或 FlatJoinFunct…

Py之cv2:cv2(OpenCV,opencv-python)库的简介、安装、使用方法(常见函数、图像基本运算等)

1. OpenCV简介 1.1 OpenCV定义与功能 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库。它为计算机视觉应用程序提供了一个通用的基础设施&#xff0c;并加速了在商业产品中使用机器感知。作为BSD许可的产品&…

JVM 触发类加载的条件有哪些?

目录 一、类加载生命周期 二、主动引用 2.1、创建类的实例 2.2、访问类的静态字段或静态方法 2.3、反射 2.4、初始化类的子类时&#xff0c;先初始化父类 2.5、虚拟机启动时&#xff0c;初始化 main 方法所在的类 2.6、动态语言支持 三、被动引用 3.1、通过子类引用父…

ElasticSearch-Nested 类型与 Object 类型的区别

在 Elasticsearch 中&#xff0c;nested 类型和 object 类型都用于处理嵌套的 JSON 数据&#xff0c;但它们在存储和查询方面有着显著的区别。本文将详细解释这两种类型的区别&#xff0c;并提供具体的示例。 一、基本概念 1. object 类型 定义&#xff1a;object 类型是 Elas…

推荐sdkman管理sdk和jdk

使用SDKMAN安装JDK通常是免费的。 SDKMAN是一个开源的命令行工具&#xff0c;用于管理和切换多个版本的软件开发工具包&#xff08;SDKs&#xff09;&#xff0c;包括JDK。它支持多种JVM相关工具&#xff0c;如Java、Scala、Groovy、Maven、Gradle等。 安装SDKMAN 首先&…