数据结构06之树形结构
树形结构拥有,有序数组和链表的所有优点,在树形结构中查找数据和在数组中一样快,在树形结构中插入数据和链表中一样简单!树是由链接和节点组成的!
根:一棵树只有一个根!
路径:从一个节点到另一个节点,所经过节点的顺序排列称为路径!
父节点:每一个节点都恰好有一条边向上链接到一个点,称为父节点!在树形结构中不能一个节点拥有两个父节点!那就不是树了!
子节点:每一个节点都可能有一个或多个向下的节点,称为子节点!父节点还是子节点都是相对的!
叶节点 :没有子节点的节点称之为叶节点!
层: 一个节点的层是指从根开始到这个节点有多少”代“,
子树:每个节点都可以当做子树的根,他和她所有的子节点都含在子树中就想家族中的那样,一个根节点包含所有的子孙!但是这个根却是另一个树的子节点!
遍历:遍历树的意思是指按照特定顺序访问每一个节点,有三种简单遍历树的方法,前序、中序、后序!最常用的是中序!不管什么序遍历访问每一个节点就行!
二叉树是一种特殊的树形结构,也就是每个节点最多有两个分支,普通的树里面可能会有更多的节点称为多路树!
用数组标示树:
定义节点:
{
int iData; // data used as key value
double dData; // other data
Node leftChild; // this Node's left child
Node rightChild; // this Node's right child
public void displayNode()
{
// (see Listing 8.1 for method body)
System.out.print("{" + iData + ", " + dData + "} ");
}
}
二叉树............
private Node root; // the only data field in Tree
public Node find(int key) // find Node with given key
{ // (assumes non-empty tree)
Node current = root; // start at root
while (current.iData != key) // while no match,
{
if (key < current.iData) // go left?
current = current.leftChild;
else
current = current.rightChild; // or go right?
if (current == null) // if no child,
return null; // didn't find it
}
return current; // found it
}
public Node minimum() // returns Node with minimum key value
{
Node current, last = null;
current = root; // start at root
while (current != null) // until the bottom,
{
last = current; // remember Node
current = current.leftChild; // go to left child
}
return last;
}
public void insert(int id, double dd) {
Node newNode = new Node(); // make new Node
newNode.iData = id; // insert data
newNode.dData = dd;
if (root == null) // no Node in root
root = newNode;
else // root occupied
{
Node current = root; // start at root
Node parent;
while (true) // (exits internally)
{
parent = current;
if (id < current.iData) // go left?
{
current = current.leftChild;
if (current == null) // if end of the line,
{ // insert on left
parent.leftChild = newNode;
return;
}
} // end if go left
else // or go right?
{
current = current.rightChild;
if (current == null) // if end of the line
{ // insert on right
parent.rightChild = newNode;
return;
}
} // end else go right
} // end while
} // end else not root
} // end insert()
public boolean delete(int key) // delete Node with given key
{ // (assumes non-empty list)
Node current = root;
Node parent = root;
boolean isLeftChild = true;
while (current.iData != key) // search for Node
{
parent = current;
if (key < current.iData) // go left?
{
isLeftChild = true;
current = current.leftChild;
} else // or go right?
{
isLeftChild = false;
current = current.rightChild;
}
if (current == null) // end of the line,
return false; // didn't find it
} // end while
// found Node to delete
// continues...
// delete() continued...
// if no children, simply delete it
if (current.leftChild == null && current.rightChild == null) {
if (current == root) // if root,
root = null; // tree is empty
else if (isLeftChild)
parent.leftChild = null; // disconnect
else
// from parent
parent.rightChild = null;
}
// continues...
// delete() continued...
// if no right child, replace with left subtree
else if (current.rightChild == null)
if (current == root)
root = current.leftChild;
else if (isLeftChild) // left child of parent
parent.leftChild = current.leftChild;
else
// right child of parent
parent.rightChild = current.leftChild;
// if no left child, replace with right subtree
else if (current.leftChild == null)
if (current == root)
root = current.rightChild;
else if (isLeftChild) // left child of parent
parent.leftChild = current.rightChild;
else
// right child of parent
parent.rightChild = current.rightChild;
// continued...
// delete() continued
else // two children, so replace with inorder successor
{
// get successor of Node to delete (current)
Node successor = getSuccessor(current);
// connect parent of current to successor instead
if (current == root)
root = successor;
else if (isLeftChild)
parent.leftChild = successor;
else
parent.rightChild = successor;
// connect successor to current's left child
successor.leftChild = current.leftChild;
} // end else two children
// (successor cannot have a left child)
return true;
} // end delete()
public void printTree() {
System.out.print("前序遍历:");
preOrder(root);
System.out.println();
System.out.print("中序遍历:");
inOrder(root);
System.out.println();
System.out.print("后序遍历:");
postOrder(root);
System.out.println();
}
// returns Node with next-highest value after delNode
// goes to right child, then right child's left descendants
private Node getSuccessor(Node delNode) {
Node successorParent = delNode;
Node successor = delNode;
Node current = delNode.rightChild; // go to right child
while (current != null) // until no more
{ // left children,
successorParent = successor;
successor = current;
current = current.leftChild; // go to left child
}
// if successor not
if (successor != delNode.rightChild) // right child,
{ // make connections
successorParent.leftChild = successor.rightChild;
successor.rightChild = delNode.rightChild;// ?
}
return successor;
}
private void preOrder(Node localRoot) {
if (localRoot != null) {
localRoot.displayNode();
preOrder(localRoot.leftChild);
preOrder(localRoot.rightChild);
}
}
private void inOrder(Node localRoot) {
if (localRoot != null) {
inOrder(localRoot.leftChild);
localRoot.displayNode();
inOrder(localRoot.rightChild);
}
}
private void postOrder(Node localRoot) {
if (localRoot != null) {
postOrder(localRoot.leftChild);
postOrder(localRoot.rightChild);
localRoot.displayNode();
}
}
public static void main(String[] args)
{
Tree theTree = new Tree(); // make a tree
theTree.insert(50, 1.5); // insert 3 Nodes
theTree.insert(25, 1.7);
theTree.insert(75, 1.9);
Node found = theTree.find(25); // find Node with key 25
if(found != null)
System.out.println("Found the Node with key 25");
else
System.out.println("Could not find node with key 25");
//theTree.minimum().displayNode();
theTree.printTree();
System.out.println("删除后...");
theTree.delete(25);
theTree.printTree();
} // end main()
}
红黑树............
红黑树很好的解决了二叉树搜索难的问题!
红黑规则:
根节点是黑色
子节点不是黑色就是红色
如果节点是红色则子节点必须是黑色
从根节点到叶节点的每条路径必须包含相同数目的黑节点
public class RedBlackTree<T extends Comparable>
{
//定义红黑树的颜色
private static final boolean RED = false;
private static final boolean BLACK = true;
static class Node
{
Object data;
Node parent;
Node left;
Node right;
//节点的默认颜色是黑色
boolean color = BLACK;
public Node(Object data , Node parent
, Node left , Node right)
{
this.data = data;
this.parent = parent;
this.left = left;
this.right = right;
}
public String toString()
{
return "[data=" + data
+ ", color=" + color + "]";
}
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj.getClass() == Node.class)
{
Node target = (Node)obj;
return data.equals(target.data)
&& color == target.color
&& left == target.left
&& right == target.right
&& parent == target.parent;
}
return false;
}
}
private Node root;
//两个构造器用于创建排序二叉树
public RedBlackTree()
{
root = null;
}
public RedBlackTree(T o)
{
root = new Node(o , null , null , null);
}
//添加节点
public void add(T ele)
{
//如果根节点为null
if (root == null)
{
root = new Node(ele , null , null , null);
}
else
{
Node current = root;
Node parent = null;
int cmp = 0;
//搜索合适的叶子节点,以该叶子节点为父节点添加新节点
do
{
parent = current;
cmp = ele.compareTo(current.data);
//如果新节点的值大于当前节点的值
if (cmp > 0)
{
//以右子节点作为当前节点
current = current.right;
}
//如果新节点的值小于当前节点的值
else
{
//以左子节点作为当前节点
current = current.left;
}
}
while (current != null);
//创建新节点
Node newNode = new Node(ele , parent , null , null);
//如果新节点的值大于父节点的值
if (cmp > 0)
{
//新节点作为父节点的右子节点
parent.right = newNode;
}
//如果新节点的值小于父节点的值
else
{
//新节点作为父节点的左子节点
parent.left = newNode;
}
//维护红黑树
fixAfterInsertion(newNode);
}
}
//删除节点
public void remove(T ele)
{
//获取要删除的节点
Node target = getNode(ele);
//如果被删除节点的左子树、右子树都不为空
if (target.left != null && target.right != null)
{
//找到target节点中序遍历的前一个节点
//s用于保存target节点的左子树中值最大的节点
Node s = target.left;
//搜索target节点的左子树中值最大的节点
while (s.right != null)
{
s = s.right;
}
//用s节点来代替p节点
target.data = s.data;
target = s;
}
//开始修复它的替换节点,如果该替换节点不为null
Node replacement = (target.left != null ? target.left : target.right);
if (replacement != null)
{
// 让replacement的parent指向target的parent
replacement.parent = target.parent;
//如果target的parent为null,表明target本身是根节点
if (target.parent == null)
{
root = replacement;
}
//如果target是其父节点的左子节点
else if (target == target.parent.left)
{
//让target的父节点left指向replacement
target.parent.left = replacement;
}
//如果target是其父节点的右子节点
else
{
//让target的父节点right指向replacement
target.parent.right = replacement;
}
//彻底删除target节点
target.left = target.right = target.parent = null;
// 修复红黑树
if (target.color == BLACK)
{
fixAfterDeletion(replacement);
}
}
//target本身是根节点
else if (target.parent == null)
{
root = null;
}
else
{
//target没有子节点,把它当成虚的替换节点。
//修复红黑树
if (target.color == BLACK)
{
fixAfterDeletion(target);
}
if (target.parent != null)
{
//如果target是其父节点的左子节点
if (target == target.parent.left)
{
//将target的父节点left设为null
target.parent.left = null;
}
//如果target是其父节点的右子节点
else if (target == target.parent.right)
{
//将target的父节点right设为null
target.parent.right = null;
}
//将target的parent设置null
target.parent = null;
}
}
}
//根据给定的值搜索节点
public Node getNode(T ele)
{
//从根节点开始搜索
Node p = root;
while (p != null)
{
int cmp = ele.compareTo(p.data);
//如果搜索的值小于当前p节点的值
if (cmp < 0)
{
//向左子树搜索
p = p.left;
}
//如果搜索的值大于当前p节点的值
else if (cmp > 0)
{
//向右子树搜索
p = p.right;
}
else
{
return p;
}
}
return null;
}
//广度优先遍历
public List<Node> breadthFirst()
{
Queue<Node> queue = new ArrayDeque<Node>();
List<Node> list = new ArrayList<Node>();
if( root != null)
{
//将根元素入“队列”
queue.offer(root);
}
while(!queue.isEmpty())
{
//将该队列的“队尾”的元素添加到List中
list.add(queue.peek());
Node p = queue.poll();
//如果左子节点不为null,将它入“队列”
if(p.left != null)
{
queue.offer(p.left);
}
//如果右子节点不为null,将它入“队列”
if(p.right != null)
{
queue.offer(p.right);
}
}
return list;
}
//插入节点后修复红黑树
private void fixAfterInsertion(Node x)
{
x.color = RED;
//直到x节点的父节点不是根,且x的父节点不是红色
while (x != null && x != root
&& x.parent.color == RED)
{
//如果x的父节点是其父节点的左子节点
if (parentOf(x) == leftOf(parentOf(parentOf(x))))
{
//获取x的父节点的兄弟节点
Node y = rightOf(parentOf(parentOf(x)));
//如果x的父节点的兄弟节点是红色
if (colorOf(y) == RED)
{
//将x的父节点设为黑色
setColor(parentOf(x), BLACK);
//将x的父节点的兄弟节点设为黑色
setColor(y, BLACK);
//将x的父节点的父节点设为红色
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
}
//如果x的父节点的兄弟节点是黑色
else
{
//如果x是其父节点的右子节点
if (x == rightOf(parentOf(x)))
{
//将x的父节点设为x
x = parentOf(x);
rotateLeft(x);
}
//把x的父节点设为黑色
setColor(parentOf(x), BLACK);
//把x的父节点的父节点设为红色
setColor(parentOf(parentOf(x)), RED);
rotateRight(parentOf(parentOf(x)));
}
}
//如果x的父节点是其父节点的右子节点
else
{
//获取x的父节点的兄弟节点
Node y = leftOf(parentOf(parentOf(x)));
//如果x的父节点的兄弟节点是红色
if (colorOf(y) == RED)
{
//将x的父节点设为黑色。
setColor(parentOf(x), BLACK);
//将x的父节点的兄弟节点设为黑色
setColor(y, BLACK);
//将x的父节点的父节点设为红色
setColor(parentOf(parentOf(x)), RED);
//将x设为x的父节点的节点
x = parentOf(parentOf(x));
}
//如果x的父节点的兄弟节点是黑色
else
{
//如果x是其父节点的左子节点
if (x == leftOf(parentOf(x)))
{
//将x的父节点设为x
x = parentOf(x);
rotateRight(x);
}
//把x的父节点设为黑色
setColor(parentOf(x), BLACK);
//把x的父节点的父节点设为红色
setColor(parentOf(parentOf(x)), RED);
rotateLeft(parentOf(parentOf(x)));
}
}
}
//将根节点设为黑色
root.color = BLACK;
}
//删除节点后修复红黑树
private void fixAfterDeletion(Node x)
{
//直到x不是根节点,且x的颜色是黑色
while (x != root && colorOf(x) == BLACK)
{
//如果x是其父节点的左子节点
if (x == leftOf(parentOf(x)))
{
//获取x节点的兄弟节点
Node sib = rightOf(parentOf(x));
//如果sib节点是红色
if (colorOf(sib) == RED)
{
//将sib节点设为黑色
setColor(sib, BLACK);
//将x的父节点设为红色
setColor(parentOf(x), RED);
rotateLeft(parentOf(x));
//再次将sib设为x的父节点的右子节点
sib = rightOf(parentOf(x));
}
//如果sib的两个子节点都是黑色
if (colorOf(leftOf(sib)) == BLACK
&& colorOf(rightOf(sib)) == BLACK)
{
//将sib设为红色
setColor(sib, RED);
//让x等于x的父节点
x = parentOf(x);
}
else
{
//如果sib的只有右子节点是黑色
if (colorOf(rightOf(sib)) == BLACK)
{
//将sib的左子节点也设为黑色
setColor(leftOf(sib), BLACK);
//将sib设为红色
setColor(sib, RED);
rotateRight(sib);
sib = rightOf(parentOf(x));
}
//设置sib的颜色与x的父节点的颜色相同
setColor(sib, colorOf(parentOf(x)));
//将x的父节点设为黑色
setColor(parentOf(x), BLACK);
//将sib的右子节点设为黑色
setColor(rightOf(sib), BLACK);
rotateLeft(parentOf(x));
x = root;
}
}
//如果x是其父节点的右子节点
else
{
//获取x节点的兄弟节点
Node sib = leftOf(parentOf(x));
//如果sib的颜色是红色
if (colorOf(sib) == RED)
{
//将sib的颜色设为黑色
setColor(sib, BLACK);
//将sib的父节点设为红色
setColor(parentOf(x), RED);
rotateRight(parentOf(x));
sib = leftOf(parentOf(x));
}
//如果sib的两个子节点都是黑色
if (colorOf(rightOf(sib)) == BLACK
&& colorOf(leftOf(sib)) == BLACK)
{
//将sib设为红色
setColor(sib, RED);
//让x等于x的父节点
x = parentOf(x);
}
else
{
//如果sib只有左子节点是黑色
if (colorOf(leftOf(sib)) == BLACK)
{
//将sib的右子节点也设为黑色
setColor(rightOf(sib), BLACK);
//将sib设为红色
setColor(sib, RED);
rotateLeft(sib);
sib = leftOf(parentOf(x));
}
//将sib的颜色设为与x的父节点颜色相同
setColor(sib, colorOf(parentOf(x)));
//将x的父节点设为黑色
setColor(parentOf(x), BLACK);
//将sib的左子节点设为黑色
setColor(leftOf(sib), BLACK);
rotateRight(parentOf(x));
x = root;
}
}
}
setColor(x, BLACK);
}
//获取指定节点的颜色
private boolean colorOf(Node p)
{
return (p == null ? BLACK : p.color);
}
//获取指定节点的父节点
private Node parentOf(Node p)
{
return (p == null ? null: p.parent);
}
//为指定节点设置颜色
private void setColor(Node p, boolean c)
{
if (p != null)
{
p.color = c;
}
}
//获取指定节点的左子节点
private Node leftOf(Node p)
{
return (p == null) ? null: p.left;
}
//获取指定节点的右子节点
private Node rightOf(Node p)
{
return (p == null) ? null: p.right;
}
/**
* 执行如下转换
* p r
* r p
* q q
*/
private void rotateLeft(Node p)
{
if (p != null)
{
//取得p的右子节点
Node r = p.right;
Node q = r.left;
//将r的左子节点链到p的右节点链上
p.right = q;
//让r的左子节点的parent指向p节点
if (q != null)
{
q.parent = p;
}
r.parent = p.parent;
//如果p已经是根节点
if (p.parent == null)
{
root = r;
}
//如果p是其父节点的左子节点
else if (p.parent.left == p)
{
//将r设为p的父节点的左子节点
p.parent.left = r;
}
else
{
//将r设为p的父节点的右子节点
p.parent.right = r;
}
r.left = p;
p.parent = r;
}
}
/**
* 执行如下转换
* p l
* l p
* q q
*/
private void rotateRight(Node p)
{
if (p != null)
{
//取得p的左子节点
Node l = p.left;
Node q = l.right;
//将l的右子节点链到p的左节点链上
p.left = q;
//让l的右子节点的parent指向p节点
if (q != null)
{
q.parent = p;
}
l.parent = p.parent;
//如果p已经是根节点
if (p.parent == null)
{
root = l;
}
//如果p是其父节点的右子节点
else if (p.parent.right == p)
{
//将l设为p的父节点的右子节点
p.parent.right = l;
}
else
{
//将l设为p的父节点的左子节点
p.parent.left = l;
}
l.right = p;
p.parent = l;
}
}
//实现中序遍历
public List<Node> inIterator()
{
return inIterator(root);
}
private List<Node> inIterator(Node node)
{
List<Node> list = new ArrayList<Node>();
//递归处理左子树
if (node.left != null)
{
list.addAll(inIterator(node.left));
}
//处理根节点
list.add(node);
//递归处理右子树
if (node.right != null)
{
list.addAll(inIterator(node.right));
}
return list;
}
public static void main(String[] args)
{
RedBlackTree<Integer> tree
= new RedBlackTree<Integer>();
//添加节点
tree.add(5);
tree.add(20);
tree.add(10);
tree.add(3);
tree.add(8);
tree.add(15);
tree.add(30);
System.out.println(tree.breadthFirst());
//删除节点
tree.remove(20);
System.out.println(tree.breadthFirst());
// System.out.println(tree.inIterator());
}
}