数据结构_顺序表_尾插、尾删、头插、头删(附带详解)

news2024/11/24 2:56:37

文章目录

  • 前言
  • 一. 线性表
  • 二. 顺序表 - - - 数组
    • 2.1 什么是顺序表
    • 2.2 顺序表一般可以分为
      • 2.2.1 静态顺序表(使用定长数组存储元素)
      • 2.2.2 动态顺序表:使用动态开辟的数组存储
      • 2.2.3 顺序表的接口实现
  • 三. SeqList.c 中各个接口的实现。
    • 3.1 初始化顺序表
    • 3.2 销毁(释放)顺序表
    • 3.3 检查顺序表容量是否满了,好进行增容
    • 3.4 realloc 原地扩容、异地扩容
    • 3.5 顺序表尾插
      • 测试
    • 3.6 顺序表尾删
      • 测试结果
      • 完整代码
    • 3.7 顺序表头插
      • 测试结果
      • 完整代码
    • 3.8 顺序表头删
      • 测试结果
      • 完整代码
  • 四. 打印顺序表
  • 五. 在顺序表中查找指定值
      • 测试结果
      • 完整代码
  • 六. 在顺序表指定下标位置插入数据
      • 测试结果
  • 七. 在顺序表中删除指定下标位置的数据
      • 测试结果


前言

顺序表_尾插、尾删、头插、头删


一. 线性表


二. 顺序表 - - - 数组

2.1 什么是顺序表

  • 顺序表是用一段物理地址连续的存储单元一次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
  • 顺序表可动态增长的数组,要求数据是连续存储的。

2.2 顺序表一般可以分为

2.2.1 静态顺序表(使用定长数组存储元素)

  • 静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。
  • 所以基本使用动态顺序表,根据需要,动态的分配空间大小。
    缺陷:给小了不够用,给大了,不实用。

2.2.2 动态顺序表:使用动态开辟的数组存储

  • 动态顺序表可根据我们的需要分配空间
  • size 表示当前顺序表中已存放的数据个数
  • capacity 表示顺序表总共能够存放的数据个数

2.2.3 顺序表的接口实现

先建一个工程(此次用的是vs2019)用的是动态顺序表

  • SeqList.h (顺序表的类型定义、接口函数声明、引用的头文件)
  • SeqList.h (顺序表接口函数的实现)
  • Test.c (主函数、测试顺序表各个接口功能)
  • SeqList.h 头文件代码:
#pragma once // 防止头文件被二次引用

#include<stdio.h>
#include<assert.h> //assert
#include<stdlib.h> //realloc

typedef int SLDataType; //后续要存储其他类型时方便更改
//顺序表的动态存储
typedef struct SeqList
{
    SLDataType* a;//指向动态开辟数组
    size_t size; //有效数据个数
    size_t capacity;//容量大小
}SeqList;

//初始化顺序表
void SeqListInit(SeqList* ps1);
//销毁顺序表
void SeqListDestory(SeqList* ps1);
//检查顺序表容量是否满了,好进行增容
void CheckCapacity(SeqList* ps1);
//顺序表尾插
void SeqListPushBack(SeqList* ps1, SLDataType x);//O(1)
//顺序表尾删
void SeqListPopBack(SeqList* ps1);//O(1)
//顺序表头插
void SeqListPushFront(SeqList* ps1, SLDataType x);//O(n)
//顺序表头删
void SeqListPopFront(SeqList* ps1);//O(n)
//打印顺序表
void SeqListPrint(const SeqList* ps1);
//在顺序表中查找指定的值
int SeqListFind(const SeqList* ps1, SLDataType x);
//在顺序表指定下标位置插入数据
void SeqListInsert(SeqList* ps1, size_t pos, SLDataType x);
//在顺序表中删除指定下标位置的数据
void SeqListErase(SeqList* ps1, size_t pos);
//查看顺序表中数据个数
size_t SeqListSize(const SeqList* ps1);
//修改指定下标位置的数据
void SeqListAt(SeqList* ps1, size_t pos, SLDataType x);

