【算法編程】二叉樹經典題(基礎篇)

二叉樹的遍歷

  二叉樹遍歷分爲三種:前序、中序和後序,爲什麼這麼命名呢?其實是根據節點順序命名的。
在這裏插入圖片描述

如圖爲滿節點,1爲根節點、2爲做節點、3爲右節點,主要是看根結點1的位置,在前面就是前序遍歷、在中間就是中序遍歷、在後面就是後續遍歷。

下面我們通過例子,來看看:

在這裏插入圖片描述

1、前序遍歷

在這裏插入圖片描述

  • 在遍歷節點的左節點的時候,可能左邊節點還有左節點和右節點,要一直遍歷到葉子節點,才能遍歷其右節點
  • 例如在遍歷到節點2時,它的左節點是3,但是節點3不是葉子節點,此時就不能去遍歷節點2的右節點4
  • 雖然節點3沒有左節點,但是有右節點5,它應該在節點2的右節點4的前面
  • 也就是我們在遍歷的時候,要將左邊節點遍歷完才能遍歷右邊節點

2、中序遍歷

在這裏插入圖片描述

3、後序遍歷

在這裏插入圖片描述

一、實現二叉樹的先序、中序、後序遍歷,包括遞歸方式和非遞歸方式

1、遞歸版

package day03;

/**
 * 二叉樹的遍歷(遞歸版)
 * @author Danycym
 *
 */
public class Code01_PreInPosTraversalRecur {
	
	//樹節點
	public static class Node{
		public int value;
		public Node left;
		public Node right;
		
		public Node(int data) {
			this.value = data;
		}
	}
	
	//前序遍歷
	public static void preOrderRecur(Node head) {
		if(head == null) {
			return;
		}
		System.out.print(head.value + " ");
		preOrderRecur(head.left);
		preOrderRecur(head.right);
	}
	
	//中序遍歷
	public static void inOrderRecur(Node head) {
		if(head == null) {
			return;
		}
		inOrderRecur(head.left);
		System.out.print(head.value + " ");
		inOrderRecur(head.right);
	}
	
	//後序遍歷
	public static void posOrderRecur(Node head) {
		if(head == null) {
			return;
		}
		posOrderRecur(head.left);			
		posOrderRecur(head.right);
		System.out.print(head.value + " ");
	}
	
	public static void main(String[] args) {
		Node head = new Node(5);
		head.left = new Node(3);
		head.right = new Node(8);
		head.left.left = new Node(2);
		head.left.right = new Node(4);
		head.left.left.left = new Node(1);
		head.right.left = new Node(7);
		head.right.left.left = new Node(6);
		head.right.right = new Node(10);
		head.right.right.left = new Node(9);
		head.right.right.right = new Node(11);
		
		System.out.print("前序遍歷:");
		preOrderRecur(head);
		System.out.print("\n中序遍歷:");
		inOrderRecur(head);
		System.out.print("\n後序遍歷:");
		posOrderRecur(head);
	}
}

2、非遞歸版圖解

在這裏插入圖片描述

上圖沒執行到最後,後面的按照重複模式執行下去即可

在這裏插入圖片描述

在這裏插入圖片描述

3、Java代碼:

package day03;

import java.util.Stack;

/**
 * 二叉樹遍歷(非遞歸版)
 * @author Danycym
 *
 */
public class Code02_PreInPosTraversalUnRecur {
	public static class Node{
		public int value;
		public Node left;
		public Node right;
		
		public Node(int data) {
			this.value = data;
		}
	}

	//前序遍歷
	public static void preOrderUnRecur(Node head) {
		if(head != null) {
			Stack<Node> stack = new Stack<Node>();
			stack.push(head);
			while(!stack.isEmpty()) {
				head = stack.pop();
				System.out.print(head.value + " ");
				if(head.right != null) {
					stack.push(head.right);
				}
				if(head.left != null) {
					stack.push(head.left);
				}
			}
		}
	}
	
