資料結構Day12

2021-10-03 23:50:42 字數 3179 閱讀 5510

首先需要明確的是二叉樹和二叉查詢樹的區別

二叉樹就是我們正常所理解的這種樹形結構,每乙個節點都包含乙個項和兩個指向其他節點(稱為子節點)的指標,分為左節點和右節點。

樹的頂部,稱為根;

當乙個節點沒有子節點時,稱為葉節點。

而二叉查詢樹是在二叉樹的基礎上有如下規定:左節點的項在父節點的項前面,右節點的項在父節點的後面。

對於乙個抽象資料型別而言,最主要的可以概括為增查刪改,而這些的前提是判斷是否為空、是否為滿、返回總項數。由於上述前提都相對來說比較簡單,因此在這裡不做過多討論。下面依次來討論一下二叉樹的增查刪改。

新增項時需要注意的邏輯是,

1、二叉查詢樹是否已經滿了

這個問題的判斷相對來說較簡單,只需要判斷這個二叉樹的累計項數是否大於了設定的最大值,在這種條件下,每刪除乙個項都需要將size-1,每新增乙個項都需要將size+1

2、為待新增的項分配記憶體

在這裡呼叫了makenode函式,使用malloc對記憶體進行分配,需要注意的是在分配記憶體的時候要注意防止記憶體溢位。

3、待新增的項應該新增到哪乙個位置

待新增的項需要新增到二叉樹的哪乙個位置由addnode實現。在這裡要注意一點,公共介面函式處理的是使用者所關心的問題,即只需要處理有關項和樹的問題,而隱藏的對於節點等處理與指標相關的實質性業務的函式應在static中實現,例如這裡的addnode函式,在addnode函式中,為了保證模組化設計,在這裡使用toleft和toright兩個函式去判斷應該將這個函式放到**,這個過程一直持續到函式發現乙個空子樹為止,並在此處新增乙個新的節點,因此這裡的**使用遞迴的方式實現,在使用遞迴的時候應該注意對每一種可能出現的情況都做判斷,避免出現死迴圈導致記憶體溢位。在這個程式中,最終判斷的邏輯為待新增位置是否為空,即如果應該向左放下乙個節點,該節點的左節點是否為空,若為空,則表示這個節點已經是這個方向的最後乙個節電了,遞迴結束。

查詢項需要注意的邏輯為

1、遵循模組化的設計理念

對節點的操作放在該檔案中實現,即查詢項的函式應該作為公共函式,而對節點的操作應該認為是adt內的操作。

2、返回值中增加其父節點

為了便於之後刪除項,在刪除項中,需要知道待刪除項的父節點,以便刪除子節點之後更新父節點指向子節點的指標。

3、迴圈判斷

迴圈判斷該節點的項是否和樹中的項相等,依次比較是否需要往左,是否需要往右,當前面兩者都不滿足時,則表示兩個節點相等,此時退出。look.child即為目標項的節點,而look.parent中已經在每一次的比較之後都會更新。如果輪詢完所有的節點之後都沒有發現,則look.child的值會為null,此時退出。而在判斷的時候只需要判斷look.child的值是不是為null,即可以知道這個節點是不是在二叉查詢樹中了。

while

(look.child !=

null)if

(toright

(待查詢項,樹中的當前項)

)else

break

;}

刪除項的邏輯需要注意以下:

1、待刪除的節點沒有子節點

沒有子節點時,只需要把其父節點的指標置為null即可,當然要去判斷待刪除的節點為其父節點的左節點還是右節點。在實際函式中,這種情況與刪除右左節點的情況合併。

2、待刪除的節點有乙個子節點

在這種情況下,需要把被刪除的節點的父節點中的位址更新為被刪除節點子樹的位址。例如,當乙個節點沒有左節點的時候,程式將右節點的位址賦給其父節點的指標,如果該節點也沒有右節點,則指標為null,這就是沒有子節點的情況。

3、待刪除的節點有兩個子節點

這個的刪除邏輯為通過for迴圈找到被刪除節點的左子樹中最右邊的葉節點,將被刪除節點的右子樹連線到這個葉節點上,之後將被刪除的節點的左節點連線套被刪除的節點的父節點上。

4、刪除節點

刪除節點時需要注意的一點是待修改的值本身就是trnode_t *型別,因此要想修改這個指標位址,傳進來的引數應該為trnode_t ** 型別。同時也應該注意模組化的設計理念,將刪除節點和刪除項的函式分開,刪除節點的函式**見下:

static

void

func

(trnode_t *

*ptr)

elseif(

(*ptr)

->left ==

null

)//沒有右節點

else

//當找到退出時,temp即為最右邊的葉節點

temp->right =

(*ptr)

->right;

temp =

*ptr;

*ptr =

(*ptr)

->left;

free

(temp);}

}

5、刪除項

刪除項即是把項和對應的節點關聯,使用前面說到的查詢項的函式(seekitem)。在這裡需要增加幾個判斷,a.判斷找到的項是否有效;b.刪除的節點是否為根節點,若為根節點,則直接將ptree->root傳到刪除節點的函式中,因為這種情況不用更新父節點,但是要更新tree_t結構中根節點的指標,因此傳入的引數是根節點。

在這裡傳入引數的時候需要注意傳入的必須是其父節點中的對應子節點,而不能直接傳入子節點,如果直接傳入子節點的話,會導致父節點不知道其對應的子節點已經被改掉了,因而會產生野指標的情況,即子節點的位址已經被free掉了,而父節點中的子節點仍然儲存著之前的值,會產生野指標的情況。

遍歷項的核心操作為利用遞迴的特性,從左子樹的項到中間的項,到右子樹的項,依次不斷遞迴遍歷,其遍歷過程自己畫乙個二叉查詢樹,之後依次遍歷一遍就可以了。

void

func

(trnode_t * root,

(void)(

*pfunc)

(item_t item)

)}

遍歷項分為前序遍歷、中序遍歷和後序遍歷,當按照左子樹-項-右子樹的順序遍歷即為前序遍歷,按照項-左子樹-右子樹的順序遍歷即為中序遍歷,按照左子樹-右子樹-項的順序即為後序遍歷,其主要差別為遞迴順序的不同。

資料結構 day 12

雙鏈表 問題 實現乙個雙鏈表,雙鏈表初始為空,支援5種操作 1 在最左側插入乙個數 2 在最右側插入乙個數 3 將第k個插入的數刪除 4 在第k個插入的數左側插入乙個數 5 在第k個插入的數右側插入乙個數 現在要對該鍊錶進行m次操作,進行完所有操作後,從左到右輸出整個鍊錶。注意 題目中第k個插入的數...

day12 上下分頁

modelandview.addobject houses pageinfo.getlists pageinfo pageinfo ihouseservice.searchhouseviewbytype currentpage,housetype modelandview.addobject pag...

實習日記 Day12

昨天穿少了,今天穿厚了。即使脫下外套,坐在辦公室的我也覺得好熱啊 今天是糾結的一天呢 1.實習生的小小感傷仍在延續 今天在和外國同事郵件聯絡的時候,無意中發現自己的skype內建備註是unpaid intern,無薪實習生 雖然我每天是有一些薪水的,但這點錢跟正式員工比,其實跟無薪差不多了吧 又想起...