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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++编写算法判断二叉树是否为完全二叉树_[校招-算法题] 二叉树基础算法1

發布時間:2025/3/20 c/c++ 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++编写算法判断二叉树是否为完全二叉树_[校招-算法题] 二叉树基础算法1 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

二叉樹是面試中??嫉臄祿Y構,因為涉及大量指針操作,因此可以考察思維的嚴謹性和靈活性。但是校招中的二叉樹題規律性很強,因此需要總結一下。

各種常見的二叉樹概念

二叉樹:每個結點最多有兩個子樹(左子樹和右子樹)的樹結構。

節點的層次:一個結點的層次直觀上來說就是其所在的行,其中根結點層次為1。

二叉樹的深度:二叉樹的深度指二叉樹的最大葉子結點所在的層。二叉樹的深度求解可用遞歸方式實現,等于max(左子樹深度,右子樹深度)+1。

結點的度:二叉樹結點的度指該結點分支的個數,取值為0、1或2。

結點種類:

  • 根結點:第一層的結點
  • 葉子結點:度為0的結點
  • 分支結點:度不為0的結點
  • 孩子結點:結點的子樹的根稱為該結點的孩子結點
  • 兄弟結點:同一雙親的孩子結點
  • 祖先結點:從根到該結點上所經分支的所有結點
  • 子孫節點:以某結點為根的子樹中任一結點都稱為該結點的子孫節點

建立一棵二叉樹

class Node:"""節點類"""def __init__(self, value=None, left=None, right=None):self.val = valueself.left = leftself.right = rightclass Tree:"""樹類"""def __init__(self):self.root = Node()self.queue = []def add(self, val):"""為樹添加節點"""node = Node(value=val)if self.root.val is None: # 如果樹是空的,則對根節點賦值self.root = nodeself.queue.append(self.root)else:treeNode = self.queue[0] # 此節點的子樹還沒有齊if treeNode.left is None:treeNode.left = nodeself.queue.append(treeNode.left)else:treeNode.right = nodeself.queue.append(treeNode.right)self.queue.pop(0) # 如果該節點存在左右子樹,將此節點丟棄if __name__ == '__main__':vals = range(10) # 生成十個數據作為樹節點tree = Tree() # 新建一個樹對象for val in vals:tree.add(val) # 逐個添加樹的節點

代碼構造的二叉樹

二叉樹的分類

滿二叉樹:除葉結點外每一個結點都有左右子結點并且葉子結點都處在最底層的二叉樹。

完全二叉樹:除最后一層外,其他各層的結點數都達到最大,最后一層的葉子結點都是從左往右依次排布。

二叉排序樹(BST):或者是一棵空樹,或者具有如下性質:(1)若左子樹不為空,則左子樹上所有結點的值均小于它的根結點的值;(2)若右子樹不為空,則右子樹上所有結點的值均大于它的根結點的值;(3)左右子樹也分別為二叉排序樹;(4)沒有值相等的結點。

平衡二叉樹(AVL):一種二叉排序樹,其中每個結點的左子樹和右子樹的高度差至多等于1。要么它是一棵空樹,要么它的左子樹和右子樹都是平衡二叉樹,且左子樹和右子樹的深度之差的絕對值不超過1。

二叉樹的遍歷

二叉樹最重要的是四種遍歷算法:前序遍歷(遞歸和非遞歸)、中序遍歷(遞歸和非遞歸)、后序遍歷(遞歸和非遞歸)和層次遍歷。

前序遍歷(根左右)

先訪問根結點,然后訪問左子樹,再訪問右子樹。

遞歸算法:

def pre_order(root):if root:print(root.val, end=" ")pre_order(root.left)pre_order(root.right)

非遞歸算法:

使用棧來臨時存儲節點:(1)打印根結點數據;(2)把根結點的right入棧,遍歷左子樹;(3)遍歷完左子樹返回時,棧頂元素應為right,出棧,遍歷以該結點為根的子樹

def pre_order_stack(root):p = roots = [] # stackwhile p or s:while p:print(p.val, end=" ")s.append(p.right)p = p.leftif s: # 注意這里是if,不是whilep = s.pop(-1)

中序遍歷(左根右)

遞歸算法:

def in_order(root):if root:in_order(root.left)print(root.val, end=" ")in_order(root.right)

非遞歸算法:

使用棧來存儲臨時節點,(1)先將根節點入棧,遍歷左子樹;(2)遍歷完左子樹返回時,棧頂元素應為根節點,此時出棧,并打印節點數據;(3)再中序遍歷右子樹。