	//中序遍歷
	public static void inOrderUnRecur(Node head) {
		if(head != null) {
			Stack<Node> stack = new Stack<Node>();
			while(!stack.isEmpty() || head != null) {
				if(head != null) {
					stack.push(head);
					head = head.left;
				}else {
					head = stack.pop();
					System.out.print(head.value + " ");
					head = head.right;
				}
			}
		}
	}
	
	//後序遍歷1
	public static void posOrderUnRecur1(Node head) {
		if(head != null) {
			Stack<Node> stack = new Stack<Node>();
			stack.push(head);
			Node c = null;
			while(!stack.isEmpty()) {
				c = stack.peek();
				if(c.left != null && head != c.left && head != c.right) {
					stack.push(c.left);
				}else if(c.right != null && head != c.right) {
					stack.push(c.right);
				}else {
					System.out.print(stack.pop().value + " ");
					head = c;
				}
			}
		}
	}
	
	//後序遍歷2
	public static void posOrderUnRecur2(Node head) {
		if(head != null) {
			Stack<Node> s1 = new Stack<Node>();
			Stack<Node> s2 = new Stack<Node>();
			s1.push(head);
			while(!s1.isEmpty()) {
				head = s1.pop();
				s2.push(head);
				if(head.left != null) {
					s1.push(head.left);
				}
				if(head.right != null) {
					s1.push(head.right);
				}
			}
			
			while(!s2.isEmpty()) {
				System.out.print(s2.pop().value + " ");
			}
		}
	}
	
	
	
	public static void main(String[] args) {
		Node head = new Node(5);
		head.left = new Node(3);
		head.right = new Node(8);
		head.left.left = new Node(2);
		head.left.right = new Node(4);
		head.left.left.left = new Node(1);
		head.right.left = new Node(7);
		head.right.left.left = new Node(6);
		head.right.right = new Node(10);
		head.right.right.left = new Node(9);
		head.right.right.right = new Node(11);
		
		System.out.print("前序遍歷:");
		preOrderUnRecur(head);
		System.out.print("\n中序遍歷:");
		inOrderUnRecur(head);
		System.out.print("\n後序遍歷1:");
		posOrderUnRecur1(head);
		System.out.print("\n後序遍歷2:");
		posOrderUnRecur2(head);

	}

}

二、在二叉樹中找到一個節點的後繼節點

1、題目描述

現在有一種新的二叉樹節點類型如下:

public class Node { 
	public int value; 
	public Node left;
	public Node right; 
	public Node parent;
	
	public Node(int data) { 
		this.value = data; 
	}
}

  該結構比普通二叉樹節點結構多了一個指向父節點的 parent 指針。假設有一 棵 Node 類型的節點組成的二叉樹,樹中每個節點的 parent 指針都正確地指向自己的父節點,頭節點的 parent 指向 null

  只給一個在二叉樹中的某個節點 node,請實現返回 node 的後繼節點的函數。在二叉樹的 中序遍歷 的序列中, node 的下一個節點叫作 node 的後繼節點。

2、圖解

在這裏插入圖片描述

3、Java代碼

package day03;

public class Code03_SuccessorNode {
	public static class Node{
		public int value;
		public Node left;
		public Node right;
		public Node parent;
		
		public Node(int data) {
			this.value = data;
		}
	}
	
	public static Node getSuccessorNode(Node node) {
		if(node == null) {
			return node;
		}
		//有右子樹
		if(node.right != null) {
			return getLeftMost(node.right);  //獲取右子樹最左的節點
		}else {//沒有右子樹
			Node parent = node.parent;  //取父節點
			while(parent != null && parent.left != node) {  //父節點不爲空,求當前節點不是父節點的左節點
				node = parent;  //父節點設置爲當前節點
				parent = node.parent;  //再找父節點的父節點
			}
			return parent;
		}
	}
	
	//獲取右子樹的最左的節點
	public static Node getLeftMost(Node node) {
		if(node == null) {
			return node;
		}
		while(node.left != null) {
			node = node.left;
		}
		return node;
	}

