import java.util.ArrayList;

public class treemodel {

	/**
	 * 2014.6.10开始写
	 * 
	 * 2014.6.21晚修改
	 * 
	 * 普通树的Java实现
	 * 
	 * 作者:张迪Victorz
	 * 
	 * 参考:李刚《疯狂Java程序员的基本修养》
	 * 
	 * %用一个节点数组保存树里面的节点,并让每个节点记录其父节点所在的组的索引即可(类似于主键和从建)
	 * 
	 * 节点的维护有两种方法
	 * 
	 * 1.维护父节点(找子节点很麻烦) 让每个节点都记住自己的父节点
	 * 
	 * 2.维护子节点,让父节点记住子节点(类似临街链表的方式)
	 * 
	 * 3.针对二叉树,(因为确定了子节点的个数 1 or 2 )采用数组就能实现存储
	 * 
	 * 4.二叉树 还可有二叉树链表存储 【左指针】【数据】【右指针】
	 * 
	 * 5.二叉树 还有进一步的链表存储 【父节点指针】【左指针】【数据】【右指针】
	 * 
	 * %%涉及二叉树的先序遍历 中序遍历 后序遍历
	 * 
	 * 暂时选用链表存储 【父节点指针】【左指针】【数据】【右指针】结构,默认从左插入
	 * 
	 * 
	 * 出现的问题:
	 * 
	 * 1.开始插入的时候由于模糊,只能实现在根节点的插入。后来改为利用标号来插入
	 * 
	 * 2.遍历知识混乱
	 */

	// 节点内部类
	public class Node {
		public Node father;// 父节点// 记录父节点的位置
		public Node leftch;// 左节点
		public Node rightch;// 右节点
		public Object data;// 存储的数据

		// 所有元素的构造方法
		public Node(Node father, Node leftch, Node rightch, Object data) {
			super();
			this.father = father;
			this.leftch = leftch;
			this.rightch = rightch;
			this.data = data;
		}

		// 默认构造方法
		public Node() {

		}

		public Node(Node leftch, Node rightch, Object data) {
			super();
			this.leftch = leftch;
			this.rightch = rightch;
			this.data = data;
		}

		// 构造尾节点
		public Node(Object data, Node father) {
			super();
			this.father = father;
			this.data = data;
		}

	}

	// 一些属性
	private int nodenum;// 节点的个数
	private int height;// 记录树的高度
	private Node root;// 永远指向根节点

	// private Node avli;

	// 初始建立树

	// 一些getter和setter方法
	public int getNodenum() {
		return nodenum;
	}

	public void setNodenum(int nodenum) {
		this.nodenum = nodenum;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	// 默认构造方法
	treemodel() {
		if (root == null) {
			root = new Node(null, null, null, null);
			setHeight(1);// 高度为1
			setNodenum(1);// 设置节点为1
		}
	}

	treemodel(Object data) {
		if (root == null) {
			root = new Node(null, null, data);
			setHeight(1);// 高度为1
			setNodenum(1);// 设置节点为1
		}
	}

	// 构造方法以指定的根节点和内容来创建树
	treemodel(Node speroot, Object data) {
		// 找到这个根节点,返回根节点

		try {
			Node node = find(speroot);
			if (node != null) {
				// 插入节点
				add(data, node);

			} else {
				throw new Exception("没找到相关的根节点");
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());

		}

		// 然后在这个根结点处插入相关的节点

	}

	// 为指定节点添加子节点(在father的节点插入节点,数据为data,默认从左面插入)
	public void add(Object data, Node father) {
		try {
			// 查找这个根节点是否存在

			if (!ishasrightnode(father)) {
				// 插入左节点
				father.leftch = new Node(father, null, null, data);
				nodenum++;
				height = (int) Math.floor(nodenum / 2) + 1;
			} else if (!isfull(father)) {
				// 插入右节点
				father.rightch = new Node(father, null, null, data);
				nodenum++;
				height = (int) Math.floor(nodenum / 2) + 1;
			} else {
				throw new Exception("对不起,此根节点不能插入");
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}

	}

	// 判断节点是否有左节点
	public boolean ishasrightnode(Node node) {
		boolean flag = false;
		if (node.leftch != null) {
			flag = true;
		}
		return flag;
	}

	// 判断给定根节点是否两个子节点都被占满
	public boolean isfull(Node node) {
		boolean flag = false;
		if (node.leftch != null && node.rightch != null) {
			flag = true;
		}
		return flag;
	}

	// 判断树是否为空
	public boolean isEmpty() {
		return nodenum == 1;
	}

	// 返回根节点函数
	public Node getRoot() {
		return root;
	}

	// 查找并返回特定的节点
	// 遍历节点开始寻找
	// 递归调用
	public Node find(Node node) {
		System.out.println(node.data);

		Node t = getRoot();
		find(t.leftch);
		find(t.rightch);
		if (t.data == node.data && t.leftch == node.leftch
				&& t.rightch == node.rightch) {
			return t;

		}
		return null;
	}

	// 主要用于查找插入的地方,用于编号
	public Node find2(int location) {
		Node ro = getRoot();
		try {
			if (location > nodenum) {
				throw new Exception("超出范围");
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		for (int i = 1; i <= location;) {
			if (ro.leftch != null) {
				ro = ro.leftch;
				i++;
			} else if (ro.rightch != null) {
				ro = ro.rightch;
				i++;
			} else {
				ro = ro.father;
			}
		}
		return ro;

	}

	// 删除相关的节点

	public void delete(Node node) { // 找到这个点,如果有子节点,顺便把节点删下去
		if (node == null) {
			return;
		}
		delete(node.leftch);
		delete(node.rightch);

		{
			node.data = null;
			node.leftch = null;
			node.rightch = null;
			if (leftorright(node).equals("left")) {
				node.father.leftch = null;
			} else {
				node.father.rightch = null;
			}
		}

	}

	// 判断节点是其父节点的左节点还是右节点
	public String leftorright(Node node) {
		if (node.father.leftch == node) {
			return "left";
		} else {
			return "right";
		}

	}

	// 修改相关的节点
	public void update(int i, Object data) {
		Node spe = find2(i);
		spe.data = data;

	}

	// 返回指定节点的父节点
	public Node returnfathernode(Node node) {
		return node.father;

	}

	// 返回树的高度
	public int height() {
		return height;
	}

	// 返回包含指定值的节点
	public ArrayList<Node> returnNodes(Object data) {
		ArrayList<Node> list = new ArrayList<Node>();
		Node t = getRoot();
		find(t.leftch);// 左递归
		find(t.rightch);// 右递归
		if (t.data == data) {
			list.add(t);// 将有特定值的点放入到线性表中
		}
		return list;
	}

	// 遍历所有树中的节点,用于查找和核对
	public void showall(Node cur) {

		// 采用先序序列遍历树(也可采用中序和后序)

		if (cur == null) {
			return;
		}
		System.out.println(cur.data);
		showall(cur.leftch);
		showall(cur.rightch);

	}

}