数据结构学习----二叉树(Java实现)
2014-12-15 10:37 雪夜&流星 阅读(1359) 评论(0) 编辑 收藏 举报二叉树接口,二叉树抽象数据类型:
package com.clarck.datastructure.binarytree; /** * 二叉树接口 * * 二叉树接口,二叉树抽象数据类型 * * @author clarck * * @param <T> */ public interface BinaryTTree<T> { /** * 判断二叉树是否为空 * * @return */ boolean isEmpty(); /** * 先根次序遍历二叉树 */ void preOrder(); /** * 中根次序遍历二叉树 */ void inOrder(); /** * 后根次序遍历二叉树 */ void postOrder(); /** * 按层次遍历二叉树 */ void levelOrder(); /** * 返回二叉树的结点个数 * * @return */ int count(); /** * 返回二叉树高度 * * @return */ int height(); /** * 查找并返回首次出现的关键字为key的元素 * * @param key * @return */ T search(T key); /** * 返回node的父母结点 * * @param node * @return */ BinaryNode<T> getParent(BinaryNode<T> node); /** * 插入元素x作为根结点 * @param x */ void insertRoot(T x); /** * 插入元素作为p结点的左右孩子 * @param p * @param x * @param leftChild * @return */ BinaryNode<T> insertChild(BinaryNode<T> p, T x, boolean leftChild); /** * 删除p结点的左或右子树 * @param p * @param leftChild */ void removeChild(BinaryNode<T> p, boolean leftChild); /** * 删除二叉树 */ void removeAll(); }
二叉树类:
package com.clarck.datastructure.binarytree; import com.clarck.datastructure.queue.LinkedQueue; import com.clarck.datastructure.queue.SeqQueue; import com.clarck.datastructure.stack.LinkedStack; /** * 二叉树类,实现BinaryTTree<T>接口,泛型T指定结点的元素类型 * * @author clarck * * @param <T> */ public class BinaryTree<T> implements BinaryTTree<T> { // 根结点,结点结构为二叉链表 public BinaryNode<T> root; /** * 构造空二叉树 */ public BinaryTree() { this.root = null; } /** * 判断二叉树是否为空 */ @Override public boolean isEmpty() { return this.root == null; } /** * 二叉树的先根、中根和后根次序遍历算法 * * 先根次序遍历二叉树 */ @Override public void preOrder() { System.out.print("先根次序遍历二叉树:"); // 调用先根次序遍历二叉树的递归方法 preOrder(root); System.out.println(); } /** * 先根次序遍历以p结点为根的子二叉树,递归方法 * * @param p */ private void preOrder(BinaryNode<T> p) { if (p != null) { // 访问当前结点 System.out.print(p.data.toString() + " "); // 按先根次序遍历当前结点的左子树,递归调用 preOrder(p.left); // 按先根次序遍历当前结点的右子树,递归调用 preOrder(p.right); } } /** * 中根次序遍历二叉树 */ @Override public void inOrder() { System.out.print("中根次序遍历二叉树: "); inOrder(root); System.out.println(); } /** * 中根次序遍历以p结点为根的子二叉树,递归方法 * * @param p */ private void inOrder(BinaryNode<T> p) { if (p != null) { // 中根次序遍历左子树 inOrder(p.left); System.out.print(p.data.toString() + " "); // 中根次序遍历右子树 inOrder(p.right); } } /** * 后根次序遍历二叉树 */ @Override public void postOrder() { System.out.print("后根次序遍历二叉树: "); postOrder(root); System.out.println(); } /** * 后根次序遍历以p结点为根的子二叉树,递归方法 * * @param p */ private void postOrder(BinaryNode<T> p) { if (p != null) { postOrder(p.left); postOrder(p.right); System.out.print(p.data.toString() + " "); } } /** * 二叉树的层次遍历 * * 按层次遍历二叉树 */ @Override public void levelOrder() { System.out.print("层次遍历二叉树: "); // 创建一个空队列 SeqQueue<BinaryNode<T>> que = new SeqQueue<BinaryNode<T>>(); BinaryNode<T> p = this.root; while (p != null) { // 访问当前结点 System.out.print(p.data + " "); // p的左孩子结点入队 if (p.left != null) que.enqueue(p.left); // p的右孩子结点入队 if (p.right != null) que.enqueue(p.right); // p指向出队结点,若队列空返回null p = que.dequeue(); } System.out.println(); } /** * 返回二叉树的结点个数 */ @Override public int count() { return count(root); } /** * 返回以p结点为根的子树的结点个数 * * @param p * @return */ private int count(BinaryNode<T> p) { if (p == null) { return 0; } return 1 + count(p.left) + count(p.right); } /** * 返回二叉树的高度 */ @Override public int height() { return height(root); } /** * 返回以p结点为根的子树高度,后根次序遍历 * * @param p * @return */ private int height(BinaryNode<T> p) { if (p == null) { return 0; } // 返回左子树的高度 int lh = height(p.left); // 返回右子树的高度 int rh = height(p.right); // 当前子树高度为较高子树的高度加1 return (lh >= rh) ? lh + 1 : rh + 1; } /** * 查找并返回首次出现的关键字key元素 */ @Override public T search(T key) { return searchNode(root, key).data; } /** * 查找并返回首次出现的关键字为key元素结点 * * @param key * @return */ public BinaryNode<T> searchNode(T key) { return searchNode(root, key); } /** * 在以p为根的子树中查找并返回首次出现的关键字为key元素结点,若未找到返回null,先根次序遍历 * * @param p * @param key * @return */ private BinaryNode<T> searchNode(BinaryNode<T> p, T key) { if (p == null || key == null) return null; // 查找成功,返回找到结点 if (p.data.equals(key)) { return p; } // 在左子树中查找,递归调用 BinaryNode<T> find = searchNode(p.left, key); // 若在左子树中未找到,怎继续在右子树中查找,递归调用 if (find == null) { find = searchNode(p.right, key); } // 返回查找结果 return find; } /** * 返回node结点的父母结点,若空树、未找到或node为根,则返回null */ @Override public BinaryNode<T> getParent(BinaryNode<T> node) { if (root == null || node == null || node == root) { return null; } return getParent(root, node); } /** * 在以p为根的子树中查找并返回node结点的父母结点 * * @param p * @param node * @return */ private BinaryNode<T> getParent(BinaryNode<T> p, BinaryNode<T> node) { if (p == null) return null; if (p.left == node || p.right == node) return p; BinaryNode<T> find = getParent(p.left, node); if (find == null) { find = getParent(p.right, node); } return find; } /** * 插入元素x作为根结点,原根结点作为其左孩子 */ @Override public void insertRoot(T x) { this.root = new BinaryNode<T>(x, this.root, null); } /** * 插入元素x作为p结点的孩子,若leftChild为true,插入结点作为左孩子,否则作为右孩子 返回插入结点,若p == null, * 则抛出空对象异常 */ @Override public BinaryNode<T> insertChild(BinaryNode<T> p, T x, boolean leftChild) { if (x == null) return null; if (leftChild) { // 插入x结点作为p的左孩子,p原左孩子成为x的左孩子 p.left = new BinaryNode<T>(x, p.left, null); return p.left; } // 插入x结点作为p的右孩子,p原右孩子成为x的右孩子 p.right = new BinaryNode<T>(x, null, p.right); return p.right; } /** * 删除p结点的左或右子树,若leftChild为true,删除左子树,否则删除右子树 * * 若p == null,将抛出空对象异常 */ @Override public void removeChild(BinaryNode<T> p, boolean leftChild) { if (leftChild) p.left = null; else p.right = null; } /** * 删除二叉树的所有结点 */ @Override public void removeAll() { this.root = null; } @Override public String toString() { return toString(root); } private String toString(BinaryNode<T> p) { if (p == null) { return ""; } // 递归调用 return p.data.toString() + " " + toString(p.left) + toString(p.right); } /** * 以先根和中根序列够杂二叉树 * * @param prelist * @param inlist */ public BinaryTree(T[] prelist, T[] inlist) { this.root = create(prelist, inlist, 0, 0, prelist.length); } private BinaryNode<T> create(T[] prelist, T[] inlist, int preStart, int inStart, int n) { System.out.print("prelist: "); print(prelist, preStart, n); System.out.print(", inlist: "); print(inlist, inStart, n); System.out.println(); if (n <= 0) { return null; } // 根结点值 T elem = prelist[preStart]; // 创建叶子结点 BinaryNode<T> p = new BinaryNode<T>(elem); int i = 0; // 在中根序列中查找根值所在位置 while (i < n && elem.equals(inlist[inStart + i])) i++; // 创建左子树 p.left = create(prelist, inlist, preStart + 1, inStart, i); // 创建右子树 p.right = create(prelist, inlist, preStart + 1, inStart + i + 1, n - 1 - i); return p; } private void print(T[] table, int start, int n) { for (int i = 0; i < n; i++) { System.out.print(table[start + i]); } } /** * 以标明空子树的先根序列构造二叉树 * * @param prelist */ public BinaryTree(T[] prelist) { this.root = create(prelist); } /** * 以标明空子树的先根序列构造一棵子二叉树,子的根值是prelist[i],返回所创建子树的根结点 */ private int i = 0; private BinaryNode<T> create(T[] prelist) { BinaryNode<T> p = null; if (i < prelist.length) { T elem = prelist[i]; i++; if (elem != null) { // 创建叶子结点 p = new BinaryNode<T>(elem); // 创建p的左子树 p.left = create(prelist); // 创建p的右子树 p.right = create(prelist); } } return p; } /** * 返回二叉树的广义表表示字符串 * * @return */ public String toGenListString() { return "二叉树的广义表表示:" + toGenListString(this.root) + "\n"; } /** * 返回以p结点为根的子二叉树的广义表表示字符串,递归方法 * * @param p * @return */ private String toGenListString(BinaryNode<T> p) { if (p == null) return "^"; String str = p.data.toString(); // 非叶结点,有子树 if (p.left != null || p.right != null) // 递归调用 str += "(" + toGenListString(p.left) + ", " + toGenListString(p.right) + ")"; return str; } /** * 二叉树遍历的非递归算法 * * 先根次序遍历二叉树的非递归算法 */ public void preOrderTraverse() { System.out.print("先根次序遍历(非遍历)"); // 创建一个空栈 LinkedStack<BinaryNode<T>> stack = new LinkedStack<BinaryNode<T>>(); BinaryNode<T> p = this.root; // p非空或栈非空时 while (p != null || !stack.isEmpty()) { if (p != null) { // 方位结点 System.out.print(p.data + " "); // p结点入栈 stack.push(p); // 进入左子树 p = p.left; } else { // p指向出栈结点 p = stack.pop(); // 进入右子树 p = p.right; } } System.out.println(); } /** * 中根次序遍历二叉树的非递归算法 */ public void inOrderTraverse() { System.out.print("中根次序遍历(非遍历) : "); LinkedStack<BinaryNode<T>> stack = new LinkedStack<BinaryNode<T>>(); BinaryNode<T> p = this.root; // p非空或栈非空时 while (p != null || !stack.isEmpty()) { if (p != null) { // p结点入栈 stack.push(p); // 进入左结点 p = p.left; } else { // p指向出栈结点 p = stack.pop(); System.out.print(p.data + " "); // 进入右子树 p = p.right; } } System.out.println(); } /** * 遍历输出叶子结点 */ public void leaf() { leaf(root); } private void leaf(BinaryNode<T> p) { if (p != null) { if (p.left == null && p.right == null) System.out.print(p.data.toString() + " "); leaf(p.left); leaf(p.right); } } /** * 返回以p结点为根的子树的叶子结点个数 * * @param p * @return */ public int countLeaf(BinaryNode<T> p) { if (p == null) { return 0; } if (p.left == null && p.right == null) { return 1; } return countLeaf(p.left) + countLeaf(p.right); } /** * 将首次出现的值为x的结点替换为y * * @param x * @param y */ public void replace(T x, T y) { BinaryNode<T> find = searchNode(x); if (find != null) { find.data = y; } } /** * 将值为x的结点值全部替换为y * * @param x * @param y */ public void replaceAll(T x, T y) { if (x != null && y != null) { replaceAll(root, x, y); } } /** * 在以p为根的子树中实现全部替换 * * @param p * @param x * @param y */ private void replaceAll(BinaryNode<T> p, T x, T y) { if (p != null) { if (p.data.equals(x)) { p.data = y; } replaceAll(p.left, x, y); replaceAll(p.right, x, y); } } /** * 后根次序遍历二叉树的非递归算法 */ public void postOrderTraverse() { System.out.print("后根次序遍历(非递归): "); LinkedStack<BinaryNode<T>> stack = new LinkedStack<BinaryNode<T>>(); BinaryNode<T> p = this.root, front = null; while (p != null || stack.isEmpty()) { if (p != null) { // p结点入栈 stack.push(p); // 进入左子树 p = p.left; } else { // 从左子树返回p结点,p结点不出栈 p = stack.get(); // p有右孩子,且右孩子没有被访问过 if (p.right != null && p.right != front) { // 进入右子树 p = p.right; stack.push(p); // 向左走 p = p.left; } else { p = stack.pop(); System.out.println(p.data + "的所有祖先结点是:" + stack.toString()); front = p; // front 是p在后根遍历次序下的前驱结点 p = null; } } } System.out.println(); } /** * 返回x结点所在的层次,若空树或未查找到x返回-1 * * @param x * @return */ public int getLevel(T x) { // 令根结点的层次为1 return getLevel(root, 1, x); } /** * 在以p结点(层次为i)为根的子树中,求x结点所在的层次 * * @param p * @param i * @param x * @return */ private int getLevel(BinaryNode<T> p, int i, T x) { // 空树或查找不成功 if (p == null) { return -1; } if (p.data.equals(x)) return i; // 在左子树查找 int level = getLevel(p.left, i + 1, x); if (level == -1) { // 继续在右子树中查找 level = getLevel(p.right, i + 1, x); } return level; } /** * 比较两棵二叉树是否相等 * * @param obj * @return */ @SuppressWarnings("unchecked") public boolean equals(Object obj) { return obj == this || obj instanceof BinaryTree && equals(this.root, ((BinaryTree<T>) obj).root); } /** * 判断以p和q结点为根的两棵子树是否相等,递归方法 * @param p * @param q * @return */ private boolean equals(BinaryNode<T> p, BinaryNode<T> q) { return p == null && q == null || p != null && q != null && p.data.equals(q.data) && equals(p.left, q.left) && equals(p.right, q.right); } /** * 深拷贝,以已知的bitree构造二叉树 * @param bitree */ public BinaryTree(BinaryTree<T> bitree) { this.root = copy(bitree.root); } /** * 复制以p为根的子二叉树,返回新建子二叉树的根结点 * @param p * @return */ private BinaryNode<T> copy(BinaryNode<T> p) { if (p == null) return null; BinaryNode<T> q = new BinaryNode<T>(p.data); //复制左子树,递归调用 q.left = copy(p.left); //复制右子树,递归调用 q.right = copy(p.right); //返回建立子树的根结点 return q; } /** * 判断是否完全二叉树 * @return */ boolean isCompleteBinaryTree() { if (this.root == null) return true; LinkedQueue<BinaryNode<T>> que = new LinkedQueue<BinaryNode<T>>(); que.enqueue(root); BinaryNode<T> p = null; while (!que.isEmpty()) { //p指向出对结点 p = que.dequeue(); //p的非空孩子结点入队 if (p.left != null) { que.enqueue(p.left); if (p.right != null) { //发现空子树,须检测队列中是否都是叶子结点 que.enqueue(p.right); } else { break; } } else { if (p.right != null) { //p的左子树空而右子树不空 return false; } else { //p是叶子,须检测队列中是否都是叶子结点 break; } } } //检测队列中是否都是叶子结点 while(!que.isEmpty()) { p= que.dequeue(); //发现非叶子,确定不是 if (p.left != null || p.right != null) { return false; } } return true; } }
二叉树的二叉链表结点类:
package com.clarck.datastructure.binarytree; /** * 二叉树的二叉链表结点类,泛型T指定结点的元素类型 * * @author clarck * * @param <T> */ public class BinaryNode<T> { // 数据域,存储数据元素 public T data; // 链域,分别指向左,右孩子结点 public BinaryNode<T> left, right; /** * 构造结点,参数分别指定元素和左、右孩子结点 * * @param data * @param left * @param right */ public BinaryNode(T data, BinaryNode<T> left, BinaryNode<T> right) { this.data = data; this.left = left; this.right = right; } /** * 构造指定值的叶子结点 * * @param data */ public BinaryNode(T data) { this(data, null, null); } public BinaryNode() { this(null, null, null); } @Override public String toString() { return this.data.toString(); } @SuppressWarnings("unchecked") public boolean equals(Object obj) { return obj == this || obj instanceof BinaryNode && this.data.equals(((BinaryNode<T>) obj).data); } public boolean isLeaf() { return this.left == null && this.right == null; } }
二叉树的广义表表示:
package com.clarck.datastructure.binarytree; /** * 二叉树的广义表表示 * * @author clarck * */ public class BinaryTree_genlist { private static int i = 0; /** * 以广义表表示构造二叉树 * @param glist * @return */ public static BinaryTree<String> createByGenList(String glist) { BinaryTree<String> bitree = new BinaryTree<String>(); i = 0; if (glist.length() > 0) { //创建子树,子树根值是glist[0] bitree.root = create(glist); } return bitree; } /** * 以广义表表示创建一颗子树,子树根值是glist[i], 返回根结点,递归方法 * @param glist * @return */ private static BinaryNode<String> create(String glist) { BinaryNode<String> p = null; char ch = glist.charAt(i); //大写字母 if (ch >= 'A' && ch <= 'Z') { //创建叶子结点 p = new BinaryNode<String>(ch + ""); i++; if (glist.charAt(i) == '(') { i++; //创建左子树,递归调用 p.left = create(glist); i++; //创建右子树,递归调用 p.right = create(glist); i++; } } //跳过'^' if (ch == '^') { i++; } return p; } public static void main(String[] args) { String glist = "A(B(D(^,G),^),C(E,F(H,^)))"; BinaryTree<String> bitree = createByGenList(glist); System.out.println(bitree.toGenListString()); System.out.println("是否完全二叉树?" + bitree.isCompleteBinaryTree()); glist = "A(B,C)"; bitree = createByGenList(glist); System.out.println(bitree.toGenListString()); System.out.println("是否完全二叉树?" + bitree.isCompleteBinaryTree()); } }
构造并遍历二叉树:
package com.clarck.datastructure.binarytree; /** * 构造并遍历二叉树 * * @author clarck * */ public class BinaryTree_make { /** * 构造给定的一棵二叉树 * @return */ public static BinaryTree<String> make() { //创建空二叉树 BinaryTree<String> bitree = new BinaryTree<String>(); BinaryNode<String> child_f, child_d, child_b, child_c; child_d = new BinaryNode<String>("D", null, new BinaryNode<String>("G")); child_b = new BinaryNode<String>("B", child_d, null); child_f = new BinaryNode<String>("F", new BinaryNode<String>("H"), null); child_c = new BinaryNode<String>("C", new BinaryNode<String>("E"), child_f); bitree.root = new BinaryNode<String>("A", child_b, child_c); return bitree; } public static void main(String[] args) { BinaryTree<String> bitree = make(); bitree.preOrder(); bitree.inOrder(); bitree.postOrder(); } }
二叉链表表示的完全二叉树类,继承二叉树类:
package com.clarck.datastructure.binarytree; /** * 以完全二叉树的层次遍历序列构造二叉链表结构存储完全二叉树 * * 二叉链表表示的完全二叉树类,继承二叉树类 * * @author clarck * * @param <T> */ public class CompleteBinaryTree<T> extends BinaryTree<T> { /** * 构造空二叉树 */ public CompleteBinaryTree() { super(); } /** * 以完全二叉树的层次序列构造完全二叉树,levellist指定层次序列 * @param levellist */ public CompleteBinaryTree(T[] levellist) { this.root = create(levellist, 0); } /** *创建以levellist[i]为根的一棵子完全二叉树,返回所创建子树的根结点 * @param levellist * @param i * @return */ private BinaryNode<T> create(T[] levellist, int i) { BinaryNode<T> p = null; if (i < levellist.length) { //创建叶子结点 p = new BinaryNode<T>(levellist[i]); //创建p的左子树 p.left = create(levellist, 2 * i + 1); //创建p的右子树 p.right = create(levellist, 2 * i + 2); } return p; } public static void main(String[] args) { String[] levellist = {"A", "B", "C", "D", "E", "F", "G", "H"}; CompleteBinaryTree<String> cbitree = new CompleteBinaryTree<String>(levellist); cbitree.preOrder(); cbitree.inOrder(); cbitree.postOrder(); System.out.println("是否完全二叉树?" + cbitree.isCompleteBinaryTree()); } }
测试类:
package com.clarck.datastructure.binarytree; public class BinaryTree_test { public static void main(String args[]) { String[] prelist1 = {"A", "B", null, null, "C"}; BinaryTree<String> bitree1 = new BinaryTree<String>(prelist1); bitree1.preOrder(); bitree1.inOrder(); bitree1.postOrder(); System.out.println("是否完全二叉树?" + bitree1.isCompleteBinaryTree()); String[] prelist2 = { "A", "B", "D", null, "G", null, null, null, "C", "E", null, null, "F", "H"}; BinaryTree<String> bitree2 = new BinaryTree<String>(prelist2); bitree2.preOrder(); bitree2.inOrder(); bitree2.postOrder(); bitree2.preOrderTraverse(); bitree2.inOrderTraverse(); bitree2.postOrderTraverse(); System.out.println(bitree2.toGenListString()); bitree2.levelOrder(); System.out.println("H结点的层次是 " + bitree2.getLevel("H")); System.out.println("是否完全二叉树?" + bitree2.isCompleteBinaryTree()); System.out.print("叶子结点: "); bitree2.leaf(); BinaryTree<String> bitree3 = new BinaryTree<String>(bitree2); System.out.println("两棵二叉树相等?" + bitree3.equals(bitree2)); System.out.println("第3棵二叉树全部替换(\"F\", \"Y\") "); bitree3.replaceAll("F", "Y"); bitree3.preOrder(); BinaryNode<String> find = bitree2.searchNode("D"); bitree2.insertChild(find, "Z", true); System.out.println("插入Z作为 " + find.data + "的左孩子"); bitree2.preOrder(); } }
运行结果:
先根次序遍历二叉树:A B C 中根次序遍历二叉树: B A C 后根次序遍历二叉树: B C A 是否完全二叉树?true 先根次序遍历二叉树:A B D G C E F H 中根次序遍历二叉树: D G B A E C H F 后根次序遍历二叉树: G D B E H F C A 先根次序遍历(非遍历)A B D G C E F H 中根次序遍历(非遍历) : D G B A E C H F 后根次序遍历(非递归): 二叉树的广义表表示:A(B(D(^, G), ^), C(E, F(H, ^))) 层次遍历二叉树: A B C D E F G H H结点的层次是 4 是否完全二叉树?false 叶子结点: G E H 两棵二叉树相等?true 第3棵二叉树全部替换("F", "Y") 先根次序遍历二叉树:A B D G C E Y H 插入Z作为 D的左孩子 先根次序遍历二叉树:A B D Z G C E F H
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本