数据结构与算法--代码鲁棒性案例分析
生活随笔
收集整理的這篇文章主要介紹了
数据结构与算法--代码鲁棒性案例分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
代碼魯棒性
- 魯棒是robust的音譯,就是健壯性。指程序能夠判斷輸入是否符合規范,對不合要求的輸入能夠給出合理的結果。
- 容錯性是魯棒的一個重要體現。不魯棒的代碼發生異常的時候,會出現不可預測的異常,或者程序奔潰。
- 由于魯棒性非常重要,因此我們在寫代碼的時候,必須進行防御性編程,這個必須成為我們編程的一種習慣,編碼過程中應該能夠預見可能出現的問題,并適當處理。
最容易出錯的雙指針操作
- 鏈表中倒數第K個節點
- 題目:輸入一個鏈表,輸出鏈表中倒數第k個結點。例如,鏈表依次是1,2,3,4,5,6,倒數第三個就是4。
- 我們依然用之前我們在講解鏈表實現時候的鏈表對象定義
分析
- 此處題目要求的應該是單向鏈表,因為雙向鏈表沒有復雜度可言。為了得到倒數第K個節點,并且不能從尾部遍歷,同樣的案例從尾部到頭打印單向鏈表,我們在之前的文章(數據結構與算法–鏈表實現以及應用)中已經有詳細的分析,此處同樣也可以利用這種方法。
- 以上方法中借助其他數據接口,棧實現,時間復雜度是O(N+k),空間復雜度O(2n)。
- 應該還有更加高效率的算法,我們還是從頭遍歷鏈表,假設有n個節點,那么倒數第k個節點從頭開始數是第n-k+1 個節點
- 如果我們能得到節點個數n大小,那么直接從頭遍歷n-k+1個就得到倒數第k個了 。
- 我們用雙指針實現,利用兩個指針中間步數的差值來得到倒數第k個,比如,我們需要n-k+1的差距,也就是n-(k-1)
- 當指針A 走到末尾的時候,指針B需要走k-1 的距離,那么此時B指針指向的就是倒數第k個
- 例如倒數第2 個,那么B就比A 少走了2-1 = 1 步驟,就是指向倒數第二個了。
- 如下圖:
- 如上圖一中P1走兩步,P2 則指向頭結點
- 接著繼續兩個指針P1, P2,一起向前走,
- 當P1走到鏈表尾,則,P2,正好走到倒數第三位置。
- 如下diam實現:
魯棒性分析
- 雙指針方法中需要注意的點還是挺多的:
- 當我們輸入head 結點為null時候回,由于代碼會范問空指針內存,次數程序會奔潰
- 輸入head為頭肩底的鏈表節點總數少于k個,此時,我們需要先走k-1 步驟,如果正好k-1個節點,那么之后的步驟會拋出NPL,如果少于k-1個節點,則此時就已經npl
- 輸入參數k為0 的時候,此時 k-1= -1,非法數值,-1 二進制位符號位1 此時會讀成數據位,此時數據變為4294967295,此時for循環將會超過執行次數。
相關問題
- 問題一:求單向鏈表中介節點,奇數個返回中間節點,偶數個返回中間兩個任意一個,同樣雙指針A,B, A每個循環走一步,B每個循環走兩步,B到末尾,則A就在中間節點
- 問題二:求解單向鏈表是否環形鏈表,同樣雙指針A,B,A走一步,B走兩步,如果到最后B追上了A 則環形,如果B到最后null,則不是環形
最容易死循環的鏈表問題
- 題目:定義一個函數,輸入鏈表頭結點,反轉并輸出反轉后的鏈表頭結點。
分析
- 我們依然用 之前鏈表的實現文章中定義的鏈表節點如下:
- 鏈表反轉涉及到每個節點的指針操作,非常容易出現死循環問題,為了正確理解整個過程,我們應該首先借助圖形來直觀的分析。如下:
- 我一開始還是想到雙指正方法,第一步驟分別指向錢兩個節點,并且改變本節點的指針指向,我們此時需要知道的是,本節點信息,上一個節點信息,這里都符合,得到下一圖步驟。
- 但是此時我們無法循環到下一個節點3, 因此邏輯無法成立,我們需要借助第三個指針,P3,如下圖
- 如上,我們可以得到本節點信息,上一個節點信息,下一個節點信息,在經過p2 指針的轉向后,我們無法通過P2.next得到下一個節點,因此我們循環時候,需要做如下調整 P2 = P1, P1 = P3, P3=P3.next,然后接著操作P1 節點指針,繼續循環到最后p3.Next為null為止,如下圖最終狀態
-
如上最終狀態,因為我們每次只修改了P1 節點的指針指向,所以循環結束后,還有最后節點沒有處理,我們需要在循環結束后處理。
-
如上分析,我有如下實現:
魯棒性分析
- 在指針操作時候,最容易出現的三個問題:
- 輸入的鏈表頭指針是努力,或者整個鏈表只有一個節點,必須在前三個步驟中判斷
- 反轉后出現環形鏈表,在如上處理過程中,最容易忽略的頭節點指針指向null,導致環形鏈表
- 鏈表斷裂, 最后一個步驟沒有對最后的節點進行指針指向操作,導致最后一個節點處斷裂。
合并兩個排序的鏈表
-
題目:輸入兩個遞增的鏈表,合并這兩個鏈表并使得新的鏈表中節點任然按原有順序有序。如下圖:
-
鏈表一,鏈表而是兩個遞增鏈表,合并兩個鏈表得到鏈表三
-
這個問題我們需要注意的和上一個問題類似,還是鏈表斷裂問題,還有環形鏈表問題,因為需要同時操作兩個鏈表的指針。
-
我們有如下分析:
- 將一二個鏈表看出需要處理的一個組,比較第一個元素,得到小的一個,剔除當成新鏈表的head節點:
- 將一二個鏈表看出需要處理的一個組,比較第一個元素,得到小的一個,剔除當成新鏈表的head節點:
- 將1 節點剔除后,將剩下的鏈表1 ,鏈表2 看成是一個整體,仍然比較第一個節點的大小,繼續如上步驟
- 繼續同樣的邏輯合并剩余的節點,這是典型的遞歸流程,我們可以定義遞歸函數完成合并過程。.
- 如上分析有如下代碼
魯棒性分析
- 首先還是空指針問題,一旦輸入空鏈表立刻npl,因此我們應該對空鏈表單獨處理
更加復雜的指針操作案例樹的子結構
- 題目:輸入兩顆二叉樹A,B,判斷B是不是A樹的子結構。二叉樹的定義我們用之前章節中講解的二叉樹實現原理中定義的樹節點來實現。
-
例如有如下兩棵二叉樹,A中有一部分子樹結構和B是一直的,因此B是A的子結構:
-
依據之前二叉樹實現原理 的分析,樹操作中指針比值鏈表更加復雜,與樹相關的問題我們通常都會用遞歸去解決。
-
如上題中查找A中包含B,可分為兩步:
- 第一步在A樹中查找B的根節點一樣的節點R,如果找到,執行下一步
- 第二步,判斷A中以R為根節點的子樹與B樹的結構是否一致,
-
用如上圖來分析:
- 首先在A中找 8 這個節點,發現A的根節點就是8 ,我們將A以8節點為根節點的樹,與B節點比較
- 將8 的左子樹看成完整的樹,與B中左子樹 比較,還是按第一步驟邏輯 發現不同則不需第三部
- 如果相同則需要,將8 的右子樹看出完整的樹,與B中右子樹比較,還是按第一步驟邏輯。
- 如果以上都不同,則回到第一步,將A的左子樹看出是一個完整的樹與B的根節點比較,
- 依次邏輯遍歷整個A樹,直到找到B一樣結構或者遍歷到葉子節點為止。
-
依據如上分析,我們有如下遞歸實現,其中某些函數是用之前文章 二叉樹實現原理的某些功能:
- 以上考察二叉樹遍歷算法的理解 以及遞歸的能力
- 考察代碼的魯棒性,每個題型都有大量的指針操作,稍不注意就會有npl奔潰。我們應該在程序開始的時候采用防御性編程的方式
- 每次范問指針地址之前都需要考慮這個指針是否有可能是null
上一篇:數據結構與算法–代碼完整性案例分析
下一篇:數據結構與算法–解決問題的方法- 二叉樹的的鏡像
總結
以上是生活随笔為你收集整理的数据结构与算法--代码鲁棒性案例分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小猫钓鱼的故事(整篇) 小猫钓鱼的故事完
- 下一篇: 数据结构与算法--解决问题的方法- 二叉