二叉树之二叉链表
来源:互联网 发布:4g通信软件 编辑:程序博客网 时间:2024/05/22 21:45
本文利用java语言模拟二叉树的二叉链表的实现,下面先对二叉树的相关概念作简单介绍:
二叉树:每个结点至多有两颗子树,且子树有左右之分,其次序不能任意颠倒; 基本形态:空、仅有根结点、左子树为空、右子树为空、左右子树均非空;
完全二叉树父子结点序号关系:
* 如果i=1,则结点i为根结点,否则其双亲结点为[i/2];
* 如果2i > n,则结点i无左孩子,否则其左孩子结点为2i;
* 如果2i+1 > n,则结点i无右孩子,否则右孩子结点为2i+1;
二叉链表:结点包含数据域和左右指针(引用)域的链表;
下面主要给出二叉链表的实现:
1. 二叉链表的结点
package org.sky.tree;/** * 二叉链表结点 * * @author sky * * @param <E> */public class BinaryTreeNode<E> { E element; BinaryTreeNode<E> leftChild; BinaryTreeNode<E> rightChild; public BinaryTreeNode() { super(); this.element = null; this.leftChild = null; this.rightChild = null; } public BinaryTreeNode(E element) { super(); this.element = element; this.leftChild = null; this.rightChild = null; } public BinaryTreeNode(E element, BinaryTreeNode<E> leftChild, BinaryTreeNode<E> rightChild) { super(); this.element = element; this.leftChild = leftChild; this.rightChild = rightChild; } public E getElement() { return element; } public void setElement(E element) { this.element = element; } public BinaryTreeNode<E> getLeftChild() { return leftChild; } public void setLeftChild(BinaryTreeNode<E> leftChild) { this.leftChild = leftChild; } public BinaryTreeNode<E> getRightChild() { return rightChild; } public void setRightChild(BinaryTreeNode<E> rightChild) { this.rightChild = rightChild; } public boolean isLeaf() { if (this.leftChild == null && this.rightChild == null) { return true; } return false; }}
2. 二叉链表实现
package org.sky.tree;import java.util.Collection;import java.util.LinkedList;import java.util.List;import java.util.Queue;import java.util.Scanner;import java.util.Stack;import java.util.concurrent.LinkedBlockingDeque;import java.util.concurrent.LinkedBlockingQueue;/** * 二叉链表实现 * * @author sky * * @param <E> */public class BinaryTree<E> { private BinaryTreeNode<E> root; public BinaryTree() { super(); this.root = new BinaryTreeNode<E>(); } public boolean isEmpty() { if (root == null) { return true; } return false; } public BinaryTreeNode<E> getRoot() { return root; } /** * 将输入的数据随机分配在二叉树的结点,以生成随机二叉树 * @param node * @param element */ public void createTreeRandomly(BinaryTreeNode<E> node, E element){ if(root == null){ root = new BinaryTreeNode<E>(); }else{ if(Math.random() > 0.5){ if(node.leftChild == null){ node.leftChild = new BinaryTreeNode<E>(element); }else{ createTreeRandomly(node.leftChild,element); } }else{ if(node.rightChild == null){ node.rightChild = new BinaryTreeNode<E>(element); }else{ createTreeRandomly(node.rightChild,element); } } } } /** * 根据传入的集合创建完全二叉树 * 此处利用了完全二叉树父结点和子结点间的关系:如果i=1,则结点i为根结点,否则其双亲结点为[i/2]; * 如果2i > n,则结点i无左孩子,否则其左孩子结点为2i; * 如果2i+1 > n,则结点i无右孩子,否则右孩子结点为2i+1; * @param c */ private BinaryTreeNode<E> node = null; public void createCompleteBinaryTree(Collection<? extends E> c){ if(c != null && c.size() > 0){ List<BinaryTreeNode<E>> treeList = new LinkedList<BinaryTreeNode<E>>(); for(Object o : c){ BinaryTreeNode<E> binaryTreeNode = new BinaryTreeNode<E>((E)o); treeList.add(binaryTreeNode); } LinkedBlockingDeque<BinaryTreeNode<E>> queue = new LinkedBlockingDeque<BinaryTreeNode<E>>(); //对前treeList.size()/2 - 1个父节点按照父节点与孩子节点的数字关系建立二叉树 for(int parentIndex = 0; parentIndex < treeList.size()/2; parentIndex++){ if(parentIndex == 0){ root = treeList.get(parentIndex); //左子树 root.leftChild = treeList.get(parentIndex*2 + 1); queue.add(root.leftChild); //右子树 root.rightChild = treeList.get(parentIndex*2 +2); queue.add(root.rightChild); }else{ if(!queue.isEmpty() && parentIndex*2+1 < treeList.size()){ node = (BinaryTreeNode<E>) queue.poll(); if(parentIndex*2+1 < treeList.size()){ //左子树 node.leftChild = treeList.get(parentIndex*2 + 1); queue.add(node.leftChild); } if(parentIndex*2+2 < treeList.size()){ //右子树 node.rightChild = treeList.get(parentIndex*2 + 2); queue.add(node.rightChild); } }else{ return ; }; } } } } /** * 先序遍历创建二叉树,其中输入的‘#’代表空结点; * 例如输入input.txt:- + a # # * # # / e # # f # #; * @param inputFile */ public void preOrderCreateBinaryTree(String inputFile){ Scanner scanner = null; try{ scanner = new Scanner(inputFile); }catch(Exception e){ e.printStackTrace(); } this.root = preOrderCreateBinaryTree(root, scanner); } public BinaryTreeNode<E> preOrderCreateBinaryTree(BinaryTreeNode<E> node, Scanner scanner){ String temp = scanner.next(); if(temp.trim().equals("#")){ return null; }else{ node = new BinaryTreeNode<E>((E)temp); node.setLeftChild(preOrderCreateBinaryTree(node.getLeftChild(), scanner)); node.setRightChild(preOrderCreateBinaryTree(node.getRightChild(), scanner)); return node; } } /** * 递推:知道第一个,推出下一个,直到达到目的。 * 递归:要知道第一个,需要先知道下一个,直到一个已知的,再反回来,得到上一个,直到第一个。 */ /** * 递归求二叉树结点个数 * @param root * @return 二叉树结点个数 */ public int getNodeNumber(BinaryTreeNode<E> root){ if(root == null){ return 0; }else{ return getNodeNumber(root.leftChild) + getNodeNumber(root.rightChild) + 1; } } /** * 递归求二叉树的深度 * @param root * @return 二叉树的深度 */ public int getDepth(BinaryTreeNode<E> root){ if(root == null){ return 0; }else{ int depthLeft = getDepth(root.leftChild); //左子树深度 int depthRight = getDepth(root.rightChild); //右子树深度 return depthLeft > depthRight ? (depthLeft+1) : (depthRight+1); } } /** * 递归求二叉树第k层的结点个数 * @param root * @param k * @return 第k层的结点个数 */ public int getKthLevelNodeNumber(BinaryTreeNode<E> root, int k){ if(root == null || k < 1){ return 0; } if(k == 1){ return 1; } int leftNumber = getKthLevelNodeNumber(root.leftChild, k-1); int rightNumber = getKthLevelNodeNumber(root.rightChild,k-1); return (leftNumber + rightNumber); } /** * 递归求二叉树的叶子结点数 * @param root * @return */ public int getLeafNodeNumber(BinaryTreeNode<E> root){ if(root == null){ return 0; } if(root.leftChild == null && root.rightChild == null){ return 1; } int leftNumber = getLeafNodeNumber(root.leftChild); int rightNumber = getLeafNodeNumber(root.rightChild); return (leftNumber + rightNumber); } /** * 判定两个二叉树结构是否相同 * 递归解法: * (1)如果两棵二叉树都为空,返回真 * (2)如果两棵二叉树一棵为空,另一棵不为空,返回假 * (3)如果两棵二叉树都不为空,如果对应的左子树和右子树都同构返回真,其他返回假 * @param root1 * @param root2 * @return 结构相同时,返回true; */ public boolean strutureComp(BinaryTreeNode<E> root1, BinaryTreeNode<E> root2){ if(root1 == null && root2 == null){ return true; }else if(root1 == null || root2 == null){ return false; } boolean leftResult = strutureComp(root1.leftChild, root2.leftChild); boolean rightResult = strutureComp(root1.rightChild, root2.rightChild); return (leftResult && rightResult); } /** * 递归插入结点 * @param root * @param element * @return 二叉树 */ public BinaryTreeNode<E> insert(BinaryTreeNode<E> root, E element){ BinaryTreeNode<E> pointer = new BinaryTreeNode<E>(element); if(root == null){ root = pointer; }else if(root.leftChild == null){ root.leftChild = insert(root.leftChild, element); }else if(root.rightChild == null){ root.rightChild = insert(root.rightChild, element); } return root; } /** * 求二叉树中特定子结点的父结点 * @param root * @param childNode * @return 存在父结点时,返回父结点;否则,返回null */ public BinaryTreeNode<E> getParent(BinaryTreeNode<E> root, BinaryTreeNode<E> childNode){ if(root == null){ return null; } if(root.leftChild == childNode || root.rightChild == childNode){ return root; } if(getParent(root.leftChild, childNode) != null){ return getParent(root.leftChild, childNode); }else{ return getParent(root.rightChild, childNode); } } /** * 递归删除二叉树,释放相应的存储空间 * @param root */ public void destoryBinaryTree(BinaryTreeNode<E> root){ if(root != null){ destoryBinaryTree(root.leftChild); destoryBinaryTree(root.rightChild); root = null; } } /** * 层序遍历(广度优先遍历) * @param root */ public void levelOrder(BinaryTreeNode<E> root){ Queue<BinaryTreeNode<E>> queue = new LinkedBlockingQueue<BinaryTreeNode<E>>(); BinaryTreeNode<E> pointer = root; /** * 当前结点非空时,放入队首 */ if(pointer != null){ queue.add(pointer); } /* * 队列不为空时,先访问中间节点,访问完成后弹出队首节点;然后是左节点,再是右节点; */ while(!queue.isEmpty()){ pointer = queue.peek(); visit(pointer); queue.remove(); if(pointer.leftChild != null){ queue.add(pointer); } if(pointer.rightChild != null){ queue.add(pointer); } } } /** * 递归先序遍历二叉树 * @param root */ public void preOrder(BinaryTreeNode<E> root){ if (root == null){ return; } visit(root); preOrder(root.leftChild); preOrder(root.rightChild); } /** * 非递归先序遍历二叉树 * @param root */ public void nPreOrder(BinaryTreeNode<E> root){ Stack<BinaryTreeNode<E>> stack = new Stack<BinaryTreeNode<E>>(); BinaryTreeNode<E> pointer = root; while(!stack.isEmpty() || pointer != null){ if(pointer != null){ visit(pointer); if(pointer.rightChild != null){ stack.push(pointer.rightChild); } pointer = pointer.leftChild; }else{ pointer = stack.pop(); } } } /** * 递归中序遍历 * @param root */ public void inOrder(BinaryTreeNode<E> root){ if (root == null){ return; } inOrder(root.leftChild); visit(root); inOrder(root.rightChild); } /** * 非递归中序遍历1 * @param root */ public void nInOrder(BinaryTreeNode<E> root){ Stack<BinaryTreeNode<E>> stack = new Stack<BinaryTreeNode<E>>(); BinaryTreeNode<E> pointer = root; while(pointer != null || !stack.isEmpty()){ if(pointer != null){ stack.push(pointer); pointer = pointer.leftChild; }else{ pointer = stack.pop(); visit(pointer); pointer = pointer.rightChild; } } } /** * 非递归中序遍历2 * @param root */ public void nInOrders(BinaryTreeNode<E> root){ Stack<BinaryTreeNode<E>> stack = new Stack<BinaryTreeNode<E>>(); BinaryTreeNode<E> pointer = root; stack.push(pointer); while(!stack.isEmpty()){ while(pointer != null){ stack.push(pointer.leftChild); pointer = pointer.leftChild; } stack.pop(); if(!stack.isEmpty()){ pointer = stack.pop(); visit(pointer); pointer = pointer.rightChild; stack.push(pointer); } } } /** * 递归后序遍历 * @param root */ public void postOrder(BinaryTreeNode<E> root){ if (root == null){ return; } postOrder(root.leftChild); postOrder(root.rightChild); visit(root); } /** * 非递归后序遍历 * @param root */ public void nPostOrder(BinaryTreeNode<E> root){ Stack<BinaryTreeNode<E>> stack = new Stack<BinaryTreeNode<E>>(); //初始化栈,用于保存带访问的节点 BinaryTreeNode<E> pointer = root; //保存根节点 BinaryTreeNode<E> preNode = root; //保存前一个被访问的节点 while(!stack.isEmpty() || pointer != null){ //若当前节点不空,就一直进栈,然后继续向左走 while(pointer.leftChild != null){ stack.push(pointer); pointer = pointer.leftChild; } /* * 当前节点为空时,分两种情况: * 1、当前节点移动到栈顶处,然后访问栈顶元素的右节点 * 2、当前节点移动到栈顶,但是栈顶元素没有右节点,这就需要弹出栈顶元素,再对此元素访问; * 然后再对新的栈顶元素进行判断即可 */ while((pointer != null && pointer.rightChild == null) || pointer.rightChild == preNode){ visit(pointer); preNode = pointer; if(stack.isEmpty()){ return; } pointer = stack.pop(); } stack.push(pointer); pointer = pointer.rightChild; } } /** * 访问当前结点 * @param current */ public void visit(BinaryTreeNode<E> current){ if(current != null && current.element != null){ System.out.println(current.element); }else{ System.out.println("null"); } }}
3. 参考文献
1. java创建二叉树并递归遍历二叉树
2. java实现二叉树相关代码—–数据结构
3. Java实现二叉树的创建、递归/非递归遍历
4. Java实现二叉树的创建和遍历操作(有更新)
0 0
- 二叉树之二叉链表
- 二叉树之二叉链表
- 二叉树、二叉链表
- 二叉树:二叉链表
- 二叉树应用之哈夫曼编码(二叉链表实现)
- C++实现二叉树之二叉链表
- 二叉树之二叉链表的类模板实现
- C语言二叉树之二叉链表
- 二叉树,线索二叉树,二叉链表
- 二叉树之线索链表
- 二叉树(二叉链表实现)
- 二叉树的二叉链表创建
- 二叉链表生成二叉树
- 二叉树的二叉链表实现
- 二叉树的二叉链表实现
- 二叉链表实现二叉树
- 二叉树的二叉链表存储
- 建立二叉树的二叉链表
- Intellij IDEA Maven:Generating Project in Batch mode 卡住问题
- poj 2987 Firing 最大权闭合图
- ns3的dce-linux integration
- HDU 1130 How Many Trees?(Catalan + 大数)
- Android简单拨打电话功能
- 二叉树之二叉链表
- Hive 5. 数据类型
- 快速排序法
- 卖票线程
- OBS学习
- K-D树算法的一些总结
- Kubernetes DNS服务配置
- JavaMail发送邮件简单实例及易错点分析
- JAVA装饰者模式(从现实生活角度理解代码原理)