非线性结构-二叉树的三种实现

/**
 * 1. 二叉树第一种实现方式,采用数字顺序存储
 * 二叉树的基本特点:
 * <ol>
 * <li>二叉树第i层上的节点数最多为2的(i-1)次方(i>=1)</li>
 *  <li>深度为k的二叉树至多有2的k次方-1个节点</li>
 *  <li>在任何一颗二叉树中,如果其叶子节点的数量为n0,度为2的子节点数量为n2,则n0 = n2 + 1</li>
 *  <li>具有n个节点的完全二叉树的深度为log2N+1(底数为2,指数为n+1)</li>
 *  <li>对一颗有n个节点的完全二叉树的节点按层自左向右编号,则对任意编号为i(n>=i>=1)具备以下 性质</li>
 *  <li>当i=1时,节点i是二叉树的根;若i>1,则i的父节点为i/2</li>
 *  <li>当2i<=n;则节点i有左子节点且编号2i,否则i无子节点并且是子节点,并且i是叶子节点</li>
 *  <li>当2i+1<=n;则节点i有右子节点,右子节点是2i+1;否则i无子节点</li>
 *  <li>对一颗n个节点的完全二叉树的节点按层自左向右编号,1~n/2范围内都是有孩子节点的非叶子节点,其余的节点全部是叶子节点
 *  编号为n/2的节点可能只有左子节点,也可能左右子节点都有</li>
 * </ol>
 * @author mk
 * 

 */

public class ArrayBinTree<T>
{
private Object[] datas;// 记录树中所以的节点
private final static int DEF_TREE_DEEP = 8;
private int arraySize;
private int deep;// 保存该树的深度


// 以默认深度创建二叉树
public ArrayBinTree()
{
this.deep = DEF_TREE_DEEP;
this.arraySize = (int) Math.pow(2, deep) - 1;
this.datas = new Object[arraySize];
}

// 以指定深度创建二叉树
public ArrayBinTree(int deep)
{
this.arraySize = (int) Math.pow(2, deep) - 1;
this.datas = new Object[arraySize];
}

// 以指定深度、指定根节点创建二叉树
public ArrayBinTree(int deep, T data)
{
this.arraySize = (int) Math.pow(2, deep) - 1;
this.datas = new Object[arraySize];
this.datas[0] = data;
}

/**
* 为指定节点添加子节点

* @param index
*            需要添加子节点的父节点的索引
* @param data
*            新子节点的数据
* @param left
*            是否是左子节点
*/
public void add(int index, T data, boolean left)
{
if (datas[index] == null)
throw new RuntimeException(index + "处节点为空,不能添加子节点");

if (2 * index + 1 >= arraySize)
throw new RuntimeException("树已满,不能添加子节点");

if (left)
datas[2 * index + 1] = data; // 数组首位被根节点占据,要增1
else
datas[2 * index + 2] = data;
}

// 判断树是否为空树
public boolean empty()
{
return datas[0] == null;
}

// 返回根节点
public T root()
{
return (T) datas[0];
}

// 返回指定节点(非根节点)的父节点
public T parent(int index)
{
return (T) datas[(index - 1) / 2];
}

// 返回指定节点的左子节点,当左子节点不存在时返回null
public T left(int index)
{
if (2 * index + 1 >= arraySize)
throw new RuntimeException("该节点为叶子节点,没有子节点");
return (T) datas[2 * index + 1];
}

// 返回指定节点的左子节点,当左子节点不存在时返回null
public T right(int index)
{
if (2 * index + 1 >= arraySize)
throw new RuntimeException("该节点为叶子节点,没有子节点");
return (T) datas[2 * index + 2];
}

public int deep()
{
return this.deep;// 返回二叉树的深度
}

// 返回指定节点的位置
public int pos(T data)
{
for (int i = 0; i < arraySize; i++)
if (datas[i].equals(data))
return i;

return -1;
}

@Override
public String toString()
{
return Arrays.toString(datas);
}
public static void main(String[] args)
{
ArrayBinTree<String> tree = new ArrayBinTree<String>(4, "根");
tree.add(0, "第二层右字节点", false);
tree.add(2, "第三层右子节点", false);
tree.add(6, "第四层右子节点", false);
System.out.println(tree);
//[根, null, 第二层右字节点, null, null, null, 第三层右子节点, null, null, null, null, null, null, null, 第四层右子节点]
// 可以看出空间有很大的浪费
}

}