三. SeqList.c 中各个接口的实现。

3.1 初始化顺序表

(要加上断言,防止传进来的指针为空)

void SeqListInit(SeqList* psl)
{
    assert(psl != NULL);//断言
 

    psl->a = NULL;  //初始顺序表为空
    psl->size = 0;  //初始数据个数为0
    psl->capacity = 0;  //初始空间容量为0
}

3.2 销毁(释放)顺序表

(也是要加上断言,防止传进来的指针为空)

//销毁(释放)顺序表
void SeqListDestory(SeqList* ps1)
{
    assert(ps1 != NULL);//断言

    free(ps1->a); //释放动态开辟的空间
    ps1->a = NULL;//置空
    ps1->size = 0;//数据个数置零
    ps1->capacity = 0;//空间容量大小置零

}

3.3 检查顺序表容量是否满了,好进行增容

多少倍都可以,不过一般扩2倍。2倍、1.5倍、是比较合适的方案。

void CheckCapacity(SeqList* ps1)//检查顺序表容量是否已满
{
    //满了则扩容
    if (ps1->size == ps1->capacity)
    {
        size_t Newcapacity;//新容量
        if (ps1->capacity == 0)
            Newcapacity = ps1->capacity = 4;//原来容量为零,扩容为4
        else
            Newcapacity = 2 * ps1->capacity;//原来容量不为0,扩容为原来2倍

        SLDataType* p = (SLDataType*)realloc(ps1->a, Newcapacity * sizeof(SLDataType));//扩容
        if (p == NULL)
        {
            perror("realloc");
            exit(-1);
        }
        ps1->a = p;// P不为空、开辟成功
        ps1->capacity = Newcapacity;//
        //ps1->capacity *= 2;
    }

}

3.4 realloc 原地扩容、异地扩容

异地扩容,会帮你把原数据拷贝过去,并且原空间会释放


3.5 顺序表尾插

void SeqListPushBack(SeqList* ps1, SLDataType x)
{
    assert(ps1 != NULL);
    CheckCapacity(ps1); // 检查顺序表容量是否已满,满了则扩容
    ps1->a[ps1->size] = x; //尾插数据
    ps1->size++;//有效数据个数+1
}

测试

void SeqListPrint(const SeqList* ps1)
{
    int i = 0;
    for (i = 0; i < ps1->size; i++)
    {
        printf("%d ", ps1->a[i]);
    }
}

void TestSeqList1()
{
    SeqList s1;
    //初始化顺序表
    SeqListInit(&s1);
    //尾差数据
    SeqListPushBack(&s1, 1);
    SeqListPushBack(&s1, 2);
    SeqListPushBack(&s1, 3);
    SeqListPushBack(&s1, 4);
    SeqListPushBack(&s1, 5);
    SeqListPushBack(&s1, 6);
    SeqListPrint(&s1);
    SeqListDestory(&s1);

}

int main()
{
    TestSeqList1();
    return 0;
}

3.6 顺序表尾删

SLDataType 不知道是什么类型的数据,不能冒然的将顺序表最后一个数据赋值为 0,我们只需将有效数据个数 size 减 1 即可达到尾删的目的。

void SeqListPopBack(SeqList* ps1 )
{
    assert(ps1 !=NULL);
    assert(ps1->size > 0);//顺序表不能为空

    ps1->size--; //有效数据个数-1
}

测试结果

完整代码

//尾删

void SeqListPushBack(SeqList* ps1, SLDataType x)
{
    assert(ps1 != NULL);
    CheckCapacity(ps1); // 检查顺序表容量是否已满,满了则扩容
    ps1->a[ps1->size] = x; //尾插数据
    ps1->size++;//有效数据个数+1
}

void SeqListPrint(const SeqList* ps1)
{
    int i = 0;
    for (i = 0; i < ps1->size; i++)
    {
        printf("%d ", ps1->a[i]);
    }
    printf("\n");
}

