matlab怎么找出奇数个数_工程优化设计与Matlab实现——十进制编码遗传算法

本文介绍了十进制编码的遗传算法在解决多维问题中的应用,具体阐述了Arithmetic交叉算法和变异算法的实现过程,并在Matlab环境下进行了二维Rastrigin测试函数极小值的求解。然而,遗传算法存在早熟现象,可能导致仅找到局部最优解。通过调整参数和策略,可以缓解这一问题,以提高全局搜索性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

十进制编码的遗传算法,实际上就是直接使用实数来进行交叉和变异计算。

十进制编码遗传算法

由于我们的数据本身就是用十进制表示的,所以十进制编码相当于不编码。

相应的,我们的交叉方法与变异方法也要针对十进制做出相应改变。

以下改变都是在混合遗传算法的基础上作出的。工程优化设计与Matlab实现——混合遗传算法求解多维问题

Part 1 Arith交叉算法

对染色体x1与x2进行交叉操作,方法如下:

d81f3c8b36d9fd729c210805953fc9a0.png

由于在交叉之前已经“洗牌”,所以对相邻两个染色体交叉相当于对任取的两个染色体交叉。

%**********************************************************************%
%*********************相邻两个染色体Arith交叉算法函**********************%
%**********************************************************************%
function X = Cross(n_Population, X, pc)
    if mod(n_Population ,2) == 0
        cross_num = n_Population;        %如果个体数为偶数,参与交叉个体数为全部个体数
    else
        cross_num = n_Population - 1;    %如果个体数为奇数,参与交叉个体数为全部个体数-1,,最后一个不参与交叉
    end
    for i = 1:2:cross_num
        hand_of_god = rand;            %上帝之手随机做选择
        if hand_of_god < pc            %如果上帝手小于交叉概率pc,就进行交叉,否则不交叉
            Cross_Temp_1 = X(:, i);
            Cross_Temp_2 = X(:, i+1);
            r = rand;
            X(:, i) = r * Cross_Temp_1 + (1 - r) * Cross_Temp_2;
            X(:, i+1) = r * Cross_Temp_2 + (1 - r) * Cross_Temp_1;
        end
    end
end

Part 2 变异算法

对染色体x1进行变异操作,方法如下:

3cf5fdc8c49341861370820626e0b711.png

相当于在x1与下界之间任取一个新x1。这就导致如果变异概率过大,导致变异的次数过多,会使所有种群所有个体向下界靠近。

%**********************************************************************%
%****************************变异函数****************************%
%**********************************************************************%
 function X = mutate(n_Population, lb, X, pm)
    for i = 1:n_Population
        hand_of_god = rand;            %上帝之手随机做选择
        if hand_of_god < pm            %如果上帝手小于变异概率pc,就进行变异,否则不变异
            X(:, i) = lb + (X(:, i) - lb) * rand;    %变异
        end
    end
 end

Part 3 一些问题

遗传算法早熟现象十分明显,导致很多时候只找到了局部最优解就结束迭代。

Part 4 栗子

利用十进制混合遗传算法,求2维Rastrigin测试函数的极小值点

目标函数定义:

function f = func(x)
    D = 2;
    f = 0;
    for i = 1 : D
        f = f+(x(i)^2-10*cos(2*pi*x(i)));
    end 
    f = 10 * D + f;

十进制混合遗传算法定义:

%----------求函数极小值----------%
clc;
clear all;
close all;
%----------设置参数----------%
n_Population = 20;    %种群个体数目
ub = [5.12; 5.12];        %给定上界
lb = [-5.12; -5.12];      %给定下界

Chromosome = 2;      %染色体个数
E = 0.0001;          %给定精度要求
pc = 0.8;            %交叉概率
pm = 0.001;            %变异概率
n_loop_max = 500;     %最大迭代次数

%----------一些矩阵说明----------%
X = zeros(Chromosome, n_Population)*nan;               %X为种群染色体矩阵,Chromosome行n_Population列

X_Fitness = zeros(1, n_Population)*nan;               %X_Fitness适应度矩阵,Chromosome行n_Population列
Possibility = zeros(1, n_Population)*nan;             %Possibility累积概率概率矩阵,1行n_Population列

History_X1 = zeros(n_loop_max, n_Population)*nan;      %染色体1矩阵历史记录,最终为n_loop_max+1行n_Population列
History_X2 = zeros(n_loop_max, n_Population)*nan;      %染色体2矩阵历史记录,最终为n_loop_max+1行n_Population列

History_FX = zeros(n_loop_max, n_Population)*nan;      %X为函数值矩阵历史记录,最终为n_loop_max+1行n_Population列
History_X_Fitness = zeros(n_loop_max, n_Population)*nan; %X为适应度矩阵历史记录,最终为n_loop_max行n_Population列