/**
 * 2.二叉树链表存储实现 每个节点都能记住它的left、right两个子节点,为每个节点添加left/right俩个指针,分别引用left、right俩个子节点
 * 
 * @author mk
 * 
 * @param <E>
 */
class LinkBinTree<E>
{
// 二叉树中的节点
public static class TreeNode<T>
{
private T data;// 节点数据
private TreeNode<T> left, right;// 记录引用当前节点的左右子节点

public TreeNode(T data)
{
this.data = data;
}

public TreeNode(T data, TreeNode<T> left, TreeNode<T> right)
{
this.data = data;
this.left = left;
this.right = right;
}

private TreeNode(){}

@Override
public String toString()
{
return "LinkBinTree$TreeNode[data=" + data + ", left=" + left
+ ", right=" + right + "]";
}
}

private TreeNode<E> root;// 根节点

// 以默认构造器创建二叉树
public LinkBinTree()
{
this.root = new TreeNode<E>();
}

// 以指定元素创建二叉树
public LinkBinTree(E data)
{
this.root = new TreeNode<E>(data);
}

/**
* 给指定节点添加子节点

* @param parent
*            指定的父节点
* @param data
*            新添加的子节点
* @param left
*            是否为左子节点
*/
public TreeNode<E> addNode(TreeNode<E> parent, E data, boolean left)
{
if (parent == null)
throw new RuntimeException("节点为null,无法添加");

if (left && parent.left != null)
throw new RuntimeException("左子节点已满,无法添加");

if (!left && parent.right != null)
throw new RuntimeException("右子节点已满,无法添加");

TreeNode<E> newNode = new TreeNode<E>(data);// 创建新的子节点
if (left)
parent.left = newNode;
else
parent.right = newNode;

return newNode;
}

// 判断二叉树是否为空
public boolean empty()
{
return root.data == null;
}

// 返回根节点
public TreeNode<E> root()
{
if (empty())
throw new RuntimeException("该树为空!");
return root;
}

// 返回指定节点(非叶子节点)左子节点
public TreeNode<E> leftChild(TreeNode<E> parent)
{
if (parent == null)
throw new RuntimeException("节点为null");
return parent.left == null ? null : parent.left;
}

// 返回指定节点(非叶子节点)右子节点
public TreeNode<E> rightChild(TreeNode<E> parent)
{
if (parent == null)
throw new RuntimeException("节点为null");
return parent.right == null ? null : parent.right;
}

// 返回二叉树的深度
public int deep()
{
return deep(root);
}

private int deep(TreeNode<E> node)
{
if (node == null) return 0;
if (node.left == null && node.right == null) return 1;
else
{
int left = deep(node.left), right = deep(node.right);
int max = left > right ? left : right;
return max+1;
}
}

public static void main(String[] args)
{
LinkBinTree<String> tree = new LinkBinTree<String>("root");
LinkBinTree.TreeNode<String> t1 = tree.addNode(tree.root(), "第二层左子节点",
true);
LinkBinTree.TreeNode<String> t2 = tree.addNode(tree.root(), "第二层右子节点",
false);
LinkBinTree.TreeNode<String> t3 = tree.addNode(t2, "第三层左子节点", true);
LinkBinTree.TreeNode<String> t4 = tree.addNode(t2, "第三层右子节点", false);
LinkBinTree.TreeNode<String> t5 = tree.addNode(t3, "第四层左子节点", true);
System.out.println("t2的左子节点: " + tree.leftChild(t2));
System.out.println("t2的右子节点: " + tree.leftChild(t2));
System.out.println("树的深度:" + tree.deep());
}
}

/**
 * 3.由于二叉链表无法搜索父节点,进一步改进为三叉链表,增加父节点的引用
 * 
 * @author mk
 * 
 * @param <E>
 */
class ThreeBinTree<E>
{
public static class TreeNode<T>
{
T data;// 节点数据
TreeNode<T> left, right, parent;// 记录节点的左右、父节点引用

public TreeNode()
{
}

public TreeNode(T data)
{
this.data = data;
}

public TreeNode(T data, TreeNode<T> left, TreeNode<T> right)
{
this(data);
this.left = left;
this.right = right;
}
}

private TreeNode<E> root = null;// 定义树的根节点

public ThreeBinTree()
{
this.root = new TreeNode<E>();// 默认构造器
}

// 以指定节点构造树
public ThreeBinTree(E data)
{
this.root = new TreeNode<E>(data);
}

/**
* 以指定节点添加子节点

* @param data
* @param node
* @param left
*/
public TreeNode<E> addNode(E data, TreeNode<E> parent, boolean left)
{
if (parent == null)
throw new RuntimeException("该节点为null");
if (left && parent.left != null)
throw new RuntimeException("左子节点已满,无法添加");
if (!left && parent.right != null)
throw new RuntimeException("右子节点已满,无法添加");
TreeNode<E> newNode = new TreeNode<E>(data);// 创建新的节点
if (left)
parent.left = newNode;
else
parent.right = newNode;
newNode.parent = parent;
return newNode;
}

public boolean empty()
{
return root.data == null;
}

public TreeNode<E> root()
{
if (empty())
throw new RuntimeException("节点为null");
return root;
}

// 返回节点的深度
public int deep()
{
return deep(root);
}

private int deep(TreeNode<E> node)
{
if (node == null)
return 0;
if (node.left == null && node.right == null)
return 1;
else
{
int left = deep(node.left), right = deep(node.right);
int max = left > right ? left : right;
return max + 1;
}
}
// 返回指定节点(非叶子节点)的左子节点
public TreeNode<E> leftChild(TreeNode<E> parent)
{
if(parent == null)
throw new RuntimeException("该节点为null");
return parent.left == null ? null : parent.left;
}
// 返回指定节点(非叶子节点)的右子节点
public TreeNode<E> rightChild(TreeNode<E> parent)
{
if(parent == null)
throw new RuntimeException("该节点为null");
return parent.right == null ? null : parent.right;
}

// 返回指定节点(非根节点)的父节点
public E parent(TreeNode<E> child)
{
if(child == null)
throw new RuntimeException("该节点为NULL");

return child.parent.data;
}



/**对于二叉树的遍历就是将非线性结构的每个节点排列在线性序列上的过程
* <li>如果采用数组形式实现的二叉树,可以采用深度优先就行遍历,分为先、中、后序遍历三种,一般不实用
* <li>如果采用链表结构实现的二叉树,可以采用广度优先就行遍历又称为按层遍历,第一层根节点,第二层2个子节点
* 一次类推
*/

/*
*  先序遍历二叉树
* @return
*/
public List<TreeNode<E>> preIterator()
{
return preIterator(root);
}
private List<TreeNode<E>> preIterator(TreeNode<E> node)
{
List<TreeNode<E>> list = new ArrayList<TreeNode<E>>();
list.add(node);//处理根节点
if(node.left != null)
list.addAll(preIterator(node.left));// 递归处理左子树
if(node.right != null)
list.addAll(preIterator(node.right));// 递归处理右子树
return list;
}
// 中序遍历二叉树
public List<TreeNode<E>> inIterator()
{
return inIterator(root);
}
private List<TreeNode<E>> inIterator(TreeNode<E> node)
{
List<TreeNode<E>> list = new ArrayList<TreeNode<E>>();
if(node.left != null)
list.addAll(preIterator(node.left));// 递归处理左子树
list.add(node);//处理根节点
if(node.right != null)
list.addAll(preIterator(node.right));// 递归处理右子树
return list;
}

// 后序遍历二叉树
public List<TreeNode<E>> posIterator()
{
return posIterator(root);
}
private List<TreeNode<E>> posIterator(TreeNode<E> node)
{
List<TreeNode<E>> list = new ArrayList<TreeNode<E>>();
if(node.left != null)
list.addAll(preIterator(node.left));// 递归处理左子树
if(node.right != null)
list.addAll(preIterator(node.right));// 递归处理右子树
list.add(node);//处理根节点
return list;
}
// 广度优先遍历,常用借助FIFO队列操作
public List<TreeNode<E>> breadthFirst()
{
List<TreeNode<E>> list = new ArrayList<TreeNode<E>>();
Queue<TreeNode<E>> queue = new ArrayDeque<TreeNode<E>>();
if(root != null) queue.offer(root);
while(!queue.isEmpty())
{
// 将该队列的队尾元素添加到队列中
list.add(queue.peek());
TreeNode<E> node = queue.poll();
if(node.left != null)
queue.offer(node.left);
if(node.right != null)
queue.offer(node.right);
}
return list;
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值