一、普通树结构

特点:

  • 每个节点都只有有限个子节点或无子节点。
  • 没有父节点的节点称为根节点。
  • 每一个非根节点有且只有一个父节点
  • 除了根节点外,每个子节点可以分为多个不相交的子树。
  • 树里面没有环路

名词:

  • 节点的度:一个节点含有的子树的个数称为该节点的度。
  • 树的度:一棵树中,最大的节点度称为树的度。
  • 叶节点或终端节点:度为零的节点。(一般叫叶节点居多)
  • 非终端节点或分支节点:度不为零的节点。
  • 父亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点。
  • 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点。
  • 兄弟节点:具有相同父节点的节点互称为兄弟节点。
  • 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推。
  • 深度:对于任意节点n,n的深度为从根到n的唯一路径长,根的深度为0。
  • 高度:对于任意节点n,n的高度为从n到一片树叶的最长路径长,所有树叶的高度为0。
  • 堂兄弟节点:父节点在同一层的节点互为堂兄弟。
  • 节点的祖先:从根到该节点所经分支上的所有节点。
  • 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
  • 森林:由m(m java求二叉树父节点 二叉树父节点是啥_java求二叉树父节点

树的种类:

  1. 无序树:树中任意节点的子节点之间没有顺序关系,这种树称为无序树,也成为自由树。
  2. 有序树:树中任意节点的子节点之间有顺序关系,这种树称为有序树。
  3. 二叉树:每个节点最多含有两个子树的树称为二叉树。
  4. 完全二叉树:对于一颗二叉树,假设其深度为d(d>1),除了d层外,其他各层各层的节点数目均已达到最大值,且第d层所有节点从左到右连续地紧密排列,这样的二叉树叫完全二叉树。
  5. 满二叉树:所有叶节点都在最底层的完全二叉树。
  6. 平衡二叉树AVL树):当且仅当任意节点的两棵子树的高度差不大于1的二叉树。
  7. 排序二叉树(二叉查找树):
    ①若任意节点的左子树不为空,则左子树上所有节点的值都小于它的根节点的值。
    ②若任意节点的右子树不为空,则右子树上所有节点的值都大于它的根节点的值。
    ③任意节点的左右子树也分别为二叉查找树。
  8. 霍夫曼树:带权路径最短的二叉树称为哈夫曼树或最优二叉树。
  9. B树:一种对读写操作优化的自平衡的二叉查找树,能够保持数据有序,拥有多余2个子树。
  10. 红黑树: 一种自平衡二叉查找树。

二、二叉树

定义

  • 二叉树(英语:Binary tree)是每个节点最多只有两个分支(即不存在分支度大于2的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒

性质

  • 二叉树的第i层至多拥有java求二叉树父节点 二叉树父节点是啥_数据结构_02个节点;深度为k的二叉树至多总共有java求二叉树父节点 二叉树父节点是啥_java求二叉树父节点_03个节点(定义根节点所在深度java求二叉树父节点 二叉树父节点是啥_b树_04
  • 对任何一颗非空的二叉树T,如果其叶片数为n0,分支度为2的节点数为n2,则n0=n2+1

数据存储:

1、顺序存储表示

1.1 定义

二叉树可以用数组链接串列来存储。根节点的索引为0,如果某个节点的索引为i,那么它的:

  • 左子节点索引为java求二叉树父节点 二叉树父节点是啥_数据结构_05
  • 右子节点为java求二叉树父节点 二叉树父节点是啥_二叉树_06
  • 父节点为java求二叉树父节点 二叉树父节点是啥_数据结构_07

    伪代码:
#define MAX_TREE_SIZE 100 /* 二叉树的最大节点数 */
typedef TELemType SqBiTree[MAX_TREE_SIZE] /* 0号单元存储根节点 */
typedef struct
{
	int level, order; /* 即节点的层(按满二叉树计算) */
}position;
1.2 优点:
  1. 更有利于紧凑存储。
  2. 更好的访问局部性。
  3. 前序遍历更方便。
1.3 缺点:
  1. 需要连续的存储空间,如果深度为h的二叉树其每个节点都只有右子节点,那么需要占用java求二叉树父节点 二叉树父节点是啥_数据结构_08的空间,实际上却只有h个节点,极大的浪费了空间。

2、二叉链表存储表示

2.1 定义

在使用记录或存储器地址指针的程序设计语言中,二叉树通常用树结点结构来存储。如果一个结点的子结点个数小于2,一些子结点指针可能为空值,或者为特殊的哨兵结点。

java求二叉树父节点 二叉树父节点是啥_算法_09


伪代码:

/* 二叉树的二叉链表存儲表示 */
 typedef struct BiTNode
 {
   TElemType data;
   struct BiTNode *lchild,*rchild; /* 左右孩子指針 */
 }BiTNode,*BiTree;
2.2 优点

使用链表能避免顺序存储浪费空间的问题,算法和结构相对简单。

2.3 缺点

使用二叉链表,由于缺乏父链的指引,在找回父节点时需要重新扫描树得知父节点的节点地址。

3、三叉链表存储表示

3.1 定义

改进于二叉链表,增加父节点的指引。

3.2 优点

能更好地实现节点间的访问。

3.3 缺点

①不过算法相对复杂。
②当二叉树用三叉链表表示时,有N个结点,就会有N+2个空指针。

基本操作

遍历

所有遍历方法的时间复杂度都是O(n)

1、深度优先遍历
1.1 前(先)序遍历

先访问根节点,再访问左子节点,最后访问右子节点

visit(node)
    print node.value
    if node.left  != null then visit(node.left)
    if node.right != null then visit(node.right)
1.2 中序遍历

先访问左子节点,再访问根节点,最后访问右子节点

visit(node)
    if node.left  != null then visit(node.left)
    print node.value
    if node.right != null then visit(node.right)
1.3 后序遍历

先访问左子节点,再访问右子节点,最后访问根节点

visit(node)
    if node.left  != null then visit(node.left)
    if node.right != null then visit(node.right)
    print node.value

以上的递归算法使用与树的高度成比例的栈空间

2、广度优先遍历

和深度优先遍历不同,广度优先遍历会先访问离根节点最近的节点。二叉树的广度优先遍历又称按层次遍历。算法借助队列实现。
下面判断完全二叉树的代码,用到了广度优先遍历。

一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。。

判断完全二叉树代码:

public class TreeNode
{
	public TreeNode LeftNode;
	public TreeNode RightNode;
	public int Data;
	public TreeNode(int d)
	{
		Data = d;
		LeftNode = null;
		RightNode = null;
	}
}

public class IntTree
{
	public TreeNode root;

	public bool IsComplete()
	{
		if (root == null)
		{
			return false;
		}
		// 广度优先遍历
		Queue q = new Queue();
		q.Enqueue(root);
		while(q.Count > 0)
		{
			TreeNode top = q.Dequeue();
			bool leftEmpty = top.LeftNode == null;
			bool rightEmpty = top.RightNode == null;
			if (!leftEmpty && !rightEmpty )
			{
				q.Enqueue(top.LeftNode);
				q.Enqueue(top.RightNode);
			}
			else if (leftEmpty  && !rightEmpty )
			{
				return false;
			}
			else if ((!leftEmpty && rightEmpty) || (leftEmpty && rightEmpty))
			{
				if (!leftEmpty && rightEmpty)
				{
					q.Enqueue(top.LeftNode);
				}
				while(q.Count > 0)
				{
					top = q.Dequeue();
					if (top.LeftNode == null && top.rightNode == null)
					{
					}
					else
					{
						return false;
					}
				}
			}
		}
		return true;
	}
}