for n_loop = 1:n_loop_max
    if n_loop == 1
        X = X_init(Chromosome, n_Population,lb,ub);           %种群初始化
    end
    
    %将当前种群状态存储进历史记录
    History_X1(n_loop, :) = X(1, :);                     %存储当前染色体1
    History_X2(n_loop, :) = X(2, :);                     %存储当前染色体2
    History_FX(n_loop, :) = GetFunction(n_Population, X);                     %储存当前函数值
    History_X_Fitness(n_loop, :) = GetFitness(n_Population, X);   %储存适应度值
   
    fprintf('第%d次迭代n',n_loop)
    fprintf('初始种群:')
    display(X)

    %洗牌(打乱顺序)
    shuffle = randperm(n_Population);
    for i = 1:Chromosome
        X = X(:,shuffle);
    end
        
    %交叉
    for i = 1:Chromosome
        X = Cross(n_Population, X, pc);
    end
    
    %变异
    for i = 1:Chromosome
        X = mutate(n_Population, lb, X, pm);
    end
    
    %选择
    [X, x_fitness_max] = Select(n_Population, X, E);
    fprintf('选择后的新种群:')
    display(X)
    
    if x_fitness_max <= E          %如果最大的适应度函数小于精度(最大函数值与最小函数值差距特别小)则退出迭代
         break
    end   
end

History_X1(n_loop+1, :) = X(1, :);                     %存储当前染色体1
History_X2(n_loop+1, :) = X(2, :);                     %存储当前染色体2
History_FX(n_loop+1, :) = GetFunction(n_Population, X);                    %储存当前函数值
History_X_Fitness(n_loop+1, :) = GetFitness(n_Population, X);              %储存适应度值

X_Function = GetFunction(n_Population, X);       %计算当前函数值
[min_f, min_x_position] = min(X_Function);       %找出最小函数值
min_x = X(:, min_x_position);                    %找到最小函数值对应的个体

%**********************打印结果**********************%
fprintf('二进制编码混合遗传算法:n')
fprintf('****************参数设置****************n')
fprintf('种群个体数目: %dn', n_Population)
fprintf('给定上界: %f %f     给定下界: %f %fn', ub, lb)
fprintf('精度为:  %fn', E)
fprintf('交叉概率: %fn', pc)
fprintf('变异概率: %fn', pm)
fprintf('最大迭代次数: %dn', n_loop_max)
fprintf('****************迭代结果****************n')
fprintf('共迭代 %d 次n', n_loop)
fprintf('极小值点为: %fn', min_x)
fprintf('极小值为: %fn', min_f)
fprintf('****************************************n')
fprintf('endn')
                                                                          
%**********************************************************************%
%****************************种群X初始化函数****************************%
%**********************************************************************%
function X = X_init(Chromosome, n_Population, lb, ub)
    for n = 1: Chromosome
        for i = 1:n_Population               %随机生成位于上下界内的种群
            X(n, i) = lb(n) + rand * (ub(n) - lb(n));
            if X(n, i) > ub(n)        %如果圆整后超过上界则纠正到上界
                X(n, i) = ub(n);
            elseif X(n, i) < lb(n)    %如果圆整后超过下界则纠正到下界
                X(n, i) = lb(n);
            end
        end
    end
end


%**********************************************************************%
%****************************计算函数值函数****************************%
%**********************************************************************%
function X_Function = GetFunction(n_Population, X)
    for i = 1:n_Population
        X_Function(i) = func(X(:, i));
    end
end

%**********************************************************************%
%****************************计算适应度函数****************************%
%**********************************************************************%
function X_Fitness = GetFitness(n_Population, X)
    X_Function = GetFunction(n_Population, X);         %调用计算函数值函数
    max_x_function = max(X_Function);
    for i = 1:n_Population
        X_Fitness(i) = max_x_function - X_Function(i);
    end
end

%**********************************************************************%
%*********************相邻两个染色体Arith交叉算法函**********************%
%**********************************************************************%
function X = Cross(n_Population, X, pc)
    if mod(n_Population ,2) == 0
        cross_num = n_Population;        %如果个体数为偶数,参与交叉个体数为全部个体数
    else
        cross_num = n_Population - 1;    %如果个体数为奇数,参与交叉个体数为全部个体数-1,,最后一个不参与交叉
    end
    for i = 1:2:cross_num
        hand_of_god = rand;            %上帝之手随机做选择
        if hand_of_god < pc            %如果上帝手小于交叉概率pc,就进行交叉,否则不交叉
            Cross_Temp_1 = X(:, i);
            Cross_Temp_2 = X(:, i+1);
            r = rand;
            X(:, i) = r * Cross_Temp_1 + (1 - r) * Cross_Temp_2;
            X(:, i+1) = r * Cross_Temp_2 + (1 - r) * Cross_Temp_1;
        end
    end