def in_order_stack(root):p = roots = [] # stackwhile p or s:while p:s.append(p)p = p.leftif s:p = s.pop(-1)print(p.val, end=" ")p = p.right

后序遍歷(左右根)

遞歸算法:

def post_order(root):if root:post_order(root.left)post_order(root.right)print(root.val, end=" ")

非遞歸算法:

使用棧來存儲臨時節點,使用哈希表來記錄狀態。

假設root時遍歷樹的根指針,后序遍歷要求在遍歷完左、右子樹后再訪問根,需要判斷根結點的左、右子樹是否均遍歷過。使用標記法,節點入棧時,將該結點存入哈希表,值為0表示遍歷左子樹前的現場保護,值為1表示遍歷右子樹前的現場保護。

首先將root,遍歷左子樹;返回后,修改哈希表中該結點的值為1,遍歷右子樹,最后訪問根節點。

def post_order_stack(root):p = roots = [] # stackd = {}while p or s:while p:s.append(p)d[p] = 0p = p.leftif s:p = s[-1]if d[p] == 1: # 如果該結點的右子樹遍歷過了,則打印該結點的值print(p.val, end=" ")s.pop(-1)p = Noneelse:d[p] = 1p = p.right

層次遍歷

層次遍歷需要使用一個輔助隊列,初始元素是根結點。當隊列不為空時,每次打印隊列最前端結點的值,然后判斷該結點左子結點是否存在,存在就壓入隊列;再判斷該結點右子節點是否存在,存在就壓入隊列。

def level_order(root):if root is None:return Nonemy_queue = [root]node = rootwhile my_queue:node = my_queue.pop(0)print(node.val, end=" ")if node.left:my_queue.append(node.left)if node.right:my_queue.append(node.right)

二叉樹遍歷的應用

分層打印二叉樹

在層次遍歷的基礎上,使用兩個額外的變量分別保存當前層需要打印的結點數和下一層的結點數。

def level_print(root):if root is None:return Nonemy_queue = [root]node = rootto_be_printed = 1next_level = 0while my_queue:node = my_queue.pop(0)if to_be_printed:print(node.val, end=" ")to_be_printed -= 1else:to_be_printed = next_levelnext_level = 0print()print(node.val, end=" ")to_be_printed -= 1if node.left:my_queue.append(node.left)next_level += 1if node.right:my_queue.append(node.right)next_level += 1

之字形打印二叉樹

def level_print2(root):"""之字形打印二叉樹,在分行打印的基礎上添加一個記錄本層順序的值,之前打印的地方換成壓到一個列表"""if root is None:return Nonemy_queue = []node = rootmy_queue.append(node)to_be_printed = 1next_level_num = 0all = [[], ]level_num = 0while my_queue:node = my_queue.pop(0)if to_be_printed > 0:# print(node.elem, end=" ")all[level_num].append(node.val)to_be_printed -= 1else:print()to_be_printed = next_level_numnext_level_num = 0level_num += 1all.append([])all[level_num].append(node.val)to_be_printed -= 1if node.left is not None:my_queue.append(node.left)next_level_num += 1if node.right is not None:my_queue.append(node.right)next_level_num += 1for i in range(len(all)):if i % 2 == 0:for j in all[i]:print(j, end=" ")if i != len(all) - 1:print()else:all[i].reverse()for j in all[i]:print(j, end=" ")if i != len(all) - 1:print()

判斷二叉樹是否為完全二叉樹

算法:

  • 如果為空樹,直接返回True;
  • 采用層次遍歷,使用一個變量leaf(默認為0);
  • 如果當前結點有右孩子,且沒有左孩子,直接返回False;
  • 如果當前結點沒有兩個孩子,那么leaf=1,之后的節點必須都為葉節點,即不能有孩子,否則返回False;
  • 遍歷結束后沒有返回,那么返回True。
  • def is_complete_binary_tree(root):if not root:return Truemy_queue = [root]node = rootleaf = 0while my_queue:node = my_queue.pop(0)if node.left is None and node.right is not None: # 沒有左孩子,但有右孩子return Falseif leaf == 1 and (node.left is not None or node.right is not None): # 不應該有孩子的結點有孩子存在return Falseif leaf == 0 and node.left is not None and node.right is not None:my_queue.append(node.left)my_queue.append(node.right)elif leaf == 0 and node.left is not None and node.right is None:my_queue.append(node.left)leaf = 1elif leaf == 0 and node.left is None and node.right is None:leaf = 1return True

    總結

    以上是生活随笔為你收集整理的c++编写算法判断二叉树是否为完全二叉树_[校招-算法题] 二叉树基础算法1的全部內容,希望文章能夠幫你解決所遇到的問題。

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