void SeqListPopBack(SeqList* ps1 )
{
    assert(ps1 !=NULL);
    assert(ps1->size > 0);//顺序表不能为空

    ps1->size--; //有效数据个数-1
}

void TestSeqList1()
{
    SeqList s1;
    //初识化顺序表
    SeqListInit(&s1);
    //尾插数据
    SeqListPushBack(&s1, 1);
    SeqListPushBack(&s1, 2);
    SeqListPushBack(&s1, 3);
    SeqListPushBack(&s1, 4);
    SeqListPushBack(&s1, 5);

    SeqListPrint(&s1);

    //尾删数据
    SeqListPopBack(&s1);
    SeqListPrint(&s1);
    SeqListPopBack(&s1);
    SeqListPrint(&s1);

    SeqListDestory(&s1);

}

int main()
{
    TestSeqList1();
    return 0;
}

3.7 顺序表头插

顺序表是连续的,所以头插时要依次挪动数据

//头插

void SeqListPushFront(SeqList* ps1, SLDataType x)
{
    assert(ps1);
    CheckCapacity(ps1);
    int i = 0;
    for (i = ps1->size - 1; i >= 0; i--)
    {
        ps1->a[i + 1] = ps1->a[i];
    }
    ps1->a[0] = x;//头插数据
    ps1->size++;
}

测试结果

完整代码

//头插

void SeqListPushFront(SeqList* ps1, SLDataType x)
{
    assert(ps1);
    CheckCapacity(ps1);
    int i = 0;
    for (i = ps1->size - 1; i >= 0; i--)
    {
        ps1->a[i + 1] = ps1->a[i];
    }
    ps1->a[0] = x;//头插数据
    ps1->size++;
}


void SeqListPushBack(SeqList* ps1, SLDataType x)
{
    assert(ps1 != NULL);
    CheckCapacity(ps1); // 检查顺序表容量是否已满,满了则扩容
    ps1->a[ps1->size] = x; //尾插数据
    ps1->size++;//有效数据个数+1
}

void TestSeqList1()
{
    SeqList s1;
    //初始化顺序表
    SeqListInit(&s1);
    //尾插数据
    SeqListPushBack(&s1, 1);
    SeqListPushBack(&s1, 2);
    SeqListPushBack(&s1, 3);
    SeqListPushBack(&s1, 4);
    SeqListPushBack(&s1, 5);
    SeqListPrint(&s1);
    //头插数据
    SeqListPushFront(&s1, 11);
    SeqListPushFront(&s1, 22);
    SeqListPushFront(&s1, 33);
    SeqListPrint(&s1);

    SeqListDestory(&s1);
}

void SeqListPrint(const SeqList* ps1)
{
    int i = 0;
    for (i = 0; i < ps1->size; i++)
    {
        printf("%d ", ps1->a[i]);
    }
    printf("\n");
}

int main()
{
    TestSeqList1();
    return 0;
}

3.8 顺序表头删

顺序表是连续的,头删时要依次挪动数据

//头删
void SeqListPopFront(SeqList* psl)
{
    assert(psl);  //断言
    assert(psl->size > 0);  //顺序表不能为空

    int i = 0;
    for (i = 1; i < psl->size; i++)  //顺序表中[1,size-1]的元素依次向前挪动一位
    {
        psl->a[i - 1] = psl->a[i];
    }
    psl->size--;  //有效数据个数-1
}

测试结果

完整代码

void SeqListPushBack(SeqList* ps1, SLDataType x)
{
    assert(ps1 != NULL);
    CheckCapacity(ps1); // 检查顺序表容量是否已满,满了则扩容
    ps1->a[ps1->size] = x; //尾插数据
    ps1->size++;//有效数据个数+1
}

