数据结构之顺序表应用与双指针法

元素删除

通过元素移动的方式来模拟删除操作:将指定下标后的所有元素依次向前移动一位,覆盖要删除的元素,从而达到 "删除" 的效果。 

  1. 通过自定义函数实现删除功能,需要传入数组、数组长度的指针(因为要修改长度)和要删除的下标
  2. 先判断下标是否合法(是否在有效范围内)
  3. 核心操作是通过循环将指定下标后的所有元素向前移动一位
  4. 最后将数组长度减 1(实际数组内存未变,但逻辑长度减小)

 

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
typedef int Data;void select(Data arr[], int length, int pos)
{assert(pos >= 0 && pos < length);//检查下标是否合法for (int i = pos; i <length-1; i++){arr[i] = arr[i+1];}length--;//将要删除位置后数据向前挪动一位}int main()
{int arr[10] = { 23,6,7,5,4,6878,4,423,4,3 };int length = sizeof(arr) / sizeof(arr[0]);printf("请输入:");int n = 0;scanf("%d", &n);select(arr, length, n);for (int i = 0; i < 9; i++){printf("%d ", arr[i]);}return 0;
}

移除元素(力扣)

 三个思路

 双指针法

int removeElement(int* nums, int numsSize, int val) {//定义两个变量int dst=0,src=0;while(src<numsSize){if(nums[src]!=val){nums[dst]=nums[src];dst++;}src++;}return dst;
}

src在前面探路,dst负责保存数据

  • src 相当于 “源指针”:负责遍历整个数组,逐个检查元素是否需要保留(nums[src] != val)。
  • dst 相当于 “目标指针”:负责记录需要保留的元素应该存放的位置,只有当 src 指向的元素需要保留时,dst 才会移动(dst++)。

时间复杂度:o(n)   空间复杂度:o(1)

删除有序数组中重复项

 

int removeDuplicates(int* nums, int numsSize) {//创建两个变量int dst=0,src=dst+1;while(src<numsSize){//判断dst和src值if(nums[src]!=nums[dst]&&++dst!=src){nums[dst]=nums[src];}src++;}
return dst+1;
}

 ++dst!=src的用意(自我赋值):

假设数组中存在连续的不重复元素,例如:nums = [1,2,3]

  • 初始状态:dst=0src=1
  • 第一步:nums[src]=2 != nums[dst]=1,满足第一个条件,执行 ++dst(此时 dst=1)。
    此时 dst=1 恰好等于 src=1(因为 src 只比初始 dst 大 1,dst 自增后两者重合)。
    如果没有 ++dst != src 的判断,就会执行 nums[dst] = nums[src],也就是 nums[1] = nums[1]—— 这就是无意义的自我赋值(赋值前后元素没有任何变化)。
  • 当 src 和 dst 相邻(src = dst + 1)且元素不同时,++dst 后两者会指向同一个位置,此时的赋值操作完全多余。++dst != src 正是通过判断两者是否重合,精准避免了这种无意义的操作,让算法更高效、逻辑更严谨。

如何避免无意义自我赋值

1.先判断,在操作,避免无效计算

比如处理字符串拼接

// 不好的写法:无论str是否为空都执行拼接
char* appendStr(char* result, const char* str) {strcat(result, str); // 如果str是空字符串,这是无意义的操作return result;
}// 优化写法:先判断是否需要拼接
char* appendStr(char* result, const char* str) {if (str != NULL && str[0] != '\0') { // 非空字符串才拼接strcat(result, str);}return result;
}

2.指针判空在解引用,避免无效访问

// 不好的写法:可能对NULL指针解引用
void printValue(int* ptr) {printf("%d\n", *ptr); // 如果ptr是NULL,会导致程序崩溃
}// 优化写法:先判空
void printValue(int* ptr) {if (ptr != NULL) { // 指针有效才访问printf("%d\n", *ptr);} else {printf("指针为空\n");}
}

3.避免重复计算,缓存中间结果

// 不好的写法:重复计算同一个值
int calculateSum(int* arr, int size) {int sum = 0;for (int i = 0; i < size; i++) {sum += arr[i] * (arr[i] + 1) / 2; // 每次循环都计算arr[i]的二次项}return sum;
}// 优化写法:缓存中间结果
int calculateSum(int* arr, int size) {int sum = 0;for (int i = 0; i < size; i++) {int val = arr[i]; // 缓存当前值,避免重复读取arr[i]sum += val * (val + 1) / 2;}return sum;
}

4.条件判断顺序优化,减少分支执行

让更可能成立的条件先执行,减少不必要判断

// 假设场景:90%的情况是a==0,10%是b==0
// 不好的写法:先判断低概率条件
if (b == 0) {handleB();
} else if (a == 0) {handleA();
}// 优化写法:先判断高概率条件
if (a == 0) {handleA();
} else if (b == 0) {handleB();
}

5.容器操作前先检查是否为空

// 不好的写法:对空数组执行遍历
void clearArray(int* arr, int size) {for (int i = 0; i < size; i++) { // 如果size==0,循环仍会执行(虽然不进入)arr[i] = 0;}
}// 优化写法:先判断容器是否为空
void clearArray(int* arr, int size) {if (size <= 0 || arr == NULL) { // 空数组直接返回return;}for (int i = 0; i < size; i++) {arr[i] = 0;}
}

6. 避免重复调用耗时函数

对于返回值不变的耗时函数(如获取系统时间、读取配置),避免在循环中重复调用。

// 不好的写法:循环中重复调用耗时函数
void processData(int* data, int size) {for (int i = 0; i < size; i++) {long timestamp = getCurrentTimestamp(); // 假设这是一个耗时函数data[i] += timestamp;}
}// 优化写法:外部调用一次,复用结果
void processData(int* data, int size) {long timestamp = getCurrentTimestamp(); // 只调用一次for (int i = 0; i < size; i++) {data[i] += timestamp;}
}

 合并两个有序数组(力扣)

思路 1:先合并,在排序,(冒泡排序)时间复杂度为o(n^2)

思路  2:空间换时间   创建一个新数组,比大小

思路  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--];}else{nums1[l3--]=nums2[l2--];}}while(l2>=0)//l1先越界,来还未全部放入nums1{nums1[l3--]=nums2[l2--];}
}

最后一步很关键

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

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

相关文章

Python编程基础与实践:Python基础数据类型入门

Python变量与数据类型实践 学习目标 通过本课程的学习&#xff0c;学员可以掌握Python中变量的基本概念&#xff0c;了解并能够使用Python的基本数据类型&#xff0c;包括整型、浮点型、字符串和布尔值。此外&#xff0c;学员还将学习如何在实际编程中声明和使用这些数据类型。…

深入解析C/C++函数变量传递:栈、堆与全局变量的生命周期之旅

资料合集下载链接: ​https://pan.quark.cn/s/472bbdfcd014​ 在编程学习中,函数是构建程序的基石,而理解变量如何在函数之间正确、安全地传递,则是从入门到进阶的关键一步。我们经常会遇到这样的困惑:为什么一个指针在某个函数里工作正常,传递给另一个函数后却变成了“…

Ubuntu18网络连接不上也ping不通网络配置问题排查与解决方法

Ubuntu 18启动以后发现连接不上网络,执行 ip a命令或者ifconfig都显示不了正确的地址(192.168.xxx.xxx)。 刚装好系统是没问题的,打算使用FTP开启ftp服务与windows互传文件,安装了net-tools插件就突然连不上网络了,怀疑是网络配置被修改了。 经过了一段时间折腾终于解决了,…

【计算机网络】Socket网络编程

目录 一、主机字节序列和网络字节序列 二、套接字地址结构 1、IPv4 地址结构 (sockaddr_in) 2、IPv6 地址结构 (sockaddr_in6) 3、通用套接字地址结构 (sockaddr) 4、Unix域套接字地址结构 (sockaddr_un) 5、专用 socket 地址结构 6、套接字地址结构的转换 字符串转二进制地址 …

网页操作自动化解决方案:如何用Browser-Use+CPolar提升企业运营效率

文章目录前言1. 安装Ollama2. Gemma3模型安装与运行3. 虚拟环境准备3.1 安装Python3.2. 安装conda4. 本地部署Brower Use WebUI4.1 创建一个新conda环境4.2 克隆存储库4.3 安装依赖环境4.4 安装浏览器自动化工具4.5 修改配置信息5. 本地运行测试6. 安装内网穿透6.1 配置公网地址…

Pycharm的设置过程

20250802 用于记录pycharm的设置过程 编辑器相关 python语言设置文件注释 在设置的编辑器部分&#xff0c;按照需求设置模板&#xff01; 函数生成注释

GaussDB as的用法

通过使用 SQL&#xff0c;可以为表名称或列名称指定别名&#xff08;Alias&#xff09;。1 别名的作用SQL 别名用于为表或表中的列提供临时名称。 SQL 别名通常用于使列名更具可读性。 SQL 一个别名只存在于查询期间。 提高SQL执行效率与编写SQL代码效率。2 使用别名的场景在下…

Prim算法

一&#xff0c;prim算法逻辑1.理解&#xff1a;克鲁斯卡尔算法关注的是边&#xff0c;普里姆算法关注的是点把图中每个顶点比作孤岛&#xff0c;点亮一座孤岛就可以解锁附近的孤岛每次解锁的点都是离自身最近的点2.普里姆算法流程a.采用邻接矩阵表示&#xff0c;考虑要查找最小…

嵌入式学习之硬件——51单片机 1.0

一、基础知识1.什么是嵌入式&#xff1f;嵌入式以应用为中心&#xff0c;计算机技术为基础&#xff0c;软硬件可裁剪的专用计算机系统&#xff1b;2.嵌入式的应用&#xff1f;消费电子、无人驾驶、储能、新能源........3.嵌入式发展&#xff1f;&#xff08;1&#xff09;第一阶…

51c大模型~合集161

自己的原文哦~ https://blog.51cto.com/whaosoft/14079111 #这家国内公司&#xff0c;在给xx智能技术栈做「通解」 打通机器人智能化的关键&#xff1a;眼脑手。 xx智能&#xff08;Embodied Intelligence&#xff09;是 AI 领域里热度极高的赛道&#xff1a;给大模型…

Linux9 root密码修改

开机按e进入在linux行即quiet后面输入rd.break ctrlx进入内核输入mount -o remount,rw /sysrootchroot /sysrootpasswd root即可修改密码输入touch /.autorelabelexitexit等待即可

提示词增强工程(Prompt Enhancement Engineering)白皮书草稿

提示词增强工程&#xff08;Prompt Enhancement Engineering&#xff09;白皮书草稿 作者&#xff1a; 技术人进化社 Email&#xff1a;2819699195qq.com 日期&#xff1a; 2025年7月30日 1. 引言 随着大型语言模型&#xff08;LLM&#xff09;能力的飞速发展&#xff0c;如何高…

电路元器件

电流单位 电压 电阻单位 电阻的决定式 欧姆定律 交流电和直流电 交流电 串联电路 并联电路 在线模拟器 Circuitjs web 在线电路模拟器 下载

广泛分布于内侧内嗅皮层全层的速度细胞(speed cells)对NLP中的深层语义分析的积极影响和启示

速度细胞&#xff08;Speed Cells&#xff09;作为内侧内嗅皮层&#xff08;MEC&#xff09;的核心神经元&#xff0c;通过编码运动速度信息与网格细胞协同实现动态路径整合。这一神经机制为自然语言处理&#xff08;NLP&#xff09;的深层语义分析提供了以下关键启示和影响&am…

sql中的多表查询

在SQL中&#xff0c;多表查询用于从多个表中组合数据&#xff0c;常见的方法包括 ​连接查询&#xff08;JOIN&#xff09;​​ 和 ​子查询。以下是详细说明和示例&#xff1a;一、连接查询&#xff08;JOIN&#xff09;通过关联字段将多个表的数据合并&#xff0c;分为以下几…

Ruby 面向对象编程深入解析

Ruby 面向对象编程深入解析 引言 Ruby 作为一种动态、解释型、面向对象的语言,自1995年由日本程序员Yukihiro Matsumoto创造以来,凭借其简洁、灵活和强大的面向对象特性,在全球范围内获得了广泛的认可。本文将深入探讨Ruby的面向对象编程(OOP)特性,帮助读者更好地理解和…

Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现围栏羊驼的检测识别(C#代码,UI界面版)

Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现围栏羊驼的检测识别&#xff08;C#代码&#xff0c;UI界面版&#xff09;工业相机使用YoloV8模型实现围栏羊驼的检测识别工业相机通过YoloV8模型实现围栏羊驼的检测识别的技术背景在相机SDK中获取图像转换图像的代码分…

如何利用 rowid 在OceanBase 中处理大表时提效

本文作者&#xff1a;张瑞远&#xff0c;现主要从事电信级IT系统及数据库的规划设计、架构设计、运维实施、运维服务、故障处理、性能优化等工作&#xff0c;曾经从事银行、证券数仓设计、开发、优化类工作&#xff0c;持有Orale OCM,MySQL OCP及国产代表数据库认证。 获得包括…

【从0开始学习Java | 第4篇】类和对象

文章目录&#x1f44f;类和对象的概念什么是类&#xff1f;什么是对象&#xff1f;&#x1f95d;构造方法如何创建一个对象&#xff1f;&#x1f95d;对象内存布局完整应用 - 编写一个类&#xff1a;人&#xff0c;其具备年龄、性别、姓名等基础属性&#xff0c;并实例化一个人…

Synopsys:默认报告精度(report_default_significant_digits变量)

相关阅读 Synopsyshttps://blog.csdn.net/weixin_45791458/category_12812219.html?spm1001.2014.3001.5482 在使用report_timing之类的报告命令时&#xff0c;可以使用-significant_digits选项指定报告的精度&#xff0c;在不使用该选项的情况下&#xff0c;命令使用由repor…