	public static void main(String[] args) {
		Node head = new Node(1);
		head.parent = null;
		head.left = new Node(2);
		head.left.parent = head;
		head.right = new Node(3);
		head.right.parent = head;
		head.left.left = new Node(4);
		head.left.left.parent = head.left;
		head.left.right = new Node(5);
		head.left.right.parent = head.left;
		head.right.left = new Node(6);
		head.right.left.parent = head.right;
		head.right.right = new Node(7);
		head.right.right.parent = head.right;
		head.left.right.left = new Node(8);
		head.left.right.left.parent = head.left.right;
		head.right.right.left = new Node(9);
		head.right.right.left.parent = head.right.right;
		head.right.right.right = new Node(10);
		head.right.right.right.parent = head.right.right;
		
		Node test = head;
		System.out.println(test.value + "  next:  " + getSuccessorNode(test).value);
		test = head.left;
		System.out.println(test.value + "  next:  " + getSuccessorNode(test).value);
		test = head.right;
		System.out.println(test.value + "  next:  " + getSuccessorNode(test).value);
		test = head.left.left;
		System.out.println(test.value + "  next:  " + getSuccessorNode(test).value);
		test = head.left.right;
		System.out.println(test.value + "  next:  " + getSuccessorNode(test).value);
		test = head.right.left;
		System.out.println(test.value + "  next:  " + getSuccessorNode(test).value);
		test = head.right.right;
		System.out.println(test.value + "  next:  " + getSuccessorNode(test).value);
		test = head.left.right.left;
		System.out.println(test.value + "  next:  " + getSuccessorNode(test).value);
		test = head.right.right.left;
		System.out.println(test.value + "  next:  " + getSuccessorNode(test).value);
		test = head.right.right.right;
		System.out.println(test.value + "  next:  " + getSuccessorNode(test));
	}

}

三、二叉樹的序列化和反序列化

1、圖解

在這裏插入圖片描述
在這裏插入圖片描述

2、Java代碼

package day03;

import java.util.LinkedList;
import java.util.Queue;

public class Code04_SerializeAndReconstructTree {
	public static class Node{
		public int value;
		public Node left;
		public Node right;
		
		public Node(int data) {
			this.value = data;
		}
	}
	
	//二叉樹按前序遍歷序列化
	public static String serialByPre(Node head) {
		if(head == null) {
			return "#!";
		}
		String res = head.value + "!";
		res += serialByPre(head.left);
		res += serialByPre(head.right);
		return res;
	}
	//前序遍歷反序列化
	public static Node reconByPreString(String str) {
		String[] values = str.split("!");  //按"!"拆分
		Queue<String> queue = new LinkedList<String>();  //隊列
		for(int i = 0; i != values.length; i++) {
			queue.offer(values[i]);
		}
		return reconPreOrder(queue);
	}
	public static Node reconPreOrder(Queue<String> queue) {
		String value = queue.poll();
		if(value.equals("#")) {
			return null;
		}
		Node head = new Node(Integer.valueOf(value));
		head.left = reconPreOrder(queue);
		head.right = reconPreOrder(queue);
		return head;
	}
	
	
	
	
	//層次遍歷序列化
	public static String serialByLevel(Node head) {
		if(head == null) {
			return "#!";
		}
		String res = head.value + "!";
		Queue<Node> queue = new LinkedList<Node>();
		queue.offer(head);
		while(!queue.isEmpty()) {
			head = queue.poll();
			if(head.left != null) {
				res += head.left.value + "!";
				queue.offer(head.left);
			}else {
				res += "#!";
			}
			
			if(head.right != null) {
				res += head.right.value + "!";
				queue.offer(head.right);
			}else {
				res += "#!";
			}
		}
		return res;
	}
	
