如何在Erlang中交换矩阵首行第二个元素与末行倒数第二个元素?
Erlang矩阵元素交换实现思路与代码修改
需求回顾
给定N阶方阵(N≥2),实现两种交换逻辑:
- 多进程版本:通过独立进程执行子任务,遍历矩阵行共N次
- 单进程版本:顺序编程,遍历矩阵行共2N次
核心任务:交换首行第二个元素与末行倒数第二个元素,且全程不得使用计数器。
多进程实现(遍历N次)
修改思路
- 主进程拆分首行,提取需要交换的第二个元素
B,保留首行剩余部分 - 启动子进程遍历剩余N-1行(加上主进程处理首行,总遍历次数N),找到末行后拆分出倒数第二个元素
Y - 子进程将
Y发送给主进程,同时把末行的倒数第二个元素替换为B,再将处理后的行列表返回主进程 - 主进程用
Y替换首行的第二个元素,拼接得到新矩阵
修改后的代码
mtr模块
-module(mtr). -export([main1/1, main2/1, swap1/1, swap2/1, mtr_gn1/1]). %% ver.1 多进程版本 main1(N) when N >= 2 -> timer:tc(mtr, swap1, [mtr_gn1(N)]). swap1([[A|R1]|Rs]) when R1 /= [] -> B = hd(R1), RestOfFirstRow = tl(R1), Pid = self(), spawn(mtr1, ch, [Rs, B, Pid]), receive {y, Y} -> Y end, receive {list, L1} -> L1 end, [[A, Y | RestOfFirstRow] | L1]. %% ver.2 单进程版本(后续补充) main2(N) when N >= 2 -> timer:tc(mtr, swap2, [mtr_gn1(N)]). swap2(Matrix) when is_list(Matrix), length(Matrix) >= 2 -> {B, Y} = first_pass(Matrix), second_pass(Matrix, B, Y). % 矩阵生成函数 mtr_gn1(N) -> [lists:map(fun(X) -> X/100 end, lists:seq(1, N)) | [[R || R <- lists:seq(1, N)] || _K <- lists:seq(1, N-1)]].
mtr1模块
-module(mtr1). -export([ch/3]). ch(L, B, Pid) -> Pid ! {list, ch1(L, B, Pid)}. ch1([LastRow], B, Pid) -> {InitOfLastRow, Y, Last} = split_last_two(LastRow), Pid ! {y, Y}, [InitOfLastRow ++ [B, Last]]; ch1([X|L], B, Pid) -> [X|ch1(L, B, Pid)]. % 辅助函数:拆分列表为前置部分、倒数第二个元素、最后一个元素 split_last_two([X, Y]) -> {[], X, Y}; split_last_two([H|T]) -> {Init, SecondLast, Last} = split_last_two(T), {[H|Init], SecondLast, Last}.
单进程实现(遍历2N次)
修改思路
- 第一次遍历所有N行,提取首行第二个元素
B和末行倒数第二个元素Y - 第二次遍历所有N行,将首行第二个元素替换为
Y,末行倒数第二个元素替换为B - 两次遍历总次数为2N,符合题目要求
修改后的代码(补充到mtr模块)
% 第一次遍历:获取交换所需元素 first_pass([[A|R1]|Rs]) -> B = hd(R1), Y = get_last_second(Rs), {B, Y}. get_last_second([LastRow]) -> {_, Y, _} = split_last_two(LastRow), Y; get_last_second([_|Rs]) -> get_last_second(Rs). % 第二次遍历:完成元素交换 second_pass([[A|R1]|Rs], B, Y) -> RestOfFirstRow = tl(R1), ModifiedFirstRow = [A, Y | RestOfFirstRow], ModifiedRs = modify_last_second(Rs, B), [ModifiedFirstRow | ModifiedRs]. modify_last_second([LastRow], B) -> {Init, _, Last} = split_last_two(LastRow), [Init ++ [B, Last]]; modify_last_second([R|Rs], B) -> [R|modify_last_second(Rs, B)]. % 复用拆分辅助函数 split_last_two([X, Y]) -> {[], X, Y}; split_last_two([H|T]) -> {Init, SecondLast, Last} = split_last_two(T), {[H|Init], SecondLast, Last}.
关键说明
- 所有操作均通过列表拆分/拼接实现,未使用任何计数器
- 多进程版本通过子进程处理剩余行,主进程负责首行修改,总遍历次数为N
- 单进程版本通过两次完整遍历矩阵行,总遍历次数为2N,完全符合题目要求
内容的提问来源于stack exchange,提问作者Ted Mosby
相关产品推荐
相关产品推荐

