二叉树基本知识(总结)
来源:互联网 发布:地板污染知乎 编辑:程序博客网 时间:2024/06/05 19:02
二叉树
在计算机科学中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。
二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2^{i-1}个结点;深度为k的二叉树至多有2^k-1个结点;对任何一棵二叉树T,如果其终端结点数为n_0,度为2的结点数为n_2,则n_0=n_2+1。
一棵深度为k,且有2^k-1个节点称之为满二叉树;深度为k,有n个节点的二叉树,当且仅当其每一个节点都与深度为k的满二叉树中,序号为1至n的节点对应时,称之为完全二叉树。
二叉树是递归定义的,其结点有左右子树之分,逻辑上二叉树有五种基本形态:
(1)空二叉树——如图(a);
(2)只有一个根结点的二叉树——如图(b);
(3)只有左子树——如图(c);
(4)只有右子树——如图(d);
(5)完全二叉树——如图(e)。
注意:尽管二叉树与树有许多相似之处,但二叉树不是树的特殊情形。
类型
(1)完全二叉树——若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
(2)满二叉树——除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。
(3)平衡二叉树——平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。[2]
package FinalBinaryTree;import java.util.ArrayList;import java.util.LinkedList;import java.util.List;import java.util.Stack;public class BinaryTree<E extends Comparable<E>> extends AbstractTree<E> { private TreeNode<E> root = null; private int size = 0; @Override public boolean search(E e) { // TODO Auto-generated method stub TreeNode<E> current = root; while(current != null) { if(e.compareTo(current.item) < 0) { current = current.left; } else if(e.compareTo(current.item) > 0) { current = current.right; } else { return true; } } return false; } @Override public boolean delete(E e) { // TODO Auto-generated method stub TreeNode<E> current = root; while(current != null) { if(e.compareTo(current.item) < 0) { current = current.left; } else if(e.compareTo(current.item) > 0) { current = current.right; } else { break; } } if(current == null) { return false; } if(current.left == null) { if(current.parent == null) { root = current.right; current.right.parent = null; } else { if(e.compareTo(current.parent.item) < 0) { current.parent.left = current.right; if(current.right != null) { //必须要这个判断,否则java.lang.NullPointerException current.right.parent = current.parent.left; } //help GC current.parent = null; current.right = null; current = null; } else { current.parent.right = current.right; if(current.right != null) { //必须要这个判断,否则java.lang.NullPointerException current.right.parent = current.parent.right; } //help GC current.parent = null; current.right = null; current = null; } } } else { TreeNode<E> rm = current.left; while(rm.right != null) { rm = rm.right; } current.item = rm.item; if(rm.parent.right == rm) { rm.parent.right = rm.left; if(rm.left != null) { //必须要这个判断,否则java.lang.NullPointerException rm.left.parent = rm.parent; } //help GC rm.item = null; rm.left = null; rm = null; } else { current.left = rm.left; if(rm.left != null) { //必须要这个判断,否则java.lang.NullPointerException rm.left.parent = current; } //help GC rm.item = null; rm.left = null; rm = null; } } size--; return true; } @Override public boolean insert(E e) { // TODO Auto-generated method stub if(root == null) { root = new TreeNode<E>(e); size++; } else { TreeNode<E> parent = null; TreeNode<E> current = root; while(current != null) { if(e.compareTo(current.item) < 0) { parent = current; current = current.left; } else if(e.compareTo(current.item) > 0) { parent = current; current = current.right; } else { return false; } } if(e.compareTo(parent.item) < 0) { parent.left = new TreeNode<E>(e); parent.left.parent = parent; } else { parent.right = new TreeNode<E>(e); parent.right.parent = parent; } size++; } return true; } @Override public void inorder() { // TODO Auto-generated method stub inorder(root); } private void inorder(TreeNode<E> root) { if(root == null) { return ; } inorder(root.left); System.out.print(root.item + " "); inorder(root.right); } @Override public void nrinorder() { // TODO Auto-generated method stub Stack<TreeNode<E>> stack = new Stack<>(); TreeNode<E> c = root; while(!stack.isEmpty() || c!=null) { while(c != null) { stack.push(c); c = c.left; } c = stack.pop(); System.out.print(c.item + " "); c = c.right; } } @Override public void preorder() { // TODO Auto-generated method stub preorder(root); } private void preorder(TreeNode<E> root) { // TODO Auto-generated method stub if(root == null) { return; } System.out.print(root.item + " "); preorder(root.left); preorder(root.right); } @Override public void nrpreorder() { // TODO Auto-generated method stub TreeNode<E> current = root; Stack<TreeNode<E>> stack = new Stack<>(); while(!stack.isEmpty() || current!=null) { if(current == null) { current = stack.pop(); } System.out.print(current.item + " "); if(current.right != null) { stack.push(current.right); } current = current.left; } } @Override public void postorder() { // TODO Auto-generated method stub postorder(root); } private void postorder(TreeNode<E> root) { if(root == null) { return; } postorder(root.left); postorder(root.right); System.out.print(root.item + " "); } @Override public void nrpostorder() { // TODO Auto-generated method stub TreeNode<E> last = null; TreeNode<E> current = root; Stack<TreeNode<E>> stack = new Stack<>(); while(!stack.isEmpty() || current!=null) { while(current != null) { stack.push(current); current = current.left; } current = stack.peek(); if(current.right==null || current.right==last) { System.out.print(current.item + " "); last = stack.pop(); current = null; } else { current = current.right; } } } @Override public void breadthorder() { // TODO Auto-generated method stub LinkedList<TreeNode<E>> list = new LinkedList<>(); TreeNode<E> current = root; list.add(current); int index = 0; while(index < getSize()) { for(int i=0;i<list.size();i++) { if(list.get(i) != null) { TreeNode<E> temp = list.get(i); System.out.print(temp.item + " "); list.add(i, temp.left); list.add(i+1,temp.right); list.remove(temp); index++; i++; } } } } @Override public int getSize() { // TODO Auto-generated method stub return size; } @Override public void clear() { // TODO Auto-generated method stub clearPreorder(root); size = 0; } private void clearPreorder(TreeNode<E> root) { root.parent = null; root.item = null; clearPreorder(root.left); clearPreorder(root.right); } //获得指定元素的路径,如果二叉树中不存在此元素,则返回null public ArrayList<TreeNode<E>> path(E e) { if(!search(e)) { return null; } ArrayList<TreeNode<E>> list = new ArrayList<>(); TreeNode<E> current = root; while(current != null) { list.add(current); if(e.compareTo(current.item) < 0) { current = current.left; } else if(e.compareTo(current.item) > 0) { current = current.right; } else { break; } } return list; } //返回二叉树的高度 public int height() { int len = 0; ArrayList<TreeNode<E>> list = new ArrayList<>(); TreeNode<E> current = root; list.add(current); int index = 0; while(index < getSize()) { for(int i=0;i<list.size();i++) { if(list.get(i) != null) { TreeNode<E> temp = list.get(i); list.add(i, temp.left); list.add(i+1, temp.right); list.remove(temp); index++; i++; } } len++; } return len; } //如果此二叉树为完全二叉树,则返回true public boolean isFullBinaryTree() { ArrayList<TreeNode<E>> list = new ArrayList<>(); TreeNode<E> current = root; list.add(current); int index = 0; while(index < getSize()) { for(int i=0;i<list.size();i++) { if(list.get(i) != null) { TreeNode<E> temp = list.get(i); list.add(i,temp.left); list.add(i+1,temp.right); list.remove(temp); index++; i++; } else { return false; } } } return true; } //返回根节点 public TreeNode<E> getRoot() { return root; } //返回指定元素的父节点 public TreeNode<E> getParent(E e) { TreeNode<E> current = root; while(current != null) { if(e.compareTo(current.item) < 0) { current = current.left; } else if(e.compareTo(current.item) > 0) { current = current.right; } else { return current.parent; } } return null; } //返回叶子节点的个数 public int getNumberOfLeaves() { return getNumberOfLeaves(root); } private int getNumberOfLeaves(TreeNode<E> root) { if(root == null) { return 0; } else if(root.right==null && root.left==null) { return 1; } else { return getNumberOfLeaves(root.left) + getNumberOfLeaves(root.right); } } //返回非叶子节点的个数 public int getNumberOfNonLeaves() { return getSize()-getNumberOfLeaves(); } static class TreeNode<E extends Comparable<E>> { protected E item; protected TreeNode<E> parent; protected TreeNode<E> left; protected TreeNode<E> right; public TreeNode(E item) { this.item = item; } }void inOrderTraverse(BiTree &T) { //采用二叉链表存储,中续遍历的非递归算法 initStack(S); Node *p = T; while(p || !StackEmpty(s)) { if(p) { //指针进栈,遍历左子数 push(S,p); p = p->leftChild; }else{ //跟指针节点退栈,访问跟节点,遍历右子数 pop(S,p); printf("%d",p->data); p = p->rightChild; } } }
另一种方式
//节点class TreeNode { char data; TreeNode left; TreeNode right; TreeNode(){} TreeNode(char d){ data = d; left = right = null; } void setNode(char data,TreeNode left,TreeNode right) { this.data = data; this.left = left; this.right = right; }}public class TreeTest { static int count = 0; //创建二叉树 static TreeNode createTree(TreeNode root,char[] a,int i) { if(i<a.length) { if(a[i]=='0') { root = null; }else { TreeNode left = new TreeNode(); TreeNode right = new TreeNode(); root.setNode(a[i],createTree(left, a, ++count),createTree(right,a,++count)); } } return root; } public TreeNode construct(String preOrder,String inOrder){ if(preOrder == null || inOrder == null || preOrder.length()!= inOrder.length()) { System.out.println("invalid iuput"); return null; } int len = preOrder.length(); TreeNode root = null; return constructCore(preOrder,inOrder,len,root); }//根据前序、中序重建二叉树 /* public TreeNode constructCore(String preOrder,String inOrder,int len,TreeNode root){ //前序遍历的第一个节点为根节点 TreeNode temp = new TreeNode(); temp.data = preOrder.charAt(0); temp.left = temp.right = null; if(root == null) { root = temp; } //判断只有一个节点的情况 if(len==1) { return root; } //中序遍历中遍历找到根节点,计算子树的长度 int i = 0; while(inOrder.charAt(i) != preOrder.charAt(0)){ i++; if(i > len) { System.out.println("invalid input"); return null; } } int leftLen = i; int rightLen = len - leftLen - 1; //构建二叉树 if(leftLen > 0) { //java是值传递,所以要重传root.left root.left = constructCore(preOrder.substring(1), inOrder, leftLen, root.left); } if(rightLen > 0) { root.right = constructCore(preOrder.substring(leftLen+1), inOrder.substring(leftLen+1), rightLen, root.right); } return root; } */ //根据中序、后续重建二叉树,此解有误,待解决 public TreeNode constructCore(String behindOrder,String inOrder,int len,TreeNode root){ //前序遍历的第一个节点为根节点 TreeNode temp = new TreeNode(); temp.data = behindOrder.charAt(len-1); temp.left = temp.right = null; if(root == null) { root = temp; } //判断只有一个节点的情况 if(len==1) { return root; } //中序遍历中遍历找到根节点,计算子树的长度 int i = 0; while(inOrder.charAt(i) != behindOrder.charAt(len-1)){ i++; if(i > len) { System.out.println("invalid input"); return null; } } int leftLen = i; int rightLen = len - leftLen - 1; //构建二叉树 if(rightLen > 0) { root.right = constructCore(behindOrder.substring(0,len-1), inOrder, len, root.right); } if(leftLen > 0) { //java是值传递,所以要重传root.left root.left = constructCore(behindOrder.substring(0,rightLen+1), inOrder.substring(0,rightLen+1), leftLen, root.left); } return root; } //中序遍历 void inOrder(TreeNode root) { if(root!=null) { inOrder(root.left); System.out.print(root.data); inOrder(root.right); } } //求子树,A中是否存在子树B static boolean hasSubTree(TreeNode root1,TreeNode root2){ boolean isHas = false; if(root1!=null && root2!=null) { if(root1.data == root2.data) { isHas = doesTree1HasTree2(root1,root2); } if(!isHas) { isHas = doesTree1HasTree2(root1.left,root2); } if(!isHas) { isHas = doesTree1HasTree2(root1.right,root2); } } return isHas; } private static boolean doesTree1HasTree2(TreeNode root1, TreeNode root2) { if(root2==null) return true; if(root1==null) return false; //又不想等就返回no if(root1.data!=root2.data){ return false; } return doesTree1HasTree2(root1.left, root2.left) && doesTree1HasTree2(root1.right, root2.right); } //测试 public static void main(String[] args) { // String preOrder = "74258631"; //String preOrder = "12473568"; //String inOrder = "47215386"; TreeTest tt = new TreeTest(); //TreeNode root = tt.construct(preOrder, inOrder); TreeNode root = new TreeNode(); char a[] = {'1','2','3','0','0','4','0','0','5','0','0'}; createTree(root,a,0); tt.inOrder(root); }}
- 二叉树基本知识(总结)
- 二叉树的一些基本知识总结
- 二叉树的基本知识
- 二叉树的基本知识
- 二叉树的基本知识以及各种遍历(Java)
- 【C++】 二叉树的基本知识及其遍历
- 红皮书基本知识总结(一)
- 红皮书基本知识总结(二)
- ios 基本知识总结(一)
- mysql基本知识总结(上)
- mysql基本知识总结(下)
- Mybatis总结(1)---基本知识
- 基本知识总结
- 基本知识总结
- 二叉树总结(c++)
- 二叉树总结(JAVA)
- html+css的基本知识总结(一)
- 二叉树的性质及基本知识-------图的概念
- 如何修改TOMCAT的默认主页为你自己项目的主页
- linux关闭nvidia独显的方法
- 2805: 验证数学猜想。
- Tomcat SSL配置大全
- AJAX学习笔记之xml的JQ使用方法
- 二叉树基本知识(总结)
- Apache+tomcat集群
- Java(六)运算符和表达式
- 第七周项目1——实现复数类中的运算符重载(友元函数)
- 14-15西南交通大学ACM校赛初赛题解A、D、H、J
- 回调无处不在
- Tomcat内存溢出的三种情况及解决办法分析
- 情境领导
- IDC IDP