- 二叉树概念
二叉树:是每个结点最多有两个子树的有序树,在使用二叉树的时候,数据并不是随便插入到节点中的,一个节点的左子节点的关键值必须小于此节点,右子节点的关键值必须大于或者是等于此节点,所以又称二叉查找树、二叉排序树、二叉搜索树。
完全二叉树:若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
满二叉树:除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。
- 二叉树的特点
(1)树执行查找、删除、插入的时间复杂度都是O(logN);
(2)遍历二叉树的方法包括前序、中序、后序;
(3)非平衡树指的是根的左右两边的子节点的数量不一致;
(4) 在非空二叉树中,第i层的结点总数不超过 , i>=1;
(5)深度为h的二叉树最多有个结点(h>=1),最少有h个结点;
(6)对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;
这里我们是采用孩子表示法来实现后续操作
二叉树的代码实现:
class Node {
public char val;
public Node left;//左孩子-》左子树
public Node right;//右孩子-》右子树
public Node(char val) {
this.val = val;
}
}
public class BinaryTree {
public Node buildTree() {
Node A = new Node('A');
Node B = new Node('B');
Node C = new Node('C');
Node D = new Node('D');
Node E = new Node('E');
Node F = new Node('F');
Node G = new Node('G');
Node H = new Node('H');
A.left = B;
A.right = C;
B.left = D;
B.right = E;
E.right = H;
C.left = F;
C.right = G;
return A;
}
// 前序遍历 递归来实现
void preOrderTraversal(Node root){
if(root == null) {
return;
}
System.out.print(root.val+" ");
preOrderTraversal(root.left);
preOrderTraversal(root.right);
}
// 中序遍历
void inOrderTraversal(Node root){
if(root == null) {
return;
}
inOrderTraversal(root.left);
System.out.print(root.val+" ");
inOrderTraversal(root.right);
}
// 后序遍历
void postOrderTraversal(Node root){
if(root == null) {
return;
}
postOrderTraversal(root.left);
postOrderTraversal(root.right);
System.out.print(root.val+" ");
}
// 遍历思路-求结点个数 前序遍历
static int size = 0;
void getSize1(Node root){
if(root == null) {
return;
}
size++;
getSize1(root.left);
getSize1(root.right);
}
// 子问题思路-求结点个数
int getSize2(Node root){
if(root == null) {
return 0;
}
return getSize2(root.left)+getSize2(root.right)+1;
}
//遍历思路-求叶子结点个数
static int leafSize = 0;
void getLeafSize1(Node root){
if(root == null) {
return;
}
if(root.left == null && root.right == null) {
leafSize++;
}else {
getLeafSize1(root.left);
getLeafSize1(root.right);
}
}
// 子问题思路-求叶子结点个数
int getLeafSize2(Node root){
if(root == null) {
return 0;
}
if(root.left == null && root.right == null) {
return 1;
}
return getLeafSize2(root.left)+getLeafSize2(root.right);
}
}
//求第K层的节点个数
int getKLevelSize(Node root,int k) {
if(root == null) {
return 0;
}else if(k == 1) {
return 1;
}else {
return getKLevelSize(root.left,k-1)
+getKLevelSize(root.right,k-1);
}
}
// 获取二叉树的高度
int getHeight(Node root) {
if(root == null) {
return 0;
}
int leftHeight = getHeight(root.left);
int rightHeight = getHeight(root.right);
return leftHeight > rightHeight? leftHeight+1 :
rightHeight+1;
}
// 查找 val 所在结点,没有找到返回 null
// 按照 根 -> 左子树 -> 右子树的顺序进行查找 前序遍历的方式
// 一旦找到,立即返回,不需要继续在其他位置查找
Node find(Node root, char val){
if(root == null) {
return null;
}
//1、判断根节点是否是查找的数字val
if(root.val == val) {
return root;
}
//2、左边
// 递归--》左边全部递归完成后-》返回值是否是空
Node left = find(root.left,val);
if(left != null) {
return left;
}
//3、右边
Node right = find(root.right,val);
if(right != null) {
return right;
}
return null;
}
// 层序遍历
void levelOrderTraversal(Node root){
if(root == null) return;
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
//每一次进入这个循环,就相当于是每一层的数据
Node cur = queue.poll();
if(cur != null) {
System.out.print(cur.val + " ");
if (cur.left != null) {
queue.offer(cur.left);
}
if (cur.right != null) {
queue.offer(cur.right);
}
}
}
System.out.println();
}
// 判断一棵树是不是完全二叉树
boolean isCompleteTree(Node root) {
if(root == null) return true;
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
Node cur = queue.poll();
if(cur != null) {
queue.offer(cur.left);
queue.offer(cur.right);
}else {
break;
}
}
//看一下 队列里面是否都是空
while (!queue.isEmpty()) {
Node cur2 = queue.peek();
if(cur2 != null) {
return false;
}else {
queue.poll();
}
}
return true;
}
// 前序遍历
void preOrderTraversalNor(Node root){
if(root == null) return;
Stack<Node> stack = new Stack<>();
Node cur = root;
while (cur != null || !stack.empty()) {
while (cur != null) {
stack.push(cur);
System.out.print(cur.val + " ");
cur = cur.left;
}
Node top = stack.pop();
cur = top.right;
}
System.out.println();
}
// 中序遍历
void inOrderTraversalNor(Node root){
if(root == null) return;
Stack<Node> stack = new Stack<>();
Node cur = root;
while (cur != null || !stack.empty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
Node top = stack.pop();
System.out.print(top.val + " ");
cur = top.right;
}
System.out.println();
}
// 后序遍历
void postOrderTraversalNor(Node root){
if(root == null) return;
Stack<Node> stack = new Stack<>();
Node cur = root;
Node prev = null;
while (cur != null || !stack.empty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
cur = stack.peek();
if (cur.right == null || cur.right == prev) {
System.out.print(cur.val+" ");
stack.pop();
prev = cur;
cur = null;
} else {
cur = cur.right;
}
}
System.out.println();
}
public Node prev = null;
public void ConvertChild(Node pCur) {
if(pCur == null) return;
ConvertChild(pCur.left);
pCur.left = prev;
if(prev != null) {
prev.right = pCur;
}
prev = pCur;
ConvertChild(pCur.right);
}
public Node Convert(Node pRootOfTree) {
if(pRootOfTree == null) return null;
ConvertChild(pRootOfTree);
Node head = pRootOfTree;
while (head.left != null) {
head = head.left;
}
return head;
}