【数据结构】顺序表---C语言版

【数据结构】顺序表

  • 前言:
  • 一、线性表
  • 二、顺序表
    • 1.顺序表的概念及结构:
    • 2.顺序表的分类:
    • 3.顺序表缺陷:
  • 三、顺序表的代码实现:
    • 1.头文件:
    • 2.函数文件:
    • 3.测试文件:
  • 四、顺序表的相关OJ题:
    • (1)原地移除数组中所有的元素val:
      • 1.题目描述:
      • 2.思路表述:
      • 3.代码实现:
    • (2)删除有序数组中的重复项
      • 1.题目描述:
      • 2.思路表述:
      • 3.代码实现:
    • (3)合并两个有序数组
      • 1.题目描述:
      • 2.思路表述:
      • 3.代码实现:

前言:

顺序表是一种常见的数据结构,今天就让我来带领大家一起学习一下吧!
不会再休息,一分一毫了,OK,let’s go!

一、线性表

  1. 线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使
    用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串
  2. 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的
    线性表在物理上存储时,通常以数组和链式结构的形式存储。

在这里插入图片描述

二、顺序表

1.顺序表的概念及结构:

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

2.顺序表的分类:

顺序表一般可以分为:

  1. 静态顺序表:使用定长数组存储元素。
//顺序表的静态存储
#define N 7
typedef int SLDataType;
 
typedef struct SeqList
{
	SLDataType array[N];//定长数组
	size_t size;//有效数据的个数
}SeqList;

在这里插入图片描述
2. 动态顺序表:使用动态开辟的数组存储。

typedef struct SeqList
{
	SLDataType* array;//指向动态开辟的数组
	size_t size;//有效数据的个数
	size_t capacity;//容量
}SeqList;

在这里插入图片描述

3.顺序表缺陷:

  1. 顺序表缺陷:

(1)动态增容有性能消耗。

(2)当头部插入数据时,需要挪动数据

三、顺序表的代码实现:

1.头文件:

#pragma once

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

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* s;//顺序表的名称(头指针!)

	int size;//储存的有效个数!
	int capacity;//整块空间的大小!
}SL;


//初始化
void SLInit(SL* ps);
//销毁
void SLDestory(SL* ps);
//打印
void SLPrint(SL* ps);



//管理数据:增删查改

//尾插
void PushBack(SL* ps, SLDataType x);
//头插
void PushFront(SL* ps, SLDataType x);

//尾删
void PopBack(SL* ps);
//头删
void PopFront(SL* ps);

//判断是否扩容
void SLCheckCapacity(SL* ps);

//在pos位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x);

2.函数文件:

#define _CRT_SECURE_NO_WARNINGS 1 
#include <stdio.h>
#include "SeqList.h"

//初始化函数
void SLInit(SL* ps)
{
	assert(ps);

	//创建空间
	ps->s = (SLDataType*)malloc(sizeof(SLDataType)*4);
	if (ps->s == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

	ps->size = 0;
	ps->capacity = 4;
}

//销毁函数
void SLDestory(SL* ps)
{
	free(ps);

	ps->s = NULL;
	ps->size = ps->capacity = 0;
}

//打印函数
void SLPrint(SL* ps)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->s[i]);
	}
	printf("\n");
}


//判断是否扩容
void SLCheckCapacity(SL* ps)
{
	assert(ps);

	if (ps->size == ps->capacity)
	{
		//需要扩容
		SLDataType* tmp = (SLDataType*)realloc(ps->s, sizeof(SLDataType) * ps->capacity * 2);//扩大了原来容量的二倍。

		//SLDataType* tmp = (SLDataType*)realloc(ps->s, 2 * ps->capacity);标准的错误写法!
		//如果空间不够用,要对一些元素进行扩容。我们扩容的标准:就是为这些元素申请它 自身大小 整数倍 的空间!所以说为什么要sizeof(数据类型),然后再乘以扩大的容量的倍数
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->s = tmp;
		ps->capacity *= 2;
	}
	
}

//尾插
void PushBack(SL* ps, SLDataType x)
{
	//检查容量
	SLCheckCapacity(ps);

	ps->s[ps->size] = x;
	ps->size++;
}