	//層次遍歷反序列化
	public static Node reconByLevelString(String str) {
		String[] values = str.split("!");
		int index = 0;
		Node head = generateNodeByString(values[index++]);
		Queue<Node> queue = new LinkedList<Node>();
		if(head != null) {
			queue.offer(head);
		}
		Node node = null;
		while(!queue.isEmpty()) {
			node = queue.poll();
			node.left = generateNodeByString(values[index++]);
			node.right = generateNodeByString(values[index++]);
			if(node.left != null) {
				queue.offer(node.left);
			}
			if(node.right != null) {
				queue.offer(node.right);
			}
		}
		return head;
	}
	

	private static Node generateNodeByString(String val) {
		if(val.equals("#")) {
			return null;
		}
		return new Node(Integer.valueOf(val));
	}

	//打印二叉樹結構
	public static void printTree(Node head) {
		System.out.println("二叉樹:");
		printInOrder(head, 0, "H", 17);
	}

	public static void printInOrder(Node head, int height, String to, int len) {
		if (head == null) {
			return;
		}
		printInOrder(head.right, height + 1, "v", len);
		String val = to + head.value + to;
		int lenM = val.length();
		int lenL = (len - lenM) / 2;
		int lenR = len - lenM - lenL;
		val = getSpace(lenL) + val + getSpace(lenR);
		System.out.println(getSpace(height * len) + val);
		printInOrder(head.left, height + 1, "^", len);
	}

	public static String getSpace(int num) {
		String space = " ";
		StringBuffer buf = new StringBuffer("");
		for (int i = 0; i < num; i++) {
			buf.append(space);
		}
		return buf.toString();
	}

	public static void main(String[] args) {
		Node head = null;
		printTree(head);
		
		String pre = serialByPre(head);
		System.out.println("前序遍歷序列化: " + pre);
		head = reconByPreString(pre);
		System.out.println("前序遍歷反序列化:");
		printTree(head);
		System.out.println("====================================");
		
		head = new Node(1);
		printTree(head);
		
		pre = serialByPre(head);
		System.out.println("前序遍歷序列化: " + pre);
		head = reconByPreString(pre);
		System.out.println("前序遍歷反序列化:");
		printTree(head);
		System.out.println("====================================");
		
		head = new Node(1);
		head.left = new Node(2);
		head.right = new Node(3);
		head.left.left = new Node(4);
		head.right.right = new Node(5);
		printTree(head);
		
		pre = serialByPre(head);
		System.out.println("前序遍歷序列化: " + pre);
		head = reconByPreString(pre);
		System.out.println("前序遍歷反序列化:");
		printTree(head);
		System.out.println("====================================");
		
		head = new Node(1);
		head.left = new Node(2);
		head.left.left = new Node(4);
		head.left.right = new Node(5);
		head.right = new Node(3);
		head.right.left = new Node(6);
		head.right.right = new Node(7);
		printTree(head);
		
		pre = serialByPre(head);
		System.out.println("前序遍歷序列化: " + pre);
		head = reconByPreString(pre);
		System.out.println("前序遍歷反序列化:");
		printTree(head);
		System.out.println("====================================");
		
		
		head = new Node(1);
		head.left = new Node(2);
		head.left.left = new Node(4);
		head.left.right = new Node(5);
		head.right = new Node(3);
		head.right.left = new Node(6);
		head.right.right = new Node(7);
		printTree(head);
		
		pre = serialByLevel(head);
		System.out.println("層次遍歷序列化: " + pre);
		head = reconByLevelString(pre);
		System.out.println("層次遍歷反序列化:");
		printTree(head);
		System.out.println("====================================");	
	}

}

四、摺紙問題

1、題目描述

  請把一段紙條豎着放在桌子上,然後從紙條的下邊向上方對摺1次,壓出摺痕後展開。此時 摺痕是凹下去的,即摺痕突起的方向指向紙條的背面。如果從紙條的下邊向上方連續對摺2 次,壓出摺痕後展開,此時有三條摺痕,從上到下依次是下摺痕、下摺痕和上摺痕。

  給定一 個輸入參數N,代表紙條都從下邊向上方連續對摺N次,請從上到下打印所有摺痕的方向。