void SeqListPrint(const SeqList* ps1)
{
    int i = 0;
    for (i = 0; i < ps1->size; i++)
    {
        printf("%d ", ps1->a[i]);
    }
    printf("\n");
}
//头删
void SeqListPopFront(SeqList* psl)
{
    assert(psl);  //断言
    assert(psl->size > 0);  //顺序表不能为空

    int i = 0;
    for (i = 1; i < psl->size; i++)  //顺序表中[1,size-1]的元素依次向前挪动一位
    {
        psl->a[i - 1] = psl->a[i];
    }
    psl->size--;  //有效数据个数-1
}



void TestSeqList1()
{
    SeqList s1;
    //初始化顺序表
    SeqListInit(&s1);
    //尾插数据
    SeqListPushBack(&s1, 1);
    SeqListPushBack(&s1, 2);
    SeqListPushBack(&s1, 3);
    SeqListPushBack(&s1, 4);
    SeqListPushBack(&s1, 5);
    SeqListPrint(&s1);

    //头删数据
    SeqListPopFront(&s1);
    SeqListPopFront(&s1);
    SeqListPrint(&s1);
    
    SeqListDestory(&s1);
}

int main()
{
    TestSeqList1();
    return 0;
}

四. 打印顺序表


五. 在顺序表中查找指定值

int SeqListFind(const SeqList* ps1, SLDataType x)
{
    assert(ps1);
     
    int i = 0;
    for (i = 0; i < ps1->size; i++)
    {
        if (ps1->a[i] == x)
        {
            return i; //找到,返回该值下标
        }
    }
    return -1; //没找到
}

测试结果

完整代码

int SeqListFind(const SeqList* ps1, SLDataType x)
{
    assert(ps1);
     
    int i = 0;
    for (i = 0; i < ps1->size; i++)
    {
        if (ps1->a[i] == x)
        {
            return i; //找到,返回该值下标
        }
    }
    return -1; //没找到
}


void SeqListPushBack(SeqList* ps1, SLDataType x)
{
    assert(ps1 != NULL);
    CheckCapacity(ps1); // 检查顺序表容量是否已满,满了则扩容
    ps1->a[ps1->size] = x; //尾插数据
    ps1->size++;//有效数据个数+1
}

void TestSeqList1()
{
    SeqList s1;
    //初始化顺序表
    SeqListInit(&s1);
    //尾插数据
    SeqListPushBack(&s1, 1);
    SeqListPushBack(&s1, 3);
    SeqListPushBack(&s1, 5);
    SeqListPushBack(&s1, 7);
    SeqListPushBack(&s1, 9);
    //查找指定数据
    int ret = SeqListFind(&s1, 7);
    if (ret == -1)
        printf("没找到\n");
    else
        printf("x=%d\n", s1.a[ret]);
    SeqListDestory(&s1);

}


int main()
{
    TestSeqList1();
    return 0;
}

六. 在顺序表指定下标位置插入数据

void SeqListInsert(SeqList* ps1, size_t pos, SLDataType x)
{
    assert(ps1);
    assert(pos >= 0 && pos <= ps1->size);//先检查pos下标的合法性

    CheckCapacity(ps1);

    size_t i = 0;
    for (i = ps1->size; i > pos; i--)//将pos位置后面的数据依次向后挪动一位
    {
        ps1->a[i] = ps1->a[ i - 1];
    }
    ps1->a[pos] = x;
    ps1->size++;

}

测试结果


七. 在顺序表中删除指定下标位置的数据

void SeqListErase(SeqList* psl, size_t pos)
{
    assert(psl);  
    assert(psl->size > 0);  //顺序表不能为空
    assert(pos >= 0 && pos < psl->size);  //检查pos下标的合法性

    size_t i = 0;
    for (i = pos + 1; i < psl->size; i++)  //将pos位置后面的数据依次向前挪动一位
    {
        psl->a[i - 1] = psl->a[i];
    }
    psl->size--;  //有效数据个数-1
}

测试结果

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

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

相关文章