//尾删
void PopBack(SL* ps)
{
	assert(ps);

	ps->size--;

}

//头插(利用一个end指针从后往前拷贝!)
void PushFront(SL* ps, SLDataType x)
{
	assert(ps);

	//检查容量
	SLCheckCapacity(ps);

	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->s[end+1] = ps->s[end];
		end--;
	}
	ps->s[0] = x;
	ps->size++;
}


//头删
void PopFront(SL* ps)
{
	assert(ps);

	int begin = 0;
	while (begin < ps->size-1)
	{
		ps->s[begin] = ps->s[begin + 1];
		begin++;
	}
	ps->size--;
}


//在pos位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x)

{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	SLCheckCapacity( ps);

	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->s[end+1] = ps->s[end];
		end--;
	}
	ps->s[pos] = x;
	ps->size++;
}

3.测试文件:

#define _CRT_SECURE_NO_WARNINGS 1 
#include <stdio.h>
#include "SeqList.h"



void test1()
{
	SL s1;
	SLInit(&s1);

	PushFront(&s1, 1);
	PushFront(&s1, 2);
	PushFront(&s1, 3);
	PushFront(&s1, 4);
	PushFront(&s1, 5);

	SLPrint(&s1);

	PopFront(&s1);
	PopFront(&s1);
	PopFront(&s1);

	SLPrint(&s1);

}


void test2()
{
	SL s2;

	SLInit(&s2);

	PushBack(&s2,1);
	PushBack(&s2,2);
	PushBack(&s2,3);
	PushBack(&s2,4);
	PushBack(&s2,5);

	SLPrint(&s2);

	PopBack(&s2);
	PopBack(&s2);
	PopBack(&s2);

	SLPrint(&s2);
}


void test3()
{
	SL s2;

	SLInit(&s2);

	PushBack(&s2, 1);
	PushBack(&s2, 2);
	PushBack(&s2, 3);
	PushBack(&s2, 4);
	PushBack(&s2, 5);

	SLPrint(&s2);

	SLInsert(&s2, 3, 6);//在下标为3的数据之前插入一个6

	SLPrint(&s2);
}

int main()
{

	//test1();//测试头插,头删

	//test2();//测试尾插 尾删

	test3();//测试在pos位置之前插入数据!
	return 0;

}

在这里插入图片描述

四、顺序表的相关OJ题:

(1)原地移除数组中所有的元素val:

1.题目描述:

1.原地移除数组中所有的元素val,要求时间复杂度为O(N),空间复杂度为O(1)。OJ链接:OJ链接
在这里插入图片描述

2.思路表述:

在这里插入图片描述

3.代码实现:

int removeElement(int* nums, int numsSize, int val) 
{
    int src=0;
    int dst=0;
    while(src<numsSize)
    {
        if(nums[src]!=val)
        {
            nums[dst++]=nums[src++];
        }
        else
        {
            src++;
        }
    }
    return dst;//返回的是:新数组的长度,因为最后一步出循环的时候,dst已经++了,所以说直接返回dst就行了
}

(2)删除有序数组中的重复项

1.题目描述:

在这里插入图片描述

2.思路表述:

还使用双下标法:
在这里插入图片描述

3.代码实现:

int removeDuplicates(int* nums, int numsSize) 
{
    int dst=1;
    int src=0;
    while(dst<numsSize)
    {
        if(nums[dst]!=nums[src])
        {
          //nums[++src]=nums[dst++];//这里的src一定要是前置++,先++,然后再赋值。
          
          src++;
          nums[src]=nums[dst];
          dst++;
        }
        else
        {
            
            dst++;
        }
    }
    return src+1;
}

(3)合并两个有序数组

1.题目描述:

在这里插入图片描述

2.思路表述:

使用3下标法
在这里插入图片描述

3.代码实现:

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) 
{
   int end1=m-1;
   int end2=n-1;
   int end=m+n-1;
   while(end1>=0&&end2>=0)
   {
       if(nums1[end1]>nums2[end2])
       {
           nums1[end--]=nums1[end1--];
       }
       else
       {
           nums1[end--]=nums2[end2--];
       }
   }
   //因为用nums1的初始长度是m+n,所以不会担心数组大小不够用。
   //下面这个循环是针对:比如说nums1中的所有数字都插到自己数组后面了,但是因为两个数组都是有序的,所以我只需要把nums2中的全部数字依次放到nums1前面就行了。
   while(end2>=0)
   {
       nums1[end--]=nums2[end2--];
   }
}

