二叉树
二叉树
二叉树基本性质
- 第 i 层:至多 2^(i-1) 个结点
- 深度为k,至多 2^k - 1 个结点,至少 k 个结点
- 叶子n0个,度为2的结点n2个:n0 = n2 + 1
- 完全二叉树:n个结点,则深度为 [ log2(n)] + 1
- 完全二叉树(顺序表存储,下标从1开始)下标关系:双亲[ i / 2 ] 、左孩子 2 * i 、右孩子 2 * i + 1
存储结构
顺序存储

二叉链表


三叉链表


线索链表


二叉树实现(二叉链表)
二叉树结点
publicclassBiNode{char data;BiNode left;BiNode right;int flag =0;//供非递归后序遍历使用}
初始化
privatestaticint i;publicBinaryTree(char[] pre){i =0;root = create(pre);}//初始化(先序遍历顺序存放数组、'#'表示null)privateBiNode create(char[] pre){if(i < pre.length){if(pre[i]=='#') //结点为空{i++;return null;}BiNode p =newBiNode(pre[i], null, null); //结点非空i++;p.left = create(pre); //递归建立左子树p.right = create(pre); //递归建立右子树return p;}return null;}
遍历(递归)
- 先序遍历
publicvoid preOrder(){preOrder(root);}privatevoid preOrder(BiNode root){if(root == null)return;System.out.print(root.data); //访问结点preOrder(root.left);preOrder(root.right);}
- 中序遍历
publicvoid inOrder(){inOrder(root);}privatevoid inOrder(BiNode root){if(root == null)return;inOrder(root.left);System.out.print(root.data); //访问结点inOrder(root.right);}
- 后序遍历
publicvoid postOrder(){postOrder(root);}privatevoid postOrder(BiNode root){if(root == null)return;postOrder(root.left);postOrder(root.right);System.out.print(root.data); //访问结点}
- 层序遍历
publicvoid levelOrder(){levelOrder(root);}privatevoid levelOrder(BiNode root){LinkedList<BiNode>queue=newLinkedList<BiNode>(); //LinkedList实现了Queue接口BiNode p = root;while(p != null){System.out.print(p.data); //访问结点if(p.left != null)queue.add(p.left);if(p.right != null)queue.add(p.right);p =queue.poll(); //队头出队并返回为p}}
遍历(非递归)
- 先序遍历
privatevoid preOrder(BiNode head){LinkedList<BiNode> s =newLinkedList<BiNode>();while(head != null ||!s.isEmpty()){while(head != null) //访问左子树{System.out.print(head.data); //访问左子树s.push(head); //结点入栈(待后面找其右子树使用)= =(“递归”)head = head.left;}if(!s.isEmpty()) //转向右子树{head = s.peek().right; //转向右子树s.pop(); //结点出栈(已经找到其右子树)= =(“递归结束”)}}}
- 中序遍历
privatevoid inOrder2(BiNode head){LinkedList<BiNode> s =newLinkedList<BiNode>();while(head != null ||!s.isEmpty()){while(head != null) //左子树入栈{s.push(head); //结点入栈(待后面找其右子树使用)= =(“递归”)head = head.left;}System.out.print(s.peek().data); //访问左子树if(!s.isEmpty()) //转向右子树{head = s.peek().right; //转向右子树s.pop(); //结点出栈(已经找到其右子树)= =(“递归结束”)}}}
- 后序遍历
//后序遍历特点:递归左右子树后,还需访问结点://1、左子树入栈//2、“两次出栈”(用flag标记模仿):第一次是为了找到左子树相应的右子树结点;第二次是为了访问结点privatevoid postOrder2(BiNode head){LinkedList<BiNode> s =newLinkedList<BiNode>();while(head != null ||!s.isEmpty()){while(head != null) //左子树入栈{head.flag =1;s.push(head); //结点连同flag入栈(待后面找其右子树使用)= =(“递归”)head = head.left;}while(!s.isEmpty()&& s.peek().flag ==2) //若flag为2(已经找到其右子树出过一次栈),访问结点{System.out.print(s.peek().data); //访问结点元素s.pop(); //(第二次“结点出栈”)实际结点出栈(已经访问结点元素)= =(“递归结束”)}if(!s.isEmpty()) //flag为1,转向右子树{head = s.peek().right; //转向右子树s.peek().flag =2; //(第一次“flag模拟出栈”)标记为2,但实际结点不出栈(已经找到其右子树)}}}
插入
//在p结点后插入datapublicvoid insert(BiNode p,char data, boolean left){if(p != null){if(left) //插入位置为左孩子p.left =newBiNode(data,p.left,null);else //插入位置为右孩子p.right =newBiNode(data,p.right,null);}}
删除
//删除p的一个子树publicvoiddelete(BiNode p, boolean left){if(p != null){if(left) //删除目标为左子树p.left = null;else //删除目标为右子树p.right = null;}}
哈夫曼树(最优二叉树)

哈夫曼树的存储结构:



哈夫曼算法:


一般树的存储结构
- 双亲表示法:

- 孩子表示法:
1、多重链表表示法

2、孩子链表表示法

- 双亲孩子表示法:

- 孩子兄弟表示法:


树与森林的转换



整理by Doing
参考资料:《数据结构(C++版)》王红梅

浙公网安备 33010602011771号