Java实现Modbus Tcp协议读写模拟工具数据

标题 前言一、读写模拟工具中数据(1) 定义Controller层(2) 定义Service层实现 二、调试(1) 读数据(2) 向寄存器写单个数据(3) 向寄存器写多个数据 前言 参考文章&#xff1a;https://www.cnblogs.com/ioufev/p/10831289.html 该文中谈及常见的几种读取设备数据实现&#xff0…

无硬盘的版本 1099,14寸笔记本,而且无硬盘的,特别有有意思,可以自己购买个硬盘,安装linux系统或者windows。

1&#xff0c;千元笔记本&#xff0c;金属外壳 有人进行评测了&#xff1a; https://www.bilibili.com/video/BV1Td4y1K7Cp 1499元的全新笔记本&#xff0c;有什么猫腻&#xff1f; 看了下价格&#xff0c;现在还优惠400&#xff0c;变成了1099。 https://item.jd.com/100851…

Django — 请求和响应

目录 一、请求1、概念2、请求参数方式分类3、案例3.1、URL 路径参数3.2、查询字符串参数3.3、form 表单传参3.4、Json 格式参数3.5、上传文件 二、响应1、HttpResponse2、JsonResponse 三、GET 和 POST 区别1、相同点2、不同点 一、请求 1、概念 请求&#xff08;Request&…

DDR4 眼图测试方法

DDR的全拼是Double Data Rate SDRAM双倍数据速率同步动态随机存取内存。主要就是用在电脑的内存。他的特点就是走线数量多&#xff0c;速度快&#xff0c;操作复杂&#xff0c;给测试和分析带来了很大的挑战。目前DDR技术已经发展到了DDR5&#xff0c;性能更高&#xff0c;功耗…

【算法练习Day4】 两两交换链表节点删除链表倒数第 N 个结点环形链表 II

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 两两交换链表中的节点一…

毫米波雷达 TI IWR1443 在 ROS 中进行 octomap 建图

个人实验记录 /mmwave_ti_ros/ros_driver/src/ti_mmwave_rospkg/launch/1443_multi_3d_0.launch <launch><!-- Input arguments --><arg name"device" value"1443" doc"TI mmWave sensor device type [1443, 1642]"/><arg…

一例“msvc编译器O2优化导致的崩溃”的分析

1. 初步分析 某进程崩溃必现。 打开崩溃dmp&#xff0c;结合c源代码&#xff0c;崩溃大致发生在某dll代码里的这句&#xff1a;SAFE_DELETE(pContentData); En_HP_HandleResult CTcpOperation::OnClintReceive(HP_Client pSender, HP_CONNID dwConnID, const BYTE * pdata, i…

组队竞赛(int溢出问题)

目录 一、题目 二、代码 &#xff08;一&#xff09;没有注意int溢出 &#xff08;二&#xff09;正确代码 1. long long sum0 2. #define int long long 3. 使用现成的sort函数 一、题目 二、代码 &#xff08;一&#xff09;没有注意int溢出 #include <iostream&g…

机器学习的主要内容

分类任务 回归任务 有一些算法只能解决回归问题有一些算法只能解决分类问题有一些算法的思路既能解决回归问题&#xff0c;又能解决分类问题 一些情况下&#xff0c; 回归任务可以转化为分类任务&#xff0c; 比如我们预测学生的成绩&#xff0c;然后根据学生的成绩划分为A类、…

js制作柱状图的x轴时间, 分别展示 月/周/日 的数据

背景 有个需求是要做一个柱状图, x 轴是时间, y 轴是数量. 其中 x 轴的时间有三种查看方式: 月份/周/日, 也就是分别查看从当前日期开始倒推的最近每月/每周/每日的数量. 本篇文章主要是用来制作三种不同的 x 轴 从当前月开始倒推月份 注意 getMonth() 函数可以获取当前月份…

【【萌新的FPGA学习之实战流水灯】】