好了,今天的分享就到这里了
如果对你有帮助,记得点赞👍+关注哦!
我的主页还有其他文章,欢迎学习指点。关注我,让我们一起学习,一起成长吧!

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unreal Engine 学习笔记 (4)—— 多方向动画

1.创建混合空间 1.设置水平方向命名为Direction表示行进方向 -45,300表示向左前方45度方向行走-90,300表示向正左方90度方向行走-135,300表示向左后方45度方向行走-180,300表示向正后方行走右侧方向动画与上述左侧使用同样方法设置Run动画与Walk动画使用同样方法设置 2. 设置…

数据库第十第十一章 恢复和并发简答题

数据库第一章 概论简答题 数据库第二章 关系数据库简答题 数据库第三章 SQL简答题 数据库第四第五章 安全性和完整性简答题 数据库第七章 数据库设计简答题 数据库第九章 查询处理和优化简答题 1.什么是数据库中的事务&#xff1f;它有哪些特性&#xff1f;这些特性的含义是什么…

Spring不再支持Java8了

在今天新建模块的时候发现了没有java8的选项了&#xff0c;结果一查发现在11月24日&#xff0c;Spring不再支持8了&#xff0c;这可怎么办呢&#xff1f;我们可以设置来源为阿里云https://start.aliyun.com/ 。 java8没了 设置URL为阿里云的地址

spring-webmvc练习-日程管理-访问后端展示列表数据

1、util/request.js import axios from "axios";let request axios.create({baseURL: "http://localhost:8080",timeout: 50000 });export default request 2、api/schedule.js import request from "../util/request.js";export let getSchedu…

【重磅】:Spring Initializer 已经不支持Java8,也就是SpringBoot2.x项目初始化

Spring Initializer 已经不支持Java8 问题描述解决方案升级java版本更换IDEA内置的Spring Initializer中 Server URL的镜像地址 问题描述 我们可以看到在IDEA内置的Spring Initializer中 Java版本选择模块已经不支持1.8了&#xff0c;同样的&#xff0c;官网也不再支持了 解决…

为何要隐藏IP地址?网络上哪些行为需要隐藏IP和更换IP?

网络已经成为现代人生活的重要组成部分&#xff0c;人们在网络上交流、学习、娱乐、购物等。但是&#xff0c;在享受网络带来的便利时&#xff0c;我们也需要时刻保护自己的隐私和安全。其中&#xff0c;IP地址作为网络通信中的重要标识&#xff0c;如何隐藏以及在哪些情况下需…

掌握反转链表的艺术:LeetCode 206 深入解析与优化 - 双指针与递归方法精讲

LeetCode.206反转链表 1.问题描述2.解题思路3.代码 1.问题描述 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a…

SpringBoot监控Redis事件通知

Redis的事件通知 Redis事件通过 Redis 的订阅与发布功能&#xff08;pub/sub&#xff09;来进行分发&#xff0c; 因此所有支持订阅与发布功能的客户端都可以在无须做任何修改的情况下&#xff0c; 使用键空间通知功能。 因为 Redis 目前的订阅与发布功能采取的是发送即忘&am…

oracle impdp 导入元数据表空间异常增大的解决办法

expdp导出的时候指定了contentsmetadata_only只导出元数据&#xff0c;但是在impdp导入到新库的时候&#xff0c;发现新库的表空间增长非常大&#xff0c;其实这个直接就可以想到&#xff0c;应该是大表的initial segment过大导致的 正常impdp&#xff0c;在执行创建表和索引的…

SocialFi 和 GameFi 的碰撞 — Socrates 构建新的 Web3 流量入口

伴随着比特币现货 ETF 即将通过 SEC 批准的消息&#xff0c;整个加密市场在11月份达到了熊市以来的新高峰。市场普遍上涨&#xff0c;新的玩法和项目不断涌出吸引了大量老用户回归以及新用户加入。加密市场经过长期的低迷&#xff0c;终于来到了牛市的起点&#xff01; 上一轮牛…

振南技术干货集:znFAT 硬刚日本的 FATFS 历险记(6)

注解目录 1、znFAT 的起源 1.1 源于论坛 &#xff08;那是一个论坛文化兴盛的年代。网友 DIY SDMP3 播放器激起了我的兴趣。&#xff09; 1.2 硬盘 MP3 推了我一把 &#xff08;“坤哥”的硬盘 MP3 播放器&#xff0c;让我深陷 FAT 文件系统不能自拔。&#xff09; 1.3 我…

正则表达式和awk

目录 一、正则表达式 1.正则表达式基本介绍 2.正则表达式分类 3.基本正则表达式分类 4.代表字符 5.表示次数 6.位置锚定 7.分组或其他 8.扩展正则表达式 二、awk 1.语法 2.选项 3.基础用法 4.内置变量 5.条件判断 6.数组 总结&#xff1a;本章主要介绍了正则表…

分享:身份证阅读器在ARM Linux系统调用libwlt2bmp.so解码库实现身份证头像解码

头像解码库&#xff1a;libwlt2bmp.so 照片文件名&#xff1a;photo.bmp 原始身份证相片数据&#xff1a;574C66007E00320000F........&#xff08;此处省略&#xff09; 调用身份证阅读器Linux开发包&#xff0c;然后调用libwlt2bmp.so解码库文件&#xff0c;传入身份证原始…

0基础学习VR全景平台篇第123篇:VR视频航拍补天 - PR软件教程

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 嗨&#xff0c;大家好&#xff0c;今天我们来介绍【航拍VR视频补天】。之前已经教给了大家如何处理航拍图片的补天&#xff0c;肯定有很多小伙伴也在好奇&#xff0c;航拍的VR视频…

地图标注系统v0.10.1

微启地图标注系统 thinkphpuniapp前端&#xff0c;微信小程序已适配&#xff0c;近期更新抖音小程序和QQ小程序&#xff0c;后期上分销功能&#xff0c;标注系统用户粘性不算大&#xff0c;本着小程序用完即走的理念&#xff0c;暂时没打算适配安卓和iOS 主要功能 用户端&am…

移动安全威胁:今天和明天的危险

随着技术的发展&#xff0c;个人和公司的设备、数据和隐私所面临的威胁也在发生变化。在本文中&#xff0c;我们将仔细研究当今移动设备安全面临的主要威胁&#xff0c;并共同探讨不久的将来的前景。 但首先让我们从基础开始&#xff1a;如何对移动设备发起攻击&#xff1f; …

1.ORB-SLAM3中如何保存多地图、关键帧、地图点到二进制文件中

1 保存多地图 1.1 为什么保存(视觉)地图 因为我们要去做导航&#xff0c;导航需要先验地图。因此需要保存地图供导航使用&#xff0c;下面来为大家讲解如何保存多地图。 1.2 保存多地图的主函数SaveAtlas /*** brief 保存地图* param type 保存类型*/ void System::SaveAtlas(…

机器学习中的概率与统计知识点汇总

引言 在学习高级知识时&#xff0c;理解基本概念至关重要。为什么&#xff1f;因为基础知识是您构建高级知识的基础。如果你把更多的东西放在薄弱的基础之上&#xff0c;它最终可能会分裂&#xff0c;这意味着你最终无法完全理解你所学的任何知识。因此&#xff0c;让我们尝试…

如何正确选择爬虫采集接口和API?区别在哪里?

在信息时代&#xff0c;数据已经成为了一个国家、一个企业、一个个人最宝贵的资源。而爬虫采集接口则是获取这些数据的重要手段之一。本文将从以下八个方面进行详细讨论&#xff1a; 1.什么是爬虫采集接口&#xff1f; 2.爬虫采集接口的作用和意义是什么&#xff1f; 3.爬虫…

智慧城市政务一网统管解决方案:PPT全文34页,附下载

关键词&#xff1a;智慧政务解决方案&#xff0c;智慧城市解决方案&#xff0c;智慧政务一网统管解决方案&#xff0c;一网统管治理理念&#xff0c;一网统管治理体系&#xff0c;一网统管治理手段&#xff0c;智慧政务综合服务平台建设 一、智慧城市政务一网统管建设背景 一…