end

%**********************************************************************%
%****************************变异函数****************************%
%**********************************************************************%
 function X = mutate(n_Population, lb, X, pm)
    for i = 1:n_Population
        hand_of_god = rand;            %上帝之手随机做选择
        if hand_of_god < pm            %如果上帝手小于变异概率pc,就进行变异,否则不变异
            X(:, i) = lb + (X(:, i) - lb) * rand;    %变异
        end
    end
 end

%**********************************************************************%
%********************************选择函数********************************%
%**********************************************************************%
function [X, x_fitness_max] = Select(n_Population, X, E)
    X_Function = GetFunction(n_Population, X);              %求当前函数值
    [~, x_best_position] = min(X_Function);                 %最小函数值索引
    x_best = X(:, x_best_position);                         %找到最小函数值对应的个体
    X_Fitness = GetFitness(n_Population, X);                %求当前适应度值
    x_fitness_max = max(X_Fitness);                         %适应度函数值中最大的,即当前种群最大适应度
        if x_fitness_max > E
            fitness_sum = sum(X_Fitness);                          %适应度求和
            Possibility = cumsum(X_Fitness / fitness_sum);         %根据适应度计算,X_Fitness / fitness_Sum是被选择到的概率,Possibility为累积概率
            for i = 1:(n_Population - 1)                           %n_Population选n_Population-1,可重复选(就算全选了一样的也没关系,后面还有变异)
                hand_of_god = rand;                                %“上帝之手”转动轮盘,皮一下好开心
                for ii = 1:n_Population
                    if hand_of_god < Possibility(ii)
                        Temp_X(:,i) = X(:,ii);                     %Temp_X为临时存储选择到的值的矩阵
                        break
                    end
                end
            end
        end
        [~, max_x_position] = max(X_Fitness);                 %找出最大适应度
        Temp_X(:, n_Population) = X(:, max_x_position);
        X = Temp_X;                                           %得到选择后的种群
end

计算结果:

66304c0a437995f20f64f01824a9a49c.png