萌新的FPGA学习之实战流水灯 实验任务 本节的实验任务是使用领航者底板上的两个 PL LED 灯顺序点亮并熄灭&#xff0c;循环往复产生流水灯的效 果&#xff0c;流水间隔时间为 0.5s。 1MHz&#xff1d;1000000Hz 10的6次方 1ns&#xff1d;10的-9次方秒 开发板晶振50Mhz 计算得…

如何看待Unity新的收费模式?

文章目录 背景Unity的论点开发者的担忧如何看待Unity新的收费模式&#xff1f;1. 理解Unity的立场2. 考虑小型开发者3. 探索替代方案4. 对市场变化保持敏感5. 提高游戏质量 结论 &#x1f389; 如何看待Unity新的收费模式&#xff1f; ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1…

R语言柱状图直方图 histogram

柱状图简介 柱状图也叫直方图&#xff0c;是展示连续性数值的分布状况。在x轴上将连续型数值分为一定数量的组&#xff0c;y轴显示对应值的频数。 R基本的柱状图 hist 我们用R自带的Orange数据来画图。 > head(Orange)Tree age circumference(圆周长) 1 1 118 …

Docker搭建DNS服务器--nouse

前言 DNS服务器是(Domain Name System或者Domain Name Service)域名系统或者域名服务,域名系统为Internet上的主机分配域名地址和IP地址。 安装 2.1 实验环境 IP 系统版本 角色 192.168.40.121 Ubuntu 22.10 DNS服务器 192.168.40.122 Ubuntu 22.10 测试机器 2.2 …

数据库选型参考

嵌入式数据库 SQLite、Berkeley DB、Derby、H2、HSQL DB SQLite&#xff1a; SQLite是一种非常流行的文件型数据库&#xff0c;它是一款轻量级、高性能、开源的嵌入式数据库引擎。SQLite采用C语言编写&#xff0c;可以在各种操作系统上运行&#xff0c;并且支持大多数标准SQL语…

csa从初阶到大牛(训练题1)

使用普通账户新建如下结构的2个目录&#xff1a; ~/t1/t2/t3/t4&#xff0c;~/m1/m2/m3/m4,并显示t1目录的详细信息&#xff0c;将/etc/passwd文件拷贝到~/t1/t2/t3目录下面&#xff0c;将~/t1/下面的内容拷贝到~/m1/m2/m/3/m4目录下面,最后删除~/t1/t2/t3下面的目录 # 创建目…

前端JavaScript入门到精通,javascript核心进阶ES6语法、API、js高级等基础知识和实战 —— JS基础(四)

开始吧&#xff0c;做时间的主人&#xff01; 把时间分给睡眠&#xff0c;分给书籍&#xff0c;分给运动&#xff0c; 分给花鸟树木和山川湖海&#xff0c; 分给你对这个世界的热爱&#xff0c; 而不是将自己浪费在无聊的人和事上。 思维导图 函数 为什么需要函数 <!DO…

pytest框架运行时的参数,以及多线程分布式运行用例、运行指定模块用例

一、运行时的参数 在上一篇博客中写了pytest最为核心的运行时前后置如何设置&#xff0c;细心的朋友可能也会发现其实我们当时就加过运行时的参数-vs。 pytest.main([‘-s’])&#xff1a;能打印出调试信息&#xff0c;print()或者日志都可以直接打印在控制台上。 pytest.ma…

栈和队列1——栈的实现及其oj(括号匹配问题)

一&#xff0c;栈的概念 栈是一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&#xf…

【100天精通Python】Day68:Python可视化_Matplotlib 绘制热力图,示例+代码

目录 1 值热力图&#xff08;Value Heatmap&#xff09;: 2 密度热力图&#xff08;Density Heatmap&#xff09; 3 时间热力图&#xff08;Time Heatmap&#xff09;: 4 空间热力图&#xff08;Spatial Heatmap&#xff09; 5 渐变热力图&#xff08;Gradient Heatmap&am…