例如:

  • N=1時,打印: down
  • N=2時,打印: down down up

2、圖解

在這裏插入圖片描述

程序中,可以通過一個 boolean 類型的變量表示是摺痕的左邊還是右邊

3、Java代碼

package day03;

public class Code05_PaperFolding {

	public static void printAllFolds(int N) {
		printProcess(1, N, true);
	}

	public static void printProcess(int i, int N, boolean down) {
		if (i > N) {
			return;
		}
		printProcess(i + 1, N, true);
		System.out.print(down ? "down " : "up ");
		printProcess(i + 1, N, false);
	}

	public static void main(String[] args) {
		int N = 1;
		printAllFolds(N);
		System.out.println();
		N = 2;
		printAllFolds(N);
		System.out.println();
		N = 3;
		printAllFolds(N);
	}
}

五、判斷一棵二叉樹是否是平衡二叉樹

  • 平衡二叉樹:對於二叉樹中的任意一個節點,它的左子樹和右子樹的高度差不大於1
  • 滿二叉樹一定是平衡二叉樹

1、解題思路

判斷一棵二叉樹是否是平衡二叉樹,就需要判斷每個節點的左子樹和右子樹是否平衡,且左子樹與右子樹高度差

  • 1)左子樹是否平衡
  • 2)右子樹是否平衡
  • 3)左子樹高度
  • 4)右子樹高度

那麼可以通過遞歸的方式實現

2、Java代碼

package day03;

/**
 * 判斷是否爲平衡二叉樹
 * @author Danycym
 *
 */
public class Code06_IsBalanceTree {
	public static class Node{
		public int value;
		public Node left;
		public Node right;
		
		public Node(int data) {
			this.value = data;
		}
	}
	
	//第一種寫法
	//返回結構
	public static class ReturnData{
		public boolean isB;
		public int h;

		public ReturnData(boolean isB, int h){
			this.isB = isB;
			this.h = h;
		}
	}
	//主函數
	public static boolean isB(Node head) {
		return process(head).isB;
	}
	//遞歸函數
	public static ReturnData process(Node head){
		if(head == null){
			return new ReturnData(true, 0);
		}
		ReturnData leftData = process(head.left);
		if(!leftData.isB){
			return new ReturnData(false, 0);
		}
		ReturnData rightData = process(head.right);
		if(!rightData.isB){
			return new ReturnData(false, 0);
		}
		if(Math.abs(leftData.h - rightData.h) > 1){
			return new ReturnData(false, 0);
		}
		return new ReturnData(true, Math.max(leftData.h , rightData.h) + 1);
	}
	
	//第二種寫法
	//主函數
	public static boolean isBalance(Node head) {
		boolean[] res = new boolean[1];
		res[0] = true;
		getHeight(head, 1, res);
		return res[0];
	}
	//求樹高度
	public static int getHeight(Node head, int level, boolean[] res) {
		if (head == null) {
			return level;
		}
		int lH = getHeight(head.left, level + 1, res);
		if (!res[0]) {
			return level;
		}
		int rH = getHeight(head.right, level + 1, res);
		if (!res[0]) {
			return level;
		}
		if (Math.abs(lH - rH) > 1) {
			res[0] = false;
		}
		return Math.max(lH, rH);
	}
	
	public static void main(String[] args) {
		Node head = new Node(1);
		head.left = new Node(2);
		head.right = new Node(3);
		head.left.left = new Node(4);
		head.left.right = new Node(5);
		head.right.left = new Node(6);
		head.right.right = new Node(7);
		
		System.out.println(isB(head));
		System.out.println(isBalance(head));
		
		head = new Node(1);
		head.left = new Node(2);
		head.right = new Node(3);
		head.left.left = new Node(4);
		head.left.right = new Node(5);
		head.left.left.left = new Node(6);
		
		System.out.println(isB(head));
		System.out.println(isBalance(head));

	}
}

六、判斷一棵樹是否是搜索二叉樹

  • 搜索二叉樹:二叉樹中的任意一個節點,它的左子樹都比它小,右子樹都比它大

1、解題思路

  • 我們只需要進行中序遍歷,看中序遍歷是否是從小到大排序的即可

2、Java代碼

package day03;

import java.util.Stack;

public class Code07_IsBST {
	public static class Node{
		public int value;
		public Node left;
		public Node right;
		
		public Node(int data) {
			this.value = data;
		}
	}

	public static boolean isBST(Node head) {
		int pre = Integer.MIN_VALUE;
		if(head != null) {
			Stack<Node> stack = new Stack<Node>();
			while(!stack.isEmpty() || head != null) {
				if(head != null) {
					stack.push(head);
					head = head.left;
				}else {
					head = stack.pop();
					if(head.value < pre) {
						return false;
					}
					pre = head.value;
					head = head.right;
				}
			}
		}
		return true;
	}
	
	//打印二叉樹 
	public static void printTree(Node head) {
		System.out.println("二叉樹爲:");
		printInOrder(head, 0, "H", 17);
		System.out.println();
	}
	public static void printInOrder(Node head, int height, String to, int len) {
		if (head == null) {
			return;
		}
		printInOrder(head.right, height + 1, "v", len);
		String val = to + head.value + to;
		int lenM = val.length();
		int lenL = (len - lenM) / 2;
		int lenR = len - lenM - lenL;
		val = getSpace(lenL) + val + getSpace(lenR);
		System.out.println(getSpace(height * len) + val);
		printInOrder(head.left, height + 1, "^", len);
	}

	public static String getSpace(int num) {
		String space = " ";
		StringBuffer buf = new StringBuffer("");
		for (int i = 0; i < num; i++) {
			buf.append(space);
		}
		return buf.toString();
	}
	public static void main(String[] args) {
		Node head = new Node(4);
		head.left = new Node(2);
		head.right = new Node(6);
		head.left.left = new Node(1);
		head.left.right = new Node(3);
		head.right.left = new Node(5);

		printTree(head);
		System.out.println(isBST(head));

	}
}

七、判斷一棵樹是否是完全二叉樹

  • 完全二叉樹:如果一棵二叉樹深度爲k,則除第k層外其餘所有層的所有節點都有左節點和右節點(即度爲2),且葉子節點從左到右依次存在。

在這裏插入圖片描述

1、解題思路

情況可總結如下:

  • 1)如果一個節點有右孩子,沒有左孩子,肯定不是完全二叉樹
  • 2)如果一個節點有左沒右或者左右都沒有,那麼它後面遍歷到的節點必須是葉節點,否則肯定不是完全二叉樹

在這裏插入圖片描述

按層遍歷

2、Java代碼

package day03;

import java.util.LinkedList;
import java.util.Queue;

public class Code08_IsCBT {
	public static class Node {
		public int value;
		public Node left;
		public Node right;

		public Node(int data) {
			this.value = data;
		}
	}
	public static boolean isCBT(Node head) {
		if (head == null) {
			return true;
		}
		Queue<Node> queue = new LinkedList<Node>();
		boolean leaf = false;
		Node l = null;
		Node r = null;
		queue.offer(head);
		while (!queue.isEmpty()) {
			head = queue.poll();
			l = head.left;
			r = head.right;
			//(leaf && (l != null || r != null)) 葉節點,左孩子或右孩子不爲空,返回false
			//(l == null && r != null) 情況一,左孩子爲空,右孩子不爲空
			if ((leaf && (l != null || r != null)) || (l == null && r != null)) {
				return false;
			}
			if (l != null) {
				queue.offer(l);
			}
			if (r != null) {
				queue.offer(r);
			}else{  //右孩子爲空,開啓葉子節點,也就是後面遍歷到的節點要是葉子節點
				leaf = true;
			}
		}
		return true;
	}

	// for test -- print tree
	public static void printTree(Node head) {
		System.out.println("Binary Tree:");
		printInOrder(head, 0, "H", 17);
		System.out.println();
	}

