日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构—树与二叉树

發布時間:2023/12/19 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构—树与二叉树 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

總第119篇

前言

之前談到的線性表、棧和隊列都是一對一的數據結構,但是現實中也存在很多一對多的數據結構,這篇要寫的就是一種一對多的數據結構———樹。全文分為如下幾部分:

  • 樹的一些基本概念

  • 樹的存儲結構

  • 二叉樹

  • 樹與二叉樹相互轉換

  • 樹和森林的遍歷

前文導航:

數據結構—線性表

數據結構-棧和隊列

樹的一些基本概念

樹是n個結點的有限集,n=0時稱為空樹,在任意一顆非空樹中:

  • 有且只有一個特定的稱為根的結點(下圖中的結點A),

  • 當n>1時,其余結點可分為m個互不相交的有限集T1、T2、……、Tm,其中每一個集合本身又是一棵樹,并且稱為根的子樹。

結點:A、B、C、D等都是結點,結點不僅包含數據元素,而且包含指向子樹的分支。比如,結點A不僅包含數據元素A,還包含指向結點B、C、D的指針。

結點的度:結點擁有的子樹個數或者分支的個數。例如,A結點有B、C、D3棵子樹,所以A結點的的度為3。

樹的深度或高度:樹中各結點度的最大值稱為樹的深度。

結點的深度:結點的深度是從根結點到該結點路徑上的結點個數。

結點的高度:從某一結點往下走可能到達的多個葉子結點,對應了多條通往這些葉子節點的路徑,其中最長那條路徑的長度即為該結點在樹中的深度。根節點的高度為樹的高度。
葉子結點:是指結點的度為0的結點,即不指向任何結點的結點。比如結點F、G、M、I、J。

孩子:某一結點指向的結點,比如A結點的孩子就是B、C、D結點。

雙親:與孩子相對應,B、C、D的雙親就是結點A。

兄弟:同一雙親的孩子之間互稱為兄弟。B、C、D結點互稱為兄弟。

堂兄弟:雙親在同一層次的結點互為堂兄弟。G、H、F互為堂兄弟。

祖先:從根結點到具體某節點的路徑上的所有結點,都是這個結點的祖先。結點K的祖先是A、B、E。

子孫:與祖先的概念相對應,以某結點為根的子樹中的所有結點,都是該結點的子孫。結點D的子孫為H、I、J、M。

層次:從根開始,根為第一層,根的孩子為第二層,根的孩子的孩子為第三層,以此類推。

無序樹:如果將樹中結點的各子樹看成是從左至右是有次序的,不能互換的,則稱該樹為有序樹,否則稱為無序樹。

森林:是若干顆互不相交的樹的集合。如果把根節點A去掉,剩下的三棵互不相交樹就是森林。

樹的存儲結構

1.順序存儲結構

樹的順序存儲結構中最簡單直觀的是雙親存儲結構,用一維數組即可實現。雙親結點就是用雙親的信息來存儲數據,比如結點2、3、4的雙親是1,結點5、6、7的雙親是3,結點1是根節點,無雙親,令其等于-1。

2.鏈式存儲結構

樹的鏈式存儲中最常用的兩種結構主要是孩子存儲結構、孩子兄弟存儲結構。

孩子存儲結構就是讓每個結點由一個數據域+若干個指針域組成,指針域的個數等于孩子的個數,讓每個指針指向一個孩子。

孩子兄弟存儲結構是每個結點有兩個指針,一個指針指向該結點的其中一個孩子(長子),另一個指針指向該結點的兄弟。

二叉樹

二叉樹是由n個結點的有限集合,該集合或者為空集,或者由一個根節點和兩顆互不相交的、分別稱為根節點的左子樹和右子樹的二叉樹組成。

二叉樹有如下特征:

  • 每個結點最多只有兩顆子樹,即二叉樹中結點的度最高不能超過2。

  • 子樹的左右順序之分,不能顛倒。

