matlab-歸拼排序演算法視覺化
阿新 • • 發佈:2022-03-11
matlab-歸拼排序演算法視覺化
- 歸拼演算法第一步,實現合拼兩個有序序列
%歸拼排序 % 合併的方法就是分別從兩個有序序列中拿出一個數來進行比較,小的那一個放到新序列中, % 然後,從這個小的數所屬的序列中拿出一個數來繼續比較 % 注意到這兩個序列是要有序的 %{ 歸併排序,利用了合併有序序列的思想,把一個序列分成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