树型结构
概念
树是一种非线性的数据结构,有一个特殊的节点为根节点(无前驱节点),如下图。
- 节点的度:一个节点含有的子树的个数
- 树的度:一棵树中最大节点的度
- 叶子节点(终端节点):度为0的节点
- 双亲节点(父节点):若一个节点含有子节点,则这个节点称为其子节点的双亲节点
- 孩子节点(子节点):一个节点含有的子树的根节点
- 根节点:一棵树中没有双亲节点的节点
- 节点的层次:从根开始,根为第一层,根的子节点为第二层,以此类推
- 树的高度或深度:树中节点的最大层次
树的表现形式
- 孩子兄弟表示法
不仅要保存第一个孩子节点,还要给出当前节点的下一个兄弟节点 - 双亲表示法
节点中既要保存值域,也要保存节点双亲节点的地址 - 孩子表示法
节点中既要保存值域,也要保存孩子的地址 - 孩子双亲表示法
孩子表示和双亲表示相结合,节点中既要保存值域,也要保存节点的孩子及双亲的位置
二叉树
概念
-
空树
-
非空时,由一个根节点、根节点的左子树及根节点的右子树组成
特点 -
二叉树中不存在度大于2的节点
-
二叉树是有序树
特殊的二叉树
(1)满二叉树:二叉树中每层结点的个数达到了最大值
(2)完全二叉树:一棵具有n个节点的二叉树与满二叉树前n个节点的连接形式一样。满二叉树是特殊的完全二叉树。
性质
(1)若规定根节点的曾树为1,则一棵非空二叉树的第i(i>0)层上最多有2^(i-1)个节点;
(2)若规定只有根节点的二叉树的深度为1,则深度为k(k>=0)的二叉树的最大节点数为2^k-1;
(3)对任何一棵二叉树,若其叶节点个数为n0,度为2的非叶节点个数为n2,则有n0=n2+1;
(4)具有n个节点的完全二叉树的深度k为log2(n+1)上取整,若为满二叉树,计算出的一定是整数;
(5)对于具有n个节点的完全二叉树,如果按照从上至下、从左至右的顺序对所有节点从0开始编号,则对于序号为i的节点有:
①若i>0,双亲序号:(i+1)/2;若i=0,i为根节点编号,无双亲节点
②若2i+1<n,左孩子序号:2i+1,否则无左孩子
③若2i+2<n,右孩子序号:2i+2,否则无右孩子
二叉树的存储 -
顺序存储
以数组的形式存储 -
链式存储
通过一个一个的节点引用起来
// 孩子表示法
class Node {
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
}
// 孩子双亲表示法
class Node {
int val; // 数据域
Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
Node parent; // 当前节点的根节点
}
二叉树的遍历
(1)层序遍历
(2)根据遍历根节点的先后次序:
- 前序遍历
根节点->根节点的左子树->根节点的右子树 - 中序遍历
根节点的左子树->根节点->根节点的右子树 - 后序遍历
根节点的左子树->根节点的右子树->根节点
二叉树的基本操作 - 前序遍历
//前序递归遍历
public void preOrder(BTNode root){
if(null != root) {
System.out.println(root.val + " ");
preOrder(root.left);
preOrder(root.right);
}
}
//前序非递归遍历
public void preOrderTraversel(BTNode root){
if(null == root){
return;
}
Stack<BTNode> s = new Stack<>();
s.push(root);
while(!s.isEmpty()){
BTNode cur = s.peek();
System.out.print(cur.val + " ");
s.pop();
//如果cur有右子树,让右子树入队列
if(null != cur.right){
s.push(cur.right);
}
//如果cur有左子树,让左子树入队列
if(null != cur.left){
s.push(cur.left);
}
}
System.out.println();
}
- 中序遍历
//中序递归遍历
public void inOrder(BTNode root){
if(null != root){
inOrder(root.left);
System.out.println(root.val + " ");
inOrder(root.right);
}
}
//中序非递归遍历
public void inOrderTraversel(){
if(null == root){
return;
}
Stack<BTNode> s = new Stack<>();
BTNode cur = root;
while(null != cur || !s.empty()){
while(cur != null){
s.push(cur);
cur = cur.left;
}
cur = s.peek();
System.out.print(cur.val + " ");
s.pop();
cur = cur.right;
}
}
- 后序遍历
//后序递归遍历
private void postOrder(BTNode root){
if(null != root){
postOrder(root.left);
postOrder(root.right);
System.out.println(root.val + " ");
}
}
//后序非递归遍历
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> ret = new ArrayList<>();
if(root == null){
return ret;
}
Stack<TreeNode> s = new Stack<>();
s.push(root);
while(!s.isEmpty()){
TreeNode cur = s.pop();
if(cur.left != null){
s.push(cur.left);
}
if(cur.right != null){
s.push(cur.right);
}
ret.add(0, cur.val);
}
return ret;
}
- 层序遍历
//层序遍历
public void levelOrder(){
if(null == root){
return;
}
Queue<BTNode> q = new LinkedList<>();
q.offer(root);
while(!q.isEmpty()){
BTNode cur = q.poll();
System.out.print(cur.val + " ");
//如果cur有左子树,让左子树入队列
if(null != cur.left){
q.offer(cur.left);
}
//如果cur有右子树,让右子树入队列
if(null != cur.right){
q.offer(cur.right);
}
}
System.out.println();
}
- 获取二叉树中节点的个数
public int getCount(BTNode root){
if(null == root){
return 0;
}
return 1 + getCount(root.left) + getCount(root.right);
}
- 获取叶子结点个数
public int getLeafCount(BTNode root){
if(null == root){
return 0;
}
if(root.left == null && root.right == null){
return 1;
}
return getLeafCount(root.left) + getLeafCount(root.right);
}
- 获取第k层节点个数
public int getKLevelCount(BTNode root, int k){
if(null == root){
return 0;
}
if(k < 1){
return 0;
}
if(k == 1){
return 1;
}
return getKLevelCount(root.left, k - 1) + getKLevelCount(root.right, k - 1);
}
- 求二叉树高度
private int getHeight(BTNode root){
if(null == root){
return 0;
}
int leftHeight = getHeight(root.left);
int rightHeight = getHeight(root.right);
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}