演算法思維:二分思想,捨棄思想,遞迴樹思想
阿新 • • 發佈:2021-10-07
一個歸併排序+遞迴帶來的思考.
前言
- 思想:二分思想,捨棄思想,遞迴樹思想,
- 重點:數軸,樹思想,棧思想,二分,多分思想,master公式
- 一遇遞迴,直接造樹!!
- 遞迴,永遠不要把它當作一個方法,你可以把它當作一個過程樹
先想想遞迴最大值:
-
1.[L,R]上求最大值
- 定:遞迴求最大,數軸,拆分為樹
- 解:
- 1.二分思想,兩個跑肯定比單個跑快--那麼就涉及到中間,中間數的求法最好就是捨棄法
- 2.中間為分界,左邊跑,右邊跑
- 3.呼叫Math函式進行比較
- 思維解:
- 1.多叉樹,2.利用棧後繼遍歷.3.懸而未決壓入棧 4.清晰的就出去 5.高度上壓棧
- 懸而未決(有的孩子(子節點)不知道是多少)
- 棧---
- 1.多叉樹,2.利用棧後繼遍歷.3.懸而未決壓入棧 4.清晰的就出去 5.高度上壓棧
- 規範:只有一個數?直接處理
- 注:Math雖然好用,但只能用於判斷回值.資料的交換,還是需交換方式,
-
2.遞迴的master公式---(重點)
- 定:遞迴的複雜度,遞迴的執行流程
- 解:
- 1.先樹,棧的形式解析整個遞迴 ---發現樹的高度就是遞迴的次數
- 2.master公式的學習
- T(N)=a*(N/b)+O(N^d)
- 主方法 = 次數*子方法+其它 --- 遞迴的主方法和子方法也就名字不一樣
- a指的是呼叫方法次數,b指的是切割問題幾段,,N指的是複雜度
- 3.時間複雜度的計算
- 1.log(b,a)>d--->複雜度O(N^log(b,a))
- 2.log(b,a)
複雜度O(N^d) - 3.log(b,a)==d--->複雜度O(O^d * logN)
-
一般使用遞迴是為了職責分明,遞迴就進棧,彈棧就好了,彈棧是由自己寫的條件控制.有多子遞迴時,那就樹來走
歸併
本質:二分排序,再合併
- 歸併的做法是:左側比較完,右側比較完,再最後左右比較
- 還是兩兩交換,,不管是for迴圈,還是遞迴---兩者都是使用二分思想來變成O(logN),本質是讓兩個數兩兩互動排序
歸併遞迴法
- 我測試了它的遞迴走向
- 發現它的走向是按照(終止條件,方法體控制的),遞迴的本質是都走
- 怎麼走,就是如果裡面是雙子遞迴,那麼它會按樹走,走的時候,是先左大節點,再左大節點的左子節點,再左大節點的右子節點.(往復進行),中途走到終止條件跳出,
其它繼續執行,,遇到很小的滿足要求方法體的也會去執行.
- 它的目的就是,整個流程我都整出來並且壓入棧,執行完的或者遇到條件的就出去,按照你的控制停止,你有條件,滿足就執行.
必須明白的遞迴彈棧
-
開始,進棧[0,7],遇到子,再進棧[0,3],遇到子,再進棧[0,1],再遇到再進,直到遇到該停止的,再不斷的彈,彈出這一步,走下一步,下一步再彈,再...
-
簡單沒有彈,只是順序執行的流程
這是一個,沒有終止彈棧的流程 原資料:11,8,9,4,12,3,7,6 遞迴流程:0--1 方法執行:8 11 遞迴流程:2--3 方法執行:4 9 遞迴流程:0--3 方法執行:4 8 9 11 遞迴流程:4--5 方法執行:3 12 遞迴流程:6--7 方法執行:6 7 遞迴流程:4--7 方法執行:3 6 7 12 遞迴流程:0--7 方法執行:3 4 6 7 8 9 11 12 輸出結果:3 4 6 7 8 9 11 12
-
歸併排序程式碼:
public class MergeSortTest { // 解---由大到小解決, // 1.解遞迴 // 0,R都是陣列下標 public void process(int arr[],int L,int R){ if(L==R){ // 結束標誌,也就是葉子節點結束 return; } int m = L+((R-L)>>1); process(arr,L,m); //----L----m-----R-- 不僅僅一個,是樹 process(arr,m+1,R); /* System.out.println("遞迴流程"+":"+L + "--" + R);*/ merge(arr,L,m,R); } // 2.解排序--按照最基本的葉子進行計算,滿足最基本的LMR的葉子進行思考,如 529 public void merge(int arr[],int L,int M,int R){ // 定:要使得兩邊有序 --- // 解:最基本的葉子,529--- // 需求:指標,[L,M]邊的,[M,R]邊的 int p1 = L; int p2 = M+1; // 輔助陣列存值 int help[] = new int[R-L+1]; int i = 0; // 輔助的指標 // 節點卡標 while (p1 <= M && p2 <= R){ // 有一個指標滿足就停止 help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++]; // 此時必定會將一邊的全打進去 } while (p1 <= M){ help[i++] = arr[p1++]; } while (p2 <= R){ help[i++] = arr[p2++]; } for (int j = 0; j < help.length; j++) { arr[L+j] = help[j]; } /* // merge方法體流程! System.out.print("方法執行:"); for (int i1 : help) { System.out.print(i1+" "); } System.out.println(); */ } public static void main(String[] args) { MergeSortTest mergeSortTest = new MergeSortTest(); int arr[] = new int[]{11,8,9,4,12,3,7,6}; System.out.println("原資料:"+ "11,8,9,4,12,3,7,6"); mergeSortTest.process(arr,0,arr.length-1); System.out.print("輸出結果:"); for (int i : arr) { System.out.print(i+" "); } } }
本文來自部落格園,作者:{zjz},轉載請註明原文連結:{https://www.cnblogs.com/zjz0818/}