1. 程式人生 > 其它 >matlab-歸拼排序演算法視覺化

matlab-歸拼排序演算法視覺化

matlab-歸拼排序演算法視覺化

  1. 歸拼演算法第一步,實現合拼兩個有序序列
%歸拼排序

% 合併的方法就是分別從兩個有序序列中拿出一個數來進行比較,小的那一個放到新序列中,
% 然後,從這個小的數所屬的序列中拿出一個數來繼續比較
% 注意到這兩個序列是要有序的
%{
歸併排序,利用了合併有序序列的思想,把一個序列分成A,B兩個序列,
如果這兩個序列是有序的,直接合並他們,
但是A,B兩個序列未必是有序的,就拿A序列來說,把A序列再分一次,
分成A1,A2,如果A1,A2有序,直接對他們進行合併,A變有序了,
但是A1,A2未必有序啊,繼續分,直到分出來的序列裡只有一個元素的時候,
一個元素,就是一個有序的序列啊,就可以合併了
這樣一層一層的分組,分到最後,一個組裡只有一個元素,終於符合合併的條件了,
再一層一層的向上合併
%}

%歸拼排序,有兩個需要關鍵點,如何拆分與如何合拼

%matlab 或許可以使用 num2cell()但是會使程式碼遷移性變弱

%實現合拼,可以將程式碼轉為函式形式,便於呼叫

%{
對於兩個任意兩個 有序序列
測試資料
% list_2=[1 5 10 20];
% list_3=[2 4 6 8 10 14 20 20 45];
%}
clear
%測試資料
list_3=[3,3,5,6,9];
list_2=[3,7,8,10,11,13];

n1 = length(list_2);  %兩個序列的長度
n2 = length(list_3);

N=n1+n2;
list_new=zeros(1,N); %預分配空間,優化過程

na=1; %list_2的索引
nb=1; %list_3的索引,或者說是下標
for k=1:N   %這裡其實用while也行,只要注意跳出迴圈就行
    
    %增加判斷,如果其中一個數組的元素已經全部在新陣列中,只對另一個操作
    if na>n1
        list_new(k)=list_3(nb);
        nb=nb+1;
        continue
    end
    %同上
    if nb>n2
        list_new(k)=list_2(na);
        na=na+1;
        continue
    end
    %
    if list_2(na)<list_3(nb)
        list_new(k)=list_2(na);   %將較小值寫入list_new中
        na =na+1;
    else 
        list_new(k)=list_3(nb);
        nb=nb+1;
    end 
    
end

%合拼最後一個數
% if list_2(end)>list_3(end)
%     list_new(end)=list_2(end);
% else
%     list_new(end)=list_3(end);
% end

list_new 

2.合拼兩個有序序列函式

%歸拼,合拼有序陣列
function list_new = list_messagge_sort(my_list,my_list_1)
%判斷,只輸入一個數組 與輸入兩個陣列的操作是不同的
switch nargin
    case 1
        N=length(my_list);
        N_half =round(N/2);
        
        my_list_2=my_list(1:N_half);
        my_list_3=my_list(N_half+1:end);
        n1 = length(my_list_2);  %兩個序列的長度
        n2 = length(my_list_3);
    case 2
        my_list_2=my_list;
        my_list_3=my_list_1;
        n1 = length(my_list_2);  %兩個序列的長度
        n2 = length(my_list_3);   
end

N=n1+n2;
%如果只輸入一個數組,且該輸入的陣列有一個元素,不必要繼續
if N<2
    list_new=my_list_2;
    return
end

list_new=zeros(1,N); %預分配空間,優化過程

na=1; %list_2的索引初值
nb=1; %list_3的索引初值,或者說是下標

%主體程式,迭代中合拼
for k=1:N   %這裡其實用while也行,只要注意跳出迴圈就行
    
    %增加判斷,如果其中一個數組的元素已經全部在新陣列中,只對另一個操作
    if na>n1
        list_new(k)=my_list_3(nb);
        nb=nb+1;
        continue
    end
    %同上
    if nb>n2
        list_new(k)=my_list_2(na);
        na=na+1;
        continue
    end
    %%%%%
    if my_list_2(na)<my_list_3(nb)
        list_new(k)=my_list_2(na);   %將較小值寫入list_new中
        na =na+1;
    else 
        list_new(k)=my_list_3(nb);
        nb=nb+1;
    end 
end

3 .主體

%歸拼排序 呼叫合拼函式
%本程式碼採用迭代方法,也可以用遞迴方法
%合拼在  list_messagge_sort.m函式體中
clear ,close all

list_1=[randperm(30),randperm(20)-20]; %序列(或者說陣列)
N = length(list_1);                    %序列長度

bin_list_length=dec2bin(N);     %將N實現十進位制與二進位制轉化,有大用

tem_len=2;       %第一輪迭代中使用
n= floor(N/2);   %向小取整,如 1.9—— 1,  -3.3—— -4,這裡用其他語言

bar(list_1);     %畫原始資料圖(用其他語言可以忽略,或另尋視覺化方法)
% pause             %暫停,觀察原始資料影象,按空格鍵繼續


%程式主體
%第一輪,進行2的某次方有關的資料排序
while n>0
    for k=1:n
        left_pt=(k-1)*tem_len+1;
        right_pt= k*tem_len;
        
        tem_list=list_messagge_sort(list_1(left_pt:right_pt));
        list_1(left_pt:right_pt)=tem_list;   %這裡可以簡化,tem_list非必要
    end
    n= floor(n/2);   
    tem_len=tem_len*2;  
    
    %畫圖
    drawnow
    pause(.4)  %暫停0.4秒,不然影象變化太快
    bar(list_1)
end
%第一輪的結果與N的二進位制數字相關,如果陣列的長度為2的n次方,
%那麼第二輪其實不用了;但是比較符合2的n次方長度的陣列畢竟是少數,要考慮普適性


nn = length(bin_list_length); %nn為N的二進位制數字的長度,用於迭代
tem_n=nn-1;     %二進位制數字的長度減一,用於迭代中,輔助資料的輸入與更新
L =2^tem_n;     %同上,初始為序列(陣列)中第一個有序序列的長度,也是暫時最大的
%  第二輪,迭代
for ii=2:nn
    
   % 如果陣列的某2的n次方的分組資料為空,跳過
    if bin_list_length(ii)=='0'
        tem_n=tem_n-1;
        continue
    end
    if bin_list_length(ii)=='1'
        tem_n=tem_n-1;
        
        L2=2^tem_n;
        
        tem_list=list_messagge_sort(list_1(1:L), list_1(L+1:L+L2));
        list_1(1:L+L2)=tem_list;    %同理,這裡也可以簡化

        L=L+2^tem_n;
    end
    %繼續畫圖
    drawnow
     pause(.4) %暫停0.4秒,不然影象變化太快,看不清,資料量大時可以不要
    bar(list_1)
end
% list_1