一、树的优点:
1. 像链表一样快速的插入和删除。
2. 像有序数组一样快速查找。
二、二叉树概念
1. 路径:一个节点到另一个节点,所经过的节点顺序排列后,就是“路径”。
2. 根:一个树只有一个“根”,也就是树的入口节点。
3. 父节点:每个节点只能有一个父节点。
4. 子节点:每个节点的子节点数目可以是0、1、2,最少0个,最多两个。
5. 叶节点:没有子节点的节点称为“页节点”,这个节点可能是树的最后一层。
6. 子树:每个节点都可以是“子树”的根,它和它所有的子节点构成了“子树”。
7. 层:假设根节点是0层,它的子节点就是1层,依次类推。
三、二叉树的特性
1. 在二叉树的第k层上,最多有2k-1 个结点。
2. 深度为m的二叉树最多有个2m-1个结点。
3. 在任意一棵二叉树中,度数为0的结点(即叶子结点)总比度为2的结点多一个。
4. 具有n个结点的二叉树,其深度至少为[log2n]+1
四、时间复杂度
O(logN)
五、代码
代码有三个类:Node.java(树的节点)、BinaryTree.java(二叉树)、BinaryTreeApp.java(测试类,包含main方法)。
代码清单:
1. Node.java(树的节点)
package org.fizz.ocup.dataStructure.tree.binaryTree;
/**
* 树的节点
* @author zz
*
*/
public class Node {
public int id;
public double data;
public Node leftNode;
public Node rightNode;
public void dispalyNode(){
System.out.print("{" + id +", " + data + "} ");
}
}
2. BinaryTree.java(二叉树)
package org.fizz.ocup.dataStructure.tree.binaryTree;
import java.util.Stack;
/**
* 二叉树
* @author zz
*
*/
public class BinaryTree {
private Node root;
/**
* 查找并返回id相同的node,若未找到返回null
* @param id
* @return Node
*/
public Node find(int id){
Node current = root;
while(current.id != id){
if(current.id < id){//当前节点的id小于查找的id,则去右边找,反之去左边找
current = current.rightNode;
}else{
current = current.leftNode;
}
if(current == null){//如果current为空,说明没有找到id相同的数据项,返回空
return null;
}
}
return current;
}
/**
* 插入一个节点
* @param id
* @param data
*/
public void insert(int id, double data){
Node newNode = new Node();
newNode.id = id;
newNode.data = data;
if(root == null){
root = newNode;
}else{
Node current = root;
Node parent;
while(true){
parent = current;
if(id < current.id){
current = current.leftNode;
if(current == null){
parent.leftNode = newNode;
return;
}
}else{
current = current.rightNode;
if(current == null){
parent.rightNode = newNode;
return;
}
}
}
}
}
/**
* 根据id删除一个节点
* @param id
* @return boolean
*/
public boolean delete(int id){
Node current = root;
Node parent = root;
boolean isLeftNode = false;
while(current.id != id){
parent = current;
if(id < current.id){
isLeftNode = true;
current = current.leftNode;
}else{
isLeftNode = false;
current = current.rightNode;
}
if(current == null){//未找到,直接返回null
return false;
}
}//以上为:找到要删除的节点
//current 是当前节点(也就是要删除的节点)
if(current.leftNode == null && current.rightNode == null){//如果current没有子节点的情况
if(current == root){
root = null;
}else if(isLeftNode){
parent.leftNode = null;
}else{
parent.rightNode = null;
}
}else if(current.leftNode == null){//current 左子节点为空,右子节点不为空
if(current == root){
root = current.rightNode;
}else if(isLeftNode){
parent.leftNode = current.rightNode;
}else{
parent.rightNode = current.rightNode;
}
}else if(current.rightNode == null){//current 右子节点为空,左子节点不为空
if(current == root){
root = current.leftNode;
}else if(isLeftNode){
parent.leftNode = current.leftNode;
}else{
parent.rightNode = current.leftNode;
}
}else{//current 左和右子节点都不为空
Node delNode = current;
Node successor = getSuccessor(delNode);
if(current == root){
root = successor;
}else if(isLeftNode){
parent.leftNode = successor;
}else{
parent.rightNode = successor;
}
successor.leftNode = delNode.leftNode;
}
return true;
}
/**
* 获得将要删除的节点的继承者节点</br>
* 默认将该节点的右子节点的最左端节点 作为该节点的继承者
* @param delNode
* @return Node
*/
private Node getSuccessor(Node delNode){
Node successorParent = delNode;//继承者的父级
Node successor = delNode;//继承者
Node current = delNode.rightNode;//从该节点的右子节点开始找其最左端的子节点
while(current != null){
successorParent = successor;
successor = current;
current = current.leftNode;
}
if(successor != delNode.rightNode){//如果不是该节点的直接右子节点,则做连接
successorParent.leftNode = successor.rightNode;
successor.rightNode = delNode.rightNode;
}
return successor;
}
/**
* 遍历树
* @param traverseType
*/
public void traverse(int traverseType){
switch(traverseType){
case 1:
System.out.println("前序遍历:");
preorder(root);
break;
case 2:
System.out.println("中序遍历:");
inorder(root);
break;
case 3:
System.out.println("后序遍历:");
postorder(root);
break;
}
}
/**
* 前序遍历
* @param localRoot
*/
private void preorder(Node localRoot){
if(localRoot != null){
System.out.print(localRoot.data + " ");
preorder(localRoot.leftNode);
preorder(localRoot.rightNode);
}
}
/**
* 中序遍历
* @param localRoot
*/
private void inorder(Node localRoot){
if(localRoot != null){
inorder(localRoot.leftNode);
System.out.print(localRoot.data + " ");
inorder(localRoot.rightNode);
}
}
/**
* 后序遍历
* @param localRoot
*/
private void postorder(Node localRoot){
if(localRoot != null){
postorder(localRoot.leftNode);
postorder(localRoot.rightNode);
System.out.print(localRoot.data + " ");
}
}
/**
* 显示树的内容
*/
public void displayTree(){
Stack<Node> globalStack = new Stack<Node>();
globalStack.push(root);
int nBlanks = 32;
boolean isRowEmpty = false;
System.out.println("...................................................");
while(isRowEmpty == false){
Stack<Node> localStack = new Stack<Node>();
isRowEmpty = true;
for(int j=0;j<nBlanks;j++){
System.out.print(" ");
}
while(globalStack.isEmpty() == false){
Node temp = globalStack.pop();
if(temp != null){
System.out.print(temp.id);
localStack.push(temp.leftNode);
localStack.push(temp.rightNode);
if(temp.leftNode != null || temp.rightNode != null){
isRowEmpty = false;
}
}else{
System.out.print("--");
localStack.push(null);
localStack.push(null);
}
for(int j=0;j<nBlanks*2-2;j++)
System.out.print(' ');
}
System.out.println();
nBlanks /= 2;
while(localStack.isEmpty() == false){
globalStack.push(localStack.pop());
}
}
System.out.println("................................................................");
}
}
3. BinaryTreeApp.java(测试类,包含main方法)
package org.fizz.ocup.dataStructure.tree.binaryTree;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class BinaryTreeApp {
public static void main(String[] args) throws Exception {
int value;
BinaryTree bt = new BinaryTree();
bt.insert(66, 6.2);
bt.insert(99, 9.2);
bt.insert(22, 2.2);
bt.insert(00, 0.2);
bt.insert(33, 3.2);
bt.insert(44, 4.2);
bt.insert(11, 1.1);
bt.insert(77, 7.2);
bt.insert(55, 5.2);
bt.insert(88, 8.2);
while(true){
System.out.print("Enter first letter of show, ");
System.out.print("insert,find,delete,or traverse: ");
int choice = getChar();
switch(choice){
case 's':
bt.displayTree();
break;
case 'i':
System.out.print("Enter value to insert: ");
value = getInt();
bt.insert(value, value + 0.9);
break;
case 'f':
System.out.print("Enter value to find: ");
value = getInt();
Node found = bt.find(value);
if(found != null){
System.out.print("Found: ");
found.dispalyNode();
System.out.println();
}else{
System.out.println("Could not find " + value );
}
break;
case 'd':
System.out.print("Enter value to delete: ");
value = getInt();
boolean didDelete = bt.delete(value);
if(didDelete){
System.out.println("Deleted " + value);
}else{
System.out.println("Could not delete " + value);
}
break;
case 't':
System.out.println("Enter type 1,2 or 3: ");
value = getInt();
bt.traverse(value);
break;
default:
System.out.println("Invalid entyr");
}
}
}
private static String getString() throws Exception{
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
return s;
}
private static int getChar() throws Exception{
String s = getString();
return s.charAt(0);
}
public static int getInt() throws Exception{
String s = getString();
return Integer.parseInt(s);
}
}
六、数组的详细操作代码在:
1. github地址:https://github.com/oszz/ocup.git
2. 1.0版本中,包目录为:org.fizz.ocup.dataStructure.tree.binaryTree