1.特殊二叉樹

滿二叉樹:在一顆二叉樹中,如果所有的分支結點都有左孩子和右孩子結點,并且葉子節點都集中在二叉樹的最下一層,則這樣的二叉樹稱為滿二叉樹。

完全二叉樹:如果對一顆深度為k,有n個結點的二叉樹進行編號后,各結點的編號與深度為k的滿二叉樹中相同位置上的結點的編號均相同,那么這棵二叉樹就是一顆完全二叉樹。
一顆完全二叉樹其實就是由一顆滿二叉樹從右至左從下至上的,挨個刪除結點以后所得到的。

2.二叉樹的存儲結構

2.1順序存儲結構

順序存儲即用一個數組來存儲一顆二叉樹,具體存儲方法為將二叉樹中的結點進行編號,然后按編號依次將結點值存入到一個數組中,即完成了一顆二叉樹的順序存儲。這種存儲結構比較適合存儲完全二叉樹,用于存儲一般的二叉樹會浪費大量的存儲空間。

2.2鏈式存儲結構

順序結構有一定的局限性,不便于存儲任意形態的二叉樹。通過二叉樹的形態,可以發現一個根節點與兩顆子樹有關系,因此設計一個含有一個數據域和兩個指針域的鏈式結點結構,具體如下:

data表示數據域,用于存儲對應的數據元素;lchild和rchild分別表示左指針域和右指針域,分別用于存儲左孩子結點和右孩子結點的位置,如果沒有右孩子結點,則右指針為空。這種存儲結構稱為二叉鏈表存儲結構。定義如下:

typedef?struct?BTNode {char?data;struct?BTNode?*lchild;struct?BTNode?*rchild; }BTNode;

3.二叉樹的遍歷

二叉樹的遍歷分為深度優先遍歷和廣度優先遍歷,深度優先遍歷主要就是先序、中序、后序這三種遍歷方式,而層次遍歷屬于廣度優先遍歷。下面幾種遍歷的前提是樹不為空,如果樹為空,則停止遍歷。

3.1先序遍歷

先訪問根節點,然后遍歷左子樹,最后遍歷右子樹。代碼如下:

void?preorder(BTNode?*p) {if(p?!=?NULL){Visit(p);????//Visit為訪問函數,其中包含了對結點p的各種訪問操作preorder(p?->?lchild);????//遍歷左子樹preorder(p?->?rchild);????//遍歷右子樹} }

3.2中序遍歷

先遍歷左子樹,然后訪問根節點,最后遍歷右子樹。

void?preorder(BTNode?*p) {if(p?!=?NULL){inorder(p?->?lchild);????//遍歷左子樹Visit(p);????//訪問根結點inorder(p?->?rchild);????//遍歷右子樹} }

3.3后序遍歷

先遍歷左子樹,然后遍歷右子樹,最后訪問根結點。

void?preorder(BTNode?*p) {if(p?!=?NULL){posorder(p?->?lchild);????//遍歷左子樹posorder(p?->?rchild);????//遍歷右子樹Visit(p);????//訪問根結點} }

3.4層次遍歷

層次遍歷是將樹分為若干層,然后每一層(互為兄弟的結點為一層)每一層去遍歷。如下圖所示:


具體代碼如下:void?level(BTNode?*p) {int?front,rear;BTNode?*que[maxsize];front?=?rear?=?0;BTNode?*q;if(p?!=?NULL){rear?=?(rear?+?1)%maxsize;que[rear]?=?p;while(front?!=?rear){front?=?(front?+?1)%maxsize;q?=?que[front];Visit(q);if(q?->?lchild?!=?NULL){rear?=?(rear?+1)%maxsize;que[rear]?=?q?->?lchild;}if(q?->?rchild?!=?NULL){rear?=?(rear?+?1)%maxsize;que[rear]?=?q?->?rchild;}}} }

樹和森林與二叉樹的相互轉換

樹的鏈式存儲結構和二叉樹存儲結構的指針域表示的意義不同,在二叉樹鏈式存儲結構中,結點的左指針域指向左孩子,右指針域指向右孩子;而在樹的鏈式存儲中,結點的一個指針用來指向一個孩子,另一個指針用來指向自己的兄弟結點,我們把這種方式稱為孩子兄弟存儲法。

關于樹、森林、二叉樹之間的相互轉化,這篇博客寫的很清晰,很詳細,這里直接引用該博主的文章。
博客地址:https://blog.csdn.net/u011240016/article/details/52823925

1.樹轉化為二叉樹

樹變二叉樹的規則:每個結點的左指針指向它的第一個孩子結點。右指針指向它在樹中的相鄰兄弟結點。也即:左孩子右兄弟。根沒有兄弟,所以轉換以后的樹沒有右子樹。

具體操作:

  • 在兄弟之間連線

  • 對每一個結點,只保持它與第一個子結點(長子)的連線,與其他子結點的連線全部抹去。

  • 以樹根為軸心,順時針旋轉45度。

2.二叉樹轉化為樹

二叉樹轉化為樹這個過程是樹轉化為二叉樹的一個逆過程,具體轉化過程如下:

  • 加線。如果某個結點有左孩子,那么把這個左孩子的右孩子,右孩子的右孩子,一直右下去,全部連接到這個結點。這個對應樹變二叉樹算法中的抹掉與長子以外的結點的連線,現在要找回自己的全部兒子。

  • 去線。刪除樹中所有結點與這些右孩子的連線。找回了自己的兒子,不容許別人還和它們有瓜葛。

  • 層次調整。

3.森林轉化為二叉樹

森林轉化為二叉樹的規則是:

  • 先將每一棵樹化為二叉樹

  • 第一棵樹的根作為轉換后的二叉樹的根

  • 第一棵樹的左子樹作為轉換后的二叉樹的根的左子樹

  • 第二棵樹作為二叉樹的右子樹

  • 第三棵樹作為二叉樹右子樹的右子樹

這里主要運用的點是:轉換為二叉樹后,這個二叉樹沒有右子樹,因此騰出右手可以接一棵新的樹,因此這樣可以連接很多由樹化來的二叉樹。

對照這個算法去想二叉樹變森林,就很容易明白,先砍掉根和它的左子樹作為一個整體,再對剩下的部分同樣操作。

4.二叉樹轉化為森林

轉化規則如下:

  • 遞歸出口:若二叉樹非空,則二叉樹根及其左子樹作為第一棵樹的二叉樹形式。

  • 遞歸:操作二叉樹的右子樹。即拿掉一棵樹后,再對剩下的二叉樹部分進行同樣的操作,直到無右子樹為止。

砍成一堆二叉樹后,還得注意并沒結束,重點不是二叉樹,而是樹,因此用上面的二叉樹化樹的算法化成森林。

樹和森林的遍歷

1.樹的遍歷

樹的遍歷有兩種方式:先序遍歷和后序遍歷。

先序遍歷是先訪問根結點,再依次訪問根結點的每棵子樹,訪問子樹時仍然遵循先根結點再子樹的原則。

后序遍歷是先依次訪問根結點的每顆子樹,再訪問根結點,訪問子樹時仍然遵循先子樹再根的規則。

2.森林的遍歷

森林的遍歷方式也有兩種,一種是先序遍歷、一種是后序遍歷。

先序遍歷的過程:先訪問森林中第一顆樹的根結點,然后先序遍歷第一顆樹中根結點的子樹,最后先序遍歷森林中除第一顆樹以外的其他樹。

后續遍歷的過程:先后序遍歷第一顆樹中根結點的子樹,然后訪問第一顆樹的根結點,最后后序遍歷森林中除去第一顆樹以外的森林。

總結

以上是生活随笔為你收集整理的数据结构—树与二叉树的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。