	public static void printInOrder(Node head, int height, String to, int len) {
		if (head == null) {
			return;
		}
		printInOrder(head.right, height + 1, "v", len);
		String val = to + head.value + to;
		int lenM = val.length();
		int lenL = (len - lenM) / 2;
		int lenR = len - lenM - lenL;
		val = getSpace(lenL) + val + getSpace(lenR);
		System.out.println(getSpace(height * len) + val);
		printInOrder(head.left, height + 1, "^", len);
	}

	public static String getSpace(int num) {
		String space = " ";
		StringBuffer buf = new StringBuffer("");
		for (int i = 0; i < num; i++) {
			buf.append(space);
		}
		return buf.toString();
	}

	public static void main(String[] args) {
		Node head = new Node(4);
		head.left = new Node(2);
		head.right = new Node(6);
		head.left.left = new Node(1);
		head.left.right = new Node(3);
		head.right.left = new Node(5);

		printTree(head);
		System.out.println(isCBT(head));
		
		head = new Node(4);
		head.left = new Node(2);
		head.right = new Node(6);
		head.left.left = new Node(1);
		head.left.right = new Node(3);
		head.right.right = new Node(5);

		printTree(head);
		System.out.println(isCBT(head));

	}
}

八、已知一棵完全二叉樹,求其節點的個數

  • 要求:時間複雜度低於O(N),N爲這棵樹的節點個數
  • 按要求我們就不能直接遍歷二叉樹

1、解題思路

  • 完全二叉樹是由滿二叉樹而引出來的
  • 一棵滿二叉樹,高度爲 LL ,那麼整棵樹的節點個數爲 2L12^L-1
  • 那麼我們就可以:
  • 1)先遍歷完全二叉樹的左邊界,可以記錄完全二叉樹的高度h
  • 2)再遍歷完全二叉樹頭結點的右子樹的左邊界,看它到沒到完全二叉樹的最高高度h,如果達到最高高度h,那麼頭結點的左子樹就是滿節點,爲 2(h1)12^{(h-1)}-1 個,再加上頭結點爲 2(h1)1+12^{(h-1)}-1+1,頭結點的右子樹再進行遞歸
  • 3)如果頭結點的右子樹沒有達到完全二叉樹的最高高度h, 那麼頭結點的右子樹就是滿節點,只是高度右子樹的高度比頭結點的左子樹的高度少1,那麼節點個數爲 2(h2)12^{(h-2)}-1,再加上頭結點爲 2(h2)1+12^{(h-2)}-1+1,頭結點的左子樹再進行遞歸

2、Java代碼

package day03;

public class Code09_CompleteTreeNodeNumber {

	public static class Node {
		public int value;
		public Node left;
		public Node right;

		public Node(int data) {
			this.value = data;
		}
	}

	public static int nodeNum(Node head) {
		if (head == null) {
			return 0;
		}
		return bs(head, 1, mostLeftLevel(head, 1));
	}
	/**
	 * 
	 * @param node  當前節點
	 * @param level  當前節點在第幾層
	 * @param h  樹的高度,固定值
	 * @return  返回節點個數
	 */
	public static int bs(Node node, int level, int h) {
		if (level == h) {
			return 1;
		}
		if (mostLeftLevel(node.right, level + 1) == h) {
			return (1 << (h - level)) + bs(node.right, level + 1, h);
		} else {
			return (1 << (h - level - 1)) + bs(node.left, level + 1, h);
		}
	}
	
	/**
	 * 求二叉樹的高度
	 * @param node  當前節點
	 * @param level  所在層數
	 * @return  返回二叉樹高度
	 */
	public static int mostLeftLevel(Node node, int level) {
		while (node != null) {
			level++;
			node = node.left;
		}
		return level - 1;
	}

	public static void main(String[] args) {
		Node head = new Node(1);
		head.left = new Node(2);
		head.right = new Node(3);
		head.left.left = new Node(4);
		head.left.right = new Node(5);
		head.right.left = new Node(6);
		System.out.println(nodeNum(head));

	}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章