6674aabeedd23e4b9a20a42d64467417.gif
<think>我们有一个文本文件,其中包含十六进制数。我们的目标是将这个文本文件转换为.dat文件(通常表示二进制数据文件)。 步骤: 1. 读取文本文件,每一行可能是一个十六进制字符串(可能包含空格或其他非十六进制字符,需要清理)。 2. 将每个十六进制字符串转换为对应的字节(即uint8类型)。 3. 将转换后的字节数据写入到一个新的.dat文件中。 注意:文本文件中的十六进制数可能以不同的形式出现,例如可能包含前缀'0x',或者可能用空格分隔,或者每行一个十六进制数。 我们需要根据实际情况处理。假设每行一个十六进制数,且可能是任意长度(但应该是偶数,因为一个字节需要两个十六进制字符)。 如果一行中有多个十六进制数,我们可以考虑拆分,但为了简单,我们先假设每行只有一个十六进制数(或者一行中连续无空格)。 如果文本文件中的一行包含多个十六进制字节(例如两个字符表示一个字节,中间可能有空格),我们可以先去除空格,然后按两个字符分割。 这里我们假设文本文件中的每一行是一个十六进制字符串,可能包含空格,我们需要先移除非十六进制字符(只保留0-9, A-F, a-f),然后按两个字符一组分割。 另一种常见情况:文本文件可能每行有多个字节的十六进制表示,例如: 48 65 6C 6C 6F 或者: 48656C6C6F 因此,我们需要处理两种情况: 1. 每行有多个由空格分隔的十六进制字节(每个两个字符)。 2. 每行是一个连续的十六进制字符串(没有空格)。 我们可以这样处理: 对于每一行,先删除所有非十六进制字符(包括空格),然后检查剩下的字符串长度是否为偶数。如果是,则按每两个字符分割,然后转换为字节。 但是,如果文本文件中混合了这两种情况,我们需要统一处理。所以,我们采用以下方法: 读取每一行,移除非十六进制字符(只保留0-9a-fA-F),然后按每两个字符分割。 具体步骤: 1. 打开文本文件,按行读取。 2. 对每一行,使用正则表达式或字符串操作,移除非十六进制字符(只保留0-9a-fA-F)。 3. 将保留的字符串按每两个字符分组(如果最后剩下一个字符,则可能出错,所以要偶数个)。 4. 将每组两个字符转换为一个字节(uint8)。 5. 将所有字节数据收集起来,写入.dat文件。 注意:如果移除非十六进制字符后,某行字符串长度为奇数,我们可以选择忽略最后一个字符,或者报错。这里我们选择报错。 我们使用MATLAB实现。 代码实现: 1. 读取文本文件:`fopen`和`textscan`(或者`fgetl`逐行读取)。 2. 清理每一行:使用正则表达式`regexp`匹配所有十六进制字符([0-9a-fA-F]),然后合并。 3. 检查清理后的字符串长度是否为偶数,如果不是,报错并跳过该行(或根据需处理)。 4. 将字符串按两个字符分割:`reshape`函数可以很容易做到(先转换为列向量,然后reshape成2列,再按行读取)。 5. 将分割后的每两个字符转换为一个字节:`hex2dec`,注意`hex2dec`要输入是字符串,所以分割后得到的是两个字符组成的字符串。 6. 将转换后的字节数据写入二进制文件:`fwrite`。 示例文本文件内容(hex.txt): 48656C6C6F 576F726C64 或者: 48 65 6C 6C 6F 57 6F 72 6C 64 我们写一个函数,接受输入文本文件名和输出dat文件名。 代码:</think>以下是用 MATLAB 实现将十六进制文本文件转换为二进制 .dat 文件的完整解决方案: ```matlab function hex2bin(inputFile, outputFile) % 读取文本文件内容 fid = fopen(inputFile, 'rt'); hexData = textscan(fid, '%s', 'Delimiter', '', 'Whitespace', ''); fclose(fid); % 提取并合并所有十六进制字符串 hexStr = strjoin(hexData{1}, ''); % 移除所有非十六进制字符(空格、制表符等) cleanHexStr = regexprep(hexStr, '[^0-9a-fA-F]', ''); % 检查长度是否为偶数(每个字节需要两个字符) if mod(length(cleanHexStr), 2) ~= 0 error('十六进制字符串长度不是偶数,无法正确解析字节'); end % 将十六进制字符串转换为字节数组 byteArray = uint8(hex2dec(reshape(cleanHexStr, 2, [])')); % 将字节写入二进制文件 fid = fopen(outputFile, 'wb'); fwrite(fid, byteArray, 'uint8'); fclose(fid); disp(['转换完成!写入 ', num2str(length(byteArray)), ' 字节到 ', outputFile]); end ``` ### 代码解释: 1. **文件读取**: - 使用 `textscan` 读取文本文件内容,忽略所有空白字符分隔符 - `'Delimiter', ''` 确保整行读取,`'Whitespace', ''` 禁用空白处理 2. **数据清洗**: - `regexprep(hexStr, '[^0-9a-fA-F]', '')` 移除所有非十六进制字符 - 保留有效的十六进制字符(0-9, a-f, A-F) 3. **长度验证**: - 检查字符串长度是否为偶数(每个字节由两个十六进制字符组成) - 若长度奇数则报错,防止数据截断 4. **数据转换**: - `reshape(cleanHexStr, 2, [])` 将字符串重组为 2 列矩阵 - `hex2dec` 将每对字符转换为十进制数值 - `uint8` 转换为 8 位无符号整数(字节) 5. **文件写入**: - `'wb'` 模式打开二进制文件进行写入 - `fwrite` 将字节数组按原始二进制格式写入 - 自动处理字节序(小端序) ### 使用示例: ```matlab % 转换 hex_data.txt 为 binary.dat hex2bin('hex_data.txt', 'output.dat'); % 验证生成的文件 fileInfo = dir('output.dat'); disp(['生成文件大小: ' num2str(fileInfo.bytes) ' 字节']); ``` ### 输入文件格式要: 1. 文本文件可包含: - 连续字符串:`48656C6C6F576F726C64` - 空格分隔:`48 65 6C 6C 6F` - 混合格式:`48\n65\t6C 6C6F` 2. 支持大小写十六进制字符(A-F 或 a-f) 3. 忽略所有非十六进制字符(包括空格、制表符、换行符等) ### 输出文件特性: 1. 纯二进制格式(无任何额外头信息) 2. 每个字节对应原始文本中的两个十六进制字符 3. 保持原始字节顺序(大端序排列) ### 测试用例示例: **输入文件 (hex_data.txt)**: ``` 48 65 6C 6C 6F // 空格分隔的"Hello" 576F726C64 // 连续字符串"World" A1 B2 C3 // 带大写字母 ``` **执行转换**: ```matlab hex2bin('hex_data.txt', 'output.dat'); ``` **输出文件 (output.dat)**: ``` 00000000 48 65 6c 6c 6f 57 6f 72 6c 64 a1 b2 c3 |HelloWorld...| ``` ### 注意事项: 1. 如果输入包含奇数个有效十六进制字符,函数会报错 2. 超大文件处理:可逐块读取处理(需修改实现) 3. 特殊字符:`0x` 前缀会被自动过滤(视为无效字符) 4. 内存限制:超大型文件可能需要流式处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值