java常用數據結構
java常用數據結構:數組、鏈表、棧、隊列、二叉樹、紅黑樹、哈希表.......!
數組
數組是相同類型變量的結合,可以通過下標來訪問數組,數組占用連續的內存空間,這樣在檢索時能夠快速地通過偏移來進行下標定位索引數據。數組在初始化之後內存大小將不能被改變。數組分一維數組和二維數組,二維數組其實也是一維數組,是一個一維數組中引用啦另一個一維數組。
鏈表
單向鏈表
單鏈表的存儲原理圖,簡單易懂,head為頭節點,他不存放任何的數據,只是充當一個指向鏈表中真正存放數據的第一個節點的作用,而每個節點中都有一個next引用,指向下一個節點,就這樣一節一節往下面記錄,直到最後一個節點,其中的next指向null。
雙向鏈表
如果我們在表的第一項處插入或者刪除元素該操作花費的時間很短,但是如果我們需要在最後一項插入或者刪除元素這是一個花費時間的操作。
我們可以用雙向鏈表來解決這個問題。雙向鏈表的每一個結點都有一條指向其後繼結點的next鏈和一條指向其前結點的pre鏈。雙向鏈表既可以從第一項開始遍歷也可以從最後一項開始往前遍歷,雙向鏈表可以用上圖表示:
棧
棧是一種只允許在一端進行插入或刪除的線性表,也就是說先進後出。棧的操作端通常被稱為棧頂,另一端被稱為棧底,棧的插入操作稱為壓棧(push),棧刪除操作稱為出棧(pop)。壓棧是把新元素放到棧頂元素的上面,使之成為新的棧頂元素;出棧則是把棧頂元素刪除掉,使其相鄰的元素成為新的棧頂元素。
棧的實現方式主要分為兩種,一種是基於數組實現的,另一種則是基於鏈表。順序存儲的棧稱為順序棧;鏈式存儲的棧稱為鏈式棧。不管是基於何種形式,一般都要實現幾個方法,分別為檢查棧是否為空,是否已滿,壓棧操作和出棧操作,值得說明的是,在鏈式棧中無需檢測棧是否已滿,只要內存足夠大,原理上鏈式棧是不會滿的。
隊列
隊列(queue):一種只允許在一端進行插入,在另一端進行刪除的線性表結構。允許插入的一端叫隊尾(rear),允許刪除的一端叫隊頭(font)。
二叉樹
二叉樹:樹的每個節點最多只能有兩個子節點,如果有兩個以上就不叫二叉樹,被稱為多路樹。
查找節點
查找某個節點,我們必須從根節點開始遍歷。
①、查找值比當前節點值大,則搜索右子樹;
②、查找值等於當前節點值,停止搜索(終止條件);
③、查找值小於當前節點值,則搜索左子樹;
遍歷完整個樹沒找到,返回null
插入節點
要插入節點,必須先找到插入的位置。與查找操作相似,由於二叉搜索樹的特殊性,待插入的節點也需要從根節點開
始進行比較,小於根節點則與根節點左子樹比較,反之則與右子樹比較,直到左子樹為空或右子樹為空,則插入到相應為
空的位置,在比較的過程中要註意保存父節點的信息 及 待插入的位置是父節點的左子樹還是右子樹,才能插入到正確的
位置。
遍歷樹
遍歷樹是根據一種特定的順序訪問樹的每一個節點。比較常用的有前序遍歷,中序遍歷和後序遍歷。而二叉搜索樹最常用的
是中序遍歷。
①、中序遍歷:左子樹——》根節點——》右子樹
②、前序遍歷:根節點——》左子樹——》右子樹
③、後序遍歷:左子樹——》右子樹——》根節點
查找最大值和最小值
這沒什麽好說的,要找最小值,先找根的左節點,然後一直找這個左節點的左節點,直到找到沒有左節點的節點,那
麽這個節點就是最小值。同理要找最大值,一直找根節點的右節點,直到沒有右節點,則就是最大值。
刪除節點
刪除節點是二叉搜索樹中最復雜的操作,刪除的節點有三種情況,前兩種比較簡單,但是第三種卻很復雜。
1、該節點是葉節點(沒有子節點)
2、該節點有一個子節點
3、該節點有兩個子節點
①、刪除沒有子節點的節點
要刪除葉節點,只需要改變該節點的父節點引用該節點的值,即將其引用改為 null 即可。要刪除的節點依然存
在,但是它已經不是樹的一部分了,由於Java語言的垃圾回收機制,我們不需要非得把節點本身刪掉,一旦Java意識
到程序不在與該節點有關聯,就會自動把它清理出存儲器。
刪除節點,我們要先找到該節點,並記錄該節點的父節點。在檢查該節點是否有子節點。如果沒有子節點,接著
檢查其是否是根節點,如果是根節點,只需要將其設置為null即可。如果不是根節點,是葉節點,那麽斷開父節點和
其的關系即可。
②、刪除有一個子節點的節點
刪除有一個子節點的節點,我們只需要將其父節點原本指向該節點的引用,改為指向該節點的子節點即可。
③、刪除有兩個子節點的節點
當刪除的節點存在兩個子節點,那麽刪除之後,兩個子節點的位置我們就沒辦法處理了。既然處理不了,我們就
想到一種辦法,用另一個節點來代替被刪除的節點,那麽用哪一個節點來代替呢?
我們知道二叉搜索樹中的節點是按照關鍵字來進行排列的,某個節點的關鍵字次高節點是它的中序遍歷後繼節
點。用後繼節點來代替刪除的節點,顯然該二叉搜索樹還是有序的。(這裏用後繼節點代替,如果該後繼節點自己也
有子節點,我們後面討論。)
那麽如何找到刪除節點的中序後繼節點呢?其實我們稍微分析,這實際上就是要找比刪除節點關鍵值大的節點集
合中最小的一個節點,只有這樣代替刪除節點後才能滿足二叉搜索樹的特性。
後繼節點也就是:比刪除節點大的最小節點。
算法:程序找到刪除節點的右節點,(註意這裏前提是刪除節點存在左右兩個子節點,如果不存在則是刪除情況的前
面兩種),然後轉到該右節點的左子節點,依次順著左子節點找下去,最後一個左子節點即是後繼節點;如果該右節
點沒有左子節點,那麽該右節點便是後繼節點。
需要確定後繼節點沒有子節點,如果後繼節點存在子節點,那麽又要分情況討論了。
①、後繼節點是刪除節點的右子節點
這種情況簡單,只需要將後繼節點表示的子樹移到被刪除節點的位置即可!
②、後繼節點是刪除節點的右子節點的左子節點
④、刪除有必要嗎?
通過上面的刪除分類討論,我們發現刪除其實是挺復雜的,那麽其實我們可以不用真正的刪除該節點,只需要在
Node類中增加一個標識字段isDelete,當該字段為true時,表示該節點已經刪除,反正沒有刪除。那麽我們在做比如
find()等操作的時候,要先判斷isDelete字段是否為true。這樣刪除的節點並不會改變樹的結構。
紅黑樹
特征:
①、節點都有顏色;
②、在插入和刪除的過程中,要遵循保持這些顏色的不同排列規則。
第一個很好理解,在紅-黑樹中,每個節點的顏色或者是黑色或者是紅色的。當然也可以是任意別的兩種顏色,這裏的顏色用於標
記,我們可以在節點類Node中增加一個boolean型變量isRed,以此來表示顏色的信息。
第二點,在插入或者刪除一個節點時,必須要遵守的規則稱為紅-黑規則:
1.每個節點不是紅色就是黑色的;
2.根節點總是黑色的;
3.如果節點是紅色的,則它的子節點必須是黑色的(反之不一定),(也就是從每個葉子到根的所有路徑上不能有兩個連續的紅
色節點);
4.從根節點到葉節點或空子節點的每條路徑,必須包含相同數目的黑色節點(即相同的黑色高度)。
從根節點到葉節點的路徑上的黑色節點的數目稱為黑色高度,規則 4 另一種表示就是從根到葉節點路徑上的黑色高度必須相
同。
註意:新插入的節點顏色總是紅色的,這是因為插入一個紅色節點比插入一個黑色節點違背紅-黑規則的可能性更小,原因是插入
黑色節點總會改變黑色高度(違背規則4),但是插入紅色節點只有一半的機會會違背規則3(因為父節點是黑色的沒事,父
節點是紅色的就違背規則3)。另外違背規則3比違背規則4要更容易修正。當插入一個新的節點時,可能會破壞這種平衡
性,那麽紅-黑樹是如何修正的呢?
紅-黑樹的自我修正
紅-黑樹主要通過三種方式對平衡進行修正,改變節點顏色、左旋和右旋。
①、改變節點顏色
新插入的節點為15,一般新插入顏色都為紅色,那麽我們發現直接插入會違反規則3,改為黑色卻發現違反規則4。這時
候我們將其父節點顏色改為黑色,父節點的兄弟節點顏色也改為黑色。通常其祖父節點50顏色會由黑色變為紅色,但是由
於50是根節點,所以我們這裏不能改變根節點顏色。
②、右旋
首先要說明的是節點本身是不會旋轉的,旋轉改變的是節點之間的關系,選擇一個節點作為旋轉的頂端,如果做一次右
旋,這個頂端節點會向下和向右移動到它右子節點的位置,它的左子節點會上移到它原來的位置。右旋的頂端節點必須要
有左子節點。
③、左旋
左旋的頂端節點必須要有右子節點。
我們改變顏色也是為了幫助我們判斷何時執行什麽旋轉,而旋轉是為了保證樹的平衡。光改變節點顏色是不能起到任何作
用的,旋轉才是關鍵的操作,在新增節點或者刪除節點之後,可能會破壞二叉樹的平衡,那麽何時執行旋轉以及執行什麽
旋轉,這是我們需要重點關註的。
java常用數據結構