讲师中心 微信公众号

工具推荐

视频效率加速
updream

一键生成高质量推广成片

Seko
Seko

AI短剧一键生成成片

立刻MV
立刻MV

低成本歌曲 MV、视频生成

Laper
Laper

剧本策划到成片协作

怎样用指针实现数组的原地旋转 矩阵转置与指针操作结合

雨敏姑娘_7985

雨敏姑娘_7985

发布时间:2025-07-17 09:35:02

|

463人浏览过

|

来源于php中文网

原创

数组原地旋转和矩阵转置的核心在于利用指针直接操作内存实现高效数据重排。1. 数组的原地右旋转采用三次翻转法,通过翻转整个数组、前k个元素、后n-k个元素完成高效旋转,无需额外空间;2. 方阵的原地转置通过指针算术交换对称位置元素实现,避免复制整个矩阵;3. 指针操作虽高效但需警惕野指针、越界访问、空指针解引用等陷阱,必须严格校验参数并规范内存管理;4. 原地操作相比复制显著减少内存开销,提升性能,尤其适用于资源受限环境。这些方法体现了对底层内存布局的深刻理解和高效算法设计的结合。

怎样用指针实现数组的原地旋转 矩阵转置与指针操作结合

数组的原地旋转和矩阵的原地转置,这两个看似不同的操作,骨子里都透露着对内存的直接把控欲。用指针来实现它们,核心就在于不借助额外的存储空间,直接在原数据结构上进行元素的交换与重排。这不仅仅是算法的优雅,更是对计算机底层运作逻辑的一种深刻理解和实践。它意味着我们能以极高的效率,甚至接近硬件极限地去玩转数据。

怎样用指针实现数组的原地旋转 矩阵转置与指针操作结合

解决方案 谈到数组的原地旋转,我脑子里首先浮现的是那个经典的“三次翻转法”。这招真的妙,它把一个看似复杂的整体旋转问题,拆解成了几次简单的局部翻转。你想想看,如果要把数组 [1, 2, 3, 4, 5] 向右旋转2位变成 [4, 5, 1, 2, 3]。我们不必逐个挪动,那样太笨拙了。

怎样用指针实现数组的原地旋转 矩阵转置与指针操作结合

我的做法是这样:

  1. 先把整个数组分成两部分:需要旋转的部分(末尾2个元素)和剩余部分。
  2. 翻转整个数组:[5, 4, 3, 2, 1]。
  3. 翻转前 k 个元素(这里 k 是旋转的位数,2个):[4, 5, 3, 2, 1]。
  4. 翻转剩下的 n-k 个元素:[4, 5, 1, 2, 3]。

整个过程,我们都只在原数组上操作,没有申请新的内存。指针在这里就是我们的“手”,它指向数组中的某个元素,让我们能直接读取或修改那个位置的值。

怎样用指针实现数组的原地旋转 矩阵转置与指针操作结合
#include <stdio.h>

// 辅助函数:翻转指定范围的数组元素
void reverse(int* start, int* end) {
    while (start < end) {
        int temp = *start;
        *start = *end;
        *end = temp;
        start++;
        end--;
    }
}

// 数组原地右旋转
void rotateArray(int arr[], int n, int k) {
    if (n == 0 || k % n == 0) return; // 数组为空或旋转位数是数组长度的倍数,无需操作
    k %= n; // 确保k在有效范围内

    // 指针操作:
    // 1. 翻转整个数组
    reverse(arr, arr + n - 1);
    // 2. 翻转前 k 个元素
    reverse(arr, arr + k - 1);
    // 3. 翻转后 n-k 个元素
    reverse(arr + k, arr + n - 1);
}

/*
// 示例用法,可自行取消注释运行
int main() {
    int myArr[] = {1, 2, 3, 4, 5, 6, 7};
    int n = sizeof(myArr) / sizeof(myArr[0]);
    int k = 3; // 右旋转3位

    printf("原始数组: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", myArr[i]);
    }
    printf("\n");

    rotateArray(myArr, n, k);

    printf("旋转后数组: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", myArr[i]);
    }
    printf("\n");

    return 0;
}
*/

这里 arr 本身就是一个指向数组首元素的指针。arr + n - 1 则是指向数组最后一个元素的指针。start++ 和 end-- 这样的操作,本质上就是指针的移动,让它们指向下一个(或上一个)元素。通过解引用 *start 和 *end,我们直接访问并交换了内存中的值。这种直接而暴力的内存操作,效率自然是没得说。

原地矩阵转置:指针如何优化内存操作? 矩阵转置,尤其是在地转置(in-place transposition),是另一个考验指针功力的地方。对于一个 M x N 的矩阵,如果 M != N,那么严格意义上的“原地”转置几乎是不可能的,因为转置后维度变了,内存布局会完全不同。所以,我们通常讨论的是方阵(N x N 矩阵)的原地转置。

想象一个二维数组 int matrix[N][N]。在内存里,它其实是连续存放的。比如 matrix[0][0], matrix[0][1], ..., matrix[0][N-1], matrix[1][0], ...。要转置,就是把 matrix[i][j] 和 matrix[j][i] 互换。

AI舌诊面诊问诊医疗系统+诊疗商城系统源码
AI舌诊面诊问诊医疗系统+诊疗商城系统源码

AI 舌诊面诊问诊医疗系统 + 诊疗商城系统源码是一套结合 AI 辅助诊断与商品转化的健康类程序,基于浩创云、ThinkPHP(PHP)开发,支持微信服务号与 H5 端,适合做中医舌诊面诊问答、健康建议推送以及配套诊疗商品的运营。

下载

指针在这里的作用是直接定位到这些元素。我们不需要通过 matrix[i][j] 这种形式,而是可以把整个矩阵看作一个一维数组,然后通过指针算术来访问 (i, j) 位置的元素。matrix[i][j] 的地址其实就是 &matrix[0][0] + i * N + j。

#include <stdio.h>

// 辅助函数:交换两个整数的值
void swapInt(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// 方阵原地转置
void transposeMatrix(int* matrix, int N) {
    // 遍历上三角或下三角部分,避免重复交换
    for (int i = 0; i < N; ++i) {
        for (int j = i + 1; j < N; ++j) {
            // 计算 (i, j) 和 (j, i) 在一维内存中的偏移量
            int* ptr1 = matrix + (i * N + j); // 指向 matrix[i][j]
            int* ptr2 = matrix + (j * N + i); // 指向 matrix[j][i]
            swapInt(ptr1, ptr2);
        }
    }
}

/*
// 示例用法,可自行取消注释运行
int main() {
    int N = 3;
    int myMatrix[] = {
        1, 2, 3,
        4, 5, 6,
        7, 8, 9
    }; // 模拟一个3x3矩阵

    printf("原始矩阵:\n");
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            printf("%d ", myMatrix[i * N + j]);
        }
        printf("\n");
    }

    transposeMatrix(myMatrix, N);

    printf("转置后矩阵:\n");
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            printf("%d ", myMatrix[i * N + j]);
        }
        printf("\n");
    }

    return 0;
}
*/

这里 matrix 被当作一个指向 int 的指针,它指向矩阵的第一个元素。matrix + (i * N + j) 这种写法,直接通过指针算术定位到 (i, j) 位置的元素。这种方式绕过了多维数组的语法糖,直接操作底层内存地址,这才是指针的真正威力所在。当然,它也要求你对内存布局有清晰的认知,否则很容易出错。

指针操作在处理复杂数据结构时有哪些常见陷阱? 指针的强大之处在于它能直接触及内存的“灵魂”,但这种力量也伴随着风险。在我看来,指针操作最大的陷阱就是“野指针”和“越界访问”。你声明了一个指针,但忘了初始化,或者它指向的内存已经被释放了,这时它就成了野指针。你用它去读写,结果就是未定义行为,程序可能崩溃,也可能悄无声息地破坏数据。

比如,在上面的矩阵转置代码里,如果 N 的值传错了,或者 matrix 指向的内存区域不够大,matrix + (i * N + j) 就可能跑到程序不该访问的地方。这种错误很难调试,因为它们不一定会立即报错,而是会在某个不确定的时刻爆发。

另一个常见的问题是“空指针解引用”。当你试图通过一个 NULL 指针去访问内存时,程序会立即崩溃。这通常发生在函数参数校验不严格,或者资源分配失败后没有检查返回值的情况下。

理解这些陷阱,并养成良好的编程习惯,比如:

  • 指针声明后立即初始化为 NULL 或有效地址。
  • 每次 malloc 后检查返回值。
  • free 后将指针置为 NULL。
  • 对指针进行算术运算时,务必清楚其边界。

这些都是避免掉进指针“坑”里的关键。

使用指针进行原地操作相比复制有哪些性能优势? 谈到性能,原地操作的优势是显而易见的。最直接的一点就是内存开销。你不需要为新的数据结构分配额外的内存。

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

Flowith
Flowith Hot

Flowith是一款基于画布和智能体工作流的 AI 协作工作空间。

创客贴AI

创客贴AI是一款AI图像与设计工具,AI辅助的智能在线设计工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

SoundView
SoundView Hot

SoundView是一款面向跨境电商的视频翻译、配音和本地化 AI 创作平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

569

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1698

2024.03.01

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

7559

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3585

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

4728

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

3145

2025.08.29

C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

399

2026.04.23

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2921

2023.12.01

Go-Zero API开发使用教程
Go-Zero API开发使用教程

本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

40

2026.11.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn