《C++》解密--顺序表

news2024/11/16 3:46:44

一、线性表

           线性表是n个具有相同特性的数据元素的有限序列。                                                                           线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈......

      线性表在【逻辑上】是线性结构,也就是连续的一条直线;                                                            但在【物理结构】上不一定是连续的,线性表在物理上储存时,通常是数组、链式结构等形式。

二、顺序表

1、概念

     顺序表是线性表的一种。

     顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般采用数组存储。

     【顺序表在逻辑结构物理结构上都是线性的

2、顺序表和数组区别

    顺序表的底层结构数组,对数组的封装,实现了常用的增删改查等接口。

三、分类

1、静态顺序表

2、动态顺序表

四、动态顺序表的实现

1、创立文件

2、顺序表的初始化和销毁

【SeqList.h】
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

//定义动态顺序表结构
typedef int SLDatatype;

struct SeqList
{
	SLDatatype* arr;
	int capacity;   //空间大小
	int size;      //有效数据个数
};

typedef struct SeqList SL;  //给结构体SeqList改个名字SL

//顺序表的初始化
void SLInit(SL* ps);

//顺序表的销毁
void SLDestory(SL* ps);
【SeqList.c】
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"SeqList.h"

//顺序表的初始化
void SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

//顺序表的销毁
void SLDestory(SL* ps)
{
	if (ps->arr)  //相当于ps->arr != NULL
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}
【test.c】
#include"SeqList.h"

void SLtest01()
{
	SL s;
	SLInit(&s);

	SLDestory(&s);
}

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

3、打印

【SeqList.c】
void SLPrint(SL* ps)
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");
}
【test.c】
#include"SeqList.h"

void SLtest01()
{
	SL s;
	SLInit(&s);

	SLPrint(&s);

	SLDestory(&s);
}

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

4、判断空间是否足够

【SeqList.c】
//判断空间是否充足
void SLCheckCapacity(SL* ps)
{
	//判断空间是否充足
	if (ps->size == ps->capacity)
	{
		//增容  //0*2=0
		//若capacity为0,给个默认值,否则x2倍
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDatatype* tmp = (SLDatatype*)realloc(ps->arr, newCapacity * sizeof(SLDatatype));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity *= newCapacity;
	}
}

5、头插

【SeqList.h】
//头插
void SLPushFront(SL* ps,SLDatatype x);
【SeqList.c】
//头插
void SLPushFront(SL* ps, SLDatatype x)
{
	assert(ps);
	//判断空间是否足够
	SLCheckCapacity(ps);

	//插入操作
	//数据整体后移一位
	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	//下标为0的位置空出来了
	ps->arr[0] = x;
	ps->size++;
}
【test.c】
#include"SeqList.h"

void SLtest01()
{
	SL s;
	SLInit(&s);

	//头插
	SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 4);
	SLPrint(&s);   //4 3 2 1

	SLDestory(&s);
}

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

6、尾插

【SeqList.h】
//尾插
void SLPushBack(SL* ps,SLDatatype x);
【SeqList.c】
//尾插
void SLPushBack(SL* ps, SLDatatype x)
{
	//方式1
	if (ps == NULL)
	{
		return;
	}
	//方式2   粗暴--断言
	//assert(ps); //等价于assert(ps != NULL)

	SLCheckCapacity(ps);
	ps->arr[ps->size++] = x;
}
【test.c】
//尾插
SLPushBack(&s, 1);
SLPushBack(&s, 2);
SLPushBack(&s, 3);
SLPushBack(&s, 4);
SLPrint(&s);   //1 2 3 4

7、头删

【SeqList.h】
//头删
void SLPopFront(SL* ps);
【SeqList.c】
//头删(将第一个以后的数据整体向前挪动一位)
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];  //i = size-2
	}
	ps->size--;
}
【test.c】
	//头删
	SLPopFront(&s);
	SLPrint(&s);   //2 3 4

8、尾删

【SeqList.h】
//尾删
void SLPopBack(SL* ps);
【SeqList.c】
//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	
	//ps->arr[ps->size-1] = -1  //多余了
	ps->size--;
}
【test.c】
//尾删
SLPopBack(&s);
SLPrint(&s);  //1 2 3

10、在指定位置之前插入数据

【SeqList.h】
//在指定位置之前插入数据
void SLInsert(SL* ps, SLDatatype x, int pos);
【SeqList.c】
//在指定位置之前插入数据
//空间足够才可以直接插入
void SLInsert(SL* ps, SLDatatype x, int pos)
{
	assert(ps);
//           头插         尾插
	assert(pos >= 0 && pos <= ps->size);

	//检查空间是否足够,是否可以直接插入
	SLCheckCapacity(ps);

	//pos及之后的数据整体向后移动一位
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];  //pos <-- pos+1
	}
	ps->arr[pos] = x;
	ps->size++;
}
【test.c】
//SLInsert(&s, 11, 0);  //头插11
//SLPrint(&s);     //11 1 2 3 4

//SLInsert(&s, 22, s.size);  //尾插22
//SLPrint(&s);    //1 2 3 4 22

SLInsert(&s, 33, 2);  //指定位置后插入(2后面插入33)
SLPrint(&s);      //1 2 33 3 4

11、删除指定位置的数据

【SeqList.h】
//删除指定位置的数据
void SLErase(SL* ps, int pos);
【SeqList.c】
//删除指定位置的数据
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	//还有很多限制:如顺序表不可以为空...

	//pos之后的数据整体向前挪动一位(一个一个挪)
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];  //size-1 --> size-2
	}
	ps->size--;
}
【test.c】
//指定位置删除
//SLErase(&s, 0);  //删除下标为0的那个数据
//SLPrint(&s);  //2 3 4

SLErase(&s, s.size-1);  //删除最后一个有效数据
SLPrint(&s);  //1 2 3

12、查找

【SeqList.h】
//查找数据
int SLFind(SL* ps, SLDatatype x);
【SeqList.c】
//查找数据
int SLFind(SL* ps, SLDatatype x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return 1;
		}
	}
	//没有找到,就返回一个无效下标
	return -1;
}
【test.c】
//查找数据
int find = SLFind(&s, 21);    
if (find < 0)
{
	printf("顺序表中不存在它!\n");
}
else
{
	printf("find it!\n");
}

13、整体代码

【SeqList.h】

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

//定义动态顺序表结构
typedef int SLDatatype;

struct SeqList
{
	SLDatatype* arr;
	int capacity;   //空间大小
	int size;      //有效数据个数
};

typedef struct SeqList SL;  //给结构体SeqList改个名字SL

//顺序表的初始化
void SLInit(SL* ps);

//顺序表的销毁
void SLDestory(SL* ps);

//头插
void SLPushFront(SL* ps,SLDatatype x);
//尾插
void SLPushBack(SL* ps,SLDatatype x);

//头删
void SLPopFront(SL* ps);
//尾删
void SLPopBack(SL* ps);

//在指定位置之前插入数据
void SLInsert(SL* ps, SLDatatype x, int pos);
//删除指定位置的数据
void SLErase(SL* ps, int pos);

//查找数据
int SLFind(SL* ps, SLDatatype x);

【SeqList.c】

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


//顺序表的初始化
void SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

//顺序表的销毁
void SLDestory(SL* ps)
{
	if (ps->arr)  //相当于ps->arr != NULL
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}


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


//判断空间是否充足
void SLCheckCapacity(SL* ps)
{
	//判断空间是否充足
	if (ps->size == ps->capacity)
	{
		//增容  //0*2=0
		//若capacity为0,给个默认值,否则x2倍
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDatatype* tmp = (SLDatatype*)realloc(ps->arr, newCapacity * sizeof(SLDatatype));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity *= newCapacity;
	}
}


//头插
void SLPushFront(SL* ps, SLDatatype x)
{
	assert(ps);
	//判断空间是否足够
	SLCheckCapacity(ps);

	//插入操作
	//数据整体后移一位
	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	//下标为0的位置空出来了
	ps->arr[0] = x;
	ps->size++;
}

//尾插
void SLPushBack(SL* ps, SLDatatype x)
{
	//方式1
	if (ps == NULL)
	{
		return;
	}
	//方式2   粗暴--断言
	//assert(ps); //等价于assert(ps != NULL)

	SLCheckCapacity(ps);
	ps->arr[ps->size++] = x;
}


//头删(将第一个以后的数据整体向前挪动一位)
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];  //i = size-2
	}
	ps->size--;
}

//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	
	//ps->arr[ps->size-1] = -1  //多余了
	ps->size--;
}


//在指定位置之前插入数据
//空间足够才可以直接插入
void SLInsert(SL* ps, SLDatatype x, int pos)
{
	assert(ps);
//           头插         尾插
	assert(pos >= 0 && pos <= ps->size);

	//检查空间是否足够,是否可以直接插入
	SLCheckCapacity(ps);

	//pos及之后的数据整体向后移动一位
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];  //pos <-- pos+1
	}
	ps->arr[pos] = x;
	ps->size++;
}

//删除指定位置的数据
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	//还有很多限制:如顺序表不可以为空...

	//pos之后的数据整体向前挪动一位(一个一个挪)
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];  //size-1 --> size-2
	}
	ps->size--;
}


//查找数据
int SLFind(SL* ps, SLDatatype x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return 1;
		}
	}
	//没有找到,就返回一个无效下标
	return -1;
}

【test.c】

#include"SeqList.h"

void SLtest01()
{
	SL s;
	SLInit(&s);

	//头插
	/*SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 4);
	SLPrint(&s);  */ //4 3 2 1

	//尾插
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPrint(&s);   //1 2 3 4
	

	//头删
	/*SLPopFront(&s);
	SLPrint(&s);*/   //2 3 4

	尾删
	//SLPopBack(&s);
	//SLPrint(&s);  //1 2 3


	//指定位置之后插入
	//SLInsert(&s, 11, 0);  //头插11
	//SLPrint(&s);     //11 1 2 3 4

	//SLInsert(&s, 22, s.size);  //尾插22
	//SLPrint(&s);    //1 2 3 4 22

	//SLInsert(&s, 33, 2);  //指定位置后插入(2后面插入33)
	//SLPrint(&s);      //1 2 33 3 4


	//指定位置删除
	//SLErase(&s, 0);  //删除下标为0的那个数据
	//SLPrint(&s);  //2 3 4

	//SLErase(&s, s.size-1);  //删除最后一个有效数据
	//SLPrint(&s);  //1 2 3


	//查找数据
	int find = SLFind(&s, 21);    
	if (find < 0)
	{
		printf("顺序表中不存在它!\n");
	}
	else
	{
		printf("find it!\n");
	}


	SLDestory(&s);
}

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

五、顺序表算法题

【示例1】

int removeElement(int* nums, int numsSize, int val) {
  int src = 0;  
  int dst = 0;
  while(src < numsSize)
  {
    if(nums[src] == val)
    {
        src++;
    }
    else
    {
        nums[dst] = nums[src];
        dst++;
        src++;
    }
  }
  //此时dst指向的位置就是要返回的有效个数
  return dst;
}
【示例2】

int removeDuplicates(int* nums, int numsSize) {
    int dst = 0;
    int src = dst + 1;
    while(src <numsSize)
    {
       //nums[dst]  nums[src]
       //相同(重复)src++
       //不相同,dst++,赋值,src++
        if(nums[dst] != nums[src])
        {
            dst++;
            nums[dst] = nums[src];
        }
        
            src++;
       
    }
    return dst+1;
}
【示例3】

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
    int l1 = m-1;
    int l2 = n-1;
    int l3 = m+n-1;

    while(l1 >= 0 && l2 >= 0)
    {
      if(nums1[l1]>nums2[l2])
      {
        nums1[l3] = nums1[l1];
        l3--;
        l1--;
      }
        else
        {
            //l1==l2要么l2>l1
            nums1[l3] = nums2[l2];
            l3--;
            l2--;
        }
    }
    //跳出while循环有两种情况
    //要么l1<0 ; 要么l2<0
    while(l2>=0)
    {
        nums1[l3] = nums2[l2]; 
        l3--;
        l2--;
    }
}
【思考】

感谢观看,未完待续...

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

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

相关文章

构建“零工市场小程序”,服务灵活就业“大民生”

如今&#xff0c;灵活就业已成为现代劳动力市场的重要组成部分。然而&#xff0c;这一就业形态也面临着信息不对称、匹配效率低下等一系列挑战。为有效解决这些问题&#xff0c;构建一个高效、便捷的“零工市场小程序”显得尤为重要。 二、零工市场现状与挑战 市场规模与增长趋…

单调队列的实现

这是C算法基础-数据结构专栏的第二十五篇文章&#xff0c;专栏详情请见此处。 引入 单调队列就是满足单调性的队列&#xff0c;它最经典的应用就是给定一个序列和一个窗口&#xff0c;使窗口在序列中从前向后滑动&#xff0c;求出窗口在每个位置时&#xff0c;其中元素的最大/小…

DC_(n)Xyz

intra-band contiguous EN-DC 配置需要通过DC_(n)Xyz表示&#xff0c;其中第一个字母y表示contiguous E-UTRA carriers数量&#xff0c;第二个字母z表示contiguous NR carrier数量&#xff0c;而(n)X 就代表 E-UTRA band X 和NR band nX这个组合。上图38.101-3 Table 5.3B.0-1 …

Unity同时启动多个Editor

HardLinkShellExt tool https://schinagl.priv.at/nt/hardlinkshellext/linkshellextension.html 作用&#xff1a; 1.网络Online项目方便调试&#xff0c;MMO项目 2.方便发布不同平台的包&#xff0c;快速开发测试 使用方法&#xff1a;

网络药理学:2、文章基本思路、各个数据库汇总与比对、其他相关资料(推荐复现的文章、推荐学习视频、论文基本框架、文献基本知识及知网检索入门)

一、文章基本思路&#xff08;待更&#xff09; 一篇不含分子对接和实验的纯网络药理学文章思路如下&#xff1a; 即如下&#xff1a; 二、 各个数据库&#xff08;待更&#xff09; 三、其他相关资料 1.推荐复现的文章 纯网络药理学分子对接&#xff1a;知网&#xff1…

Java 每日一刊(第6期):整数运算

文章目录 前言Java 的整数类型基本的整数运算符整数除法与取模自增与自减运算整数的进制表示整数溢出问题位运算整数的优化技巧类型自动提升&#xff08;Type Promotion&#xff09;强制类型转换&#xff08;Type Casting&#xff09;本期小知识 在有限的符号中&#xff0c;我们…

【开放词汇检测】基于MMDetection的MM-Grounding-DINO实战

文章目录 摘要安装基础环境新建虚拟环境安装pytorch安装openmim、mmengine、mmcv安装 MMDetection验证安装配置OV-DINO环境 MMDetection的MM-Grounding-DINO详细介绍测试结果Zero-Shot COCO 结果与模型Zero-Shot LVIS ResultsZero-Shot ODinW&#xff08;野生环境下的目标检测&…

Android视频编辑:利用FFmpeg实现高级功能

在移动设备上进行视频编辑的需求日益增长&#xff0c;用户期望能够在智能手机或平板电脑上轻松地编辑视频&#xff0c;以满足社交媒体分享或个人存档的需求。Android平台因其广泛的用户基础和开放的生态系统&#xff0c;成为视频编辑应用的理想选择。FFmpeg&#xff0c;作为一个…

Centos7安装MySql(特详细)

文章目录 前言一、mysql下载1.打开mysql官网&#xff0c;找到download2.打开MySQL Community(GPL) Downloads3.打开MySql Community Server4.打开Archives5.下载 二、安装1.文件上传2.文件解压3.配置文件4.添加环境变量5.初始化6.启动7.登录并修改密码8.允许远程连接 前言 每次…

【人工智能】OpenAI发布GPT-o1模型:推理能力的革命性突破,这将再次刷新编程领域的格局!

在人工智能领域&#xff0c;推理能力的提升一直是研究者们追求的目标。就在两天前&#xff0c;OpenAI正式发布了其首款具有推理能力的大语言模型——o1。这款模型的推出&#xff0c;不仅标志着AI技术的又一次飞跃&#xff0c;也为开发者和用户提供了全新的工具来解决复杂问题。…

51单片机快速入门之独立按键

51单片机快速入门之独立按键 这里我们需要用上一个仿真软件,只因不想硬件焊接:PROTEUS DESIGN SUITE PROTEUS DESIGN SUITE: PROTEUS DESIGN SUITE是一款由LabCenter Electronics开发的电子设计自动化&#xff08;EDA&#xff09;软件&#xff0c;广泛应用于电气工程和电子工…

debian服务器上搭建git服务及添加文件提交拉取的操作记录、在Ubuntu上搭建Jenkins服务以及Ubuntu中的PPA源及PPA的安装使用

一、debian服务器上搭建git服务及添加文件提交拉取的操作记录 需要新建一个代码仓库&#xff0c;准备找台业务量不大的服务器上找个空间大的文件夹搭建一个。整个过程&#xff1a; 1&#xff0c;在服务器端安装git服务&#xff0c;新建git用户并设置密码&#xff0c;创建仓库&a…

深度学习-神经网络

文章目录 一、基本组成单元&#xff1a;神经元二、神经网络层三、偏置与权重四、激活函数1.激活函数的作用2.常见的激活函数1).Sigmoid2).Tanh函数3).ReLU函数 五、优点与缺点六、总结 神经网络&#xff08;Neural Network, NN&#xff09;是一种模拟人类大脑工作方式的计算模型…

北大阿里:新出炉的LLM偏好对齐方法综述

最近大家都聚集在 Open AI 新的&#x1f353;o1发布和 self-play RL 的共识上。 我想不管是草莓、self-play RL还是数据合成下的new scaling law&#xff0c;也不论这条路是否能够最终走通&#xff0c;仅对于当下以及未来LLM在偏好对齐来说&#xff0c;如文中所述&#xff0c;相…

C语言 | Leetcode C语言题解之第402题移掉K位数字

题目&#xff1a; 题解&#xff1a; char* removeKdigits(char* num, int k) {int n strlen(num), top 0;char* stk malloc(sizeof(char) * (n 1));for (int i 0; i < n; i) {while (top > 0 && stk[top] > num[i] && k) {top--, k--;}stk[top]…

【SSRF漏洞】——http协议常见绕过

改变的确很难&#xff0c;但结果值得冒险 本文如有错误之处&#xff0c;还请各位师傅指正 一.ssrf概述 SSRF全称为Server-side Request Fogery,中文含义服务器端请求伪造 SSRF是一种由攻击者构造形成由目标服务端发起请求的一个安全漏洞。一般情况下&#xff0c;SSRF攻击的目标…

Qt常用控件——QLineEdit

文章目录 QLineEdit核心属性和信号基本示例正则表达式约束验证输入密码是否一致密码显示状态切换 QLineEdit核心属性和信号 QLineEdit用来表示单行输入&#xff0c;可以输入一段文本&#xff0c;但是不能替换 核心属性&#xff1a; 属性说明text输入框中的文本inputMask输入…

Java后端程序员简单操作Linux系统命令

Linux系统概述 Linux 内核最初是由芬兰人林纳斯托瓦兹&#xff08;Linus Torvalds&#xff09;在赫尔辛基大学上 学时而编写的一个开源的操作系统。 Linux&#xff08;管理计算机硬件资源&#xff0c;任务调度&#xff09;支持多用户&#xff0c;支持网络&#xff0c;支持多线…

一次开发,多端部署--实例二

一、视觉风格 1、分层参数 使用了分层参数后&#xff0c;当系统切换深色模式时&#xff0c;字体和背景也可以自适应。 Row() {Column() {Text(分层参数)// 分层参数在sysResource包&#xff0c;属于系统参数&#xff0c;全局可用.fontColor($r(sys_color.ohos_id_color_text_pr…

C语言字符函数与字符串函数

目录 1. 字符函数 1.1 字符分类函数 1.2 字符转换函数 2. 字符串函数 2.1 strlen 函数 2.2 strcpy 函数 2.3 strcat 函数 2.4 strcmp 函数 2.5 strncpy 函数 2.6 strncat 函数 2.7 strncmp 函数 2.8 strstr 函数 结语 1. 字符函数 在C语言标准库中提供了一系列用于…