顺序统计树

/*
 * 顺序统计树
 */
public class OrderStatisticTree {
	public static final OsTreeNode NIL = new OsTreeNode(RbColor.BLACK,0);
	private OsTreeNode root = null;
	public static void main(String[] args) {
		OrderStatisticTree ost = new OrderStatisticTree();
		//测试插入
		ost.insertOsTreeNode(new OsTreeNode(11,RbColor.BLACK));
		ost.insertOsTreeNode(new OsTreeNode(2,RbColor.RED));
		ost.insertOsTreeNode(new OsTreeNode(1,RbColor.BLACK));
		ost.insertOsTreeNode(new OsTreeNode(7,RbColor.BLACK));
		ost.insertOsTreeNode(new OsTreeNode(5,RbColor.RED));
		ost.insertOsTreeNode(new OsTreeNode(8,RbColor.RED));
		ost.insertOsTreeNode(new OsTreeNode(14,RbColor.BLACK));
		ost.insertOsTreeNode(new OsTreeNode(15,RbColor.RED));
		ost.printTree();
		ost.deleteOsTreeNode(ost.searchOsTreeNode(ost.root, 7));
		ost.printTree();

		//打印第i小的数
		System.out.println(ost.osSelect(ost.root,7).key);
		//找某一节点的序
		System.out.println(ost.osRank(ost.searchOsTreeNode(ost.root, 14)));

	}

	public OrderStatisticTree() {
		this.root = NIL;
	}
	//中序遍历二叉树
	private void traverseTree(OsTreeNode x) {
		if(x != NIL) {
			traverseTree(x.left);
			System.out.println(x.key + " " + x.color + " "+x.size);
			traverseTree(x.right);
		}
	}
	private void printTree() {
		System.out.println("root:"+root.key+" "+root.color);
		traverseTree(root);
		System.out.println();
	}

	//设置顺序统计树每个节点的size
//	private int setOsTreeNodeSize(OSTreeNode x) {
//		if(x == NIL) {
//			return 0;
//		} else {
//			return setOsTreeNodeSize(x.left)+setOsTreeNodeSize(x.right)+1;
//		}
//	}

	//找到第i小关键字的节点
	private OsTreeNode osSelect(OsTreeNode x,int i) {
		if(i<0) {
			System.out.println("invalidate parameter!");
			return null;
		}
		int r = x.left.size+1;
		if(i==r) {
			return x;
		} else if(i<r) {
			return osSelect(x.left,i);
		} else {
			return osSelect(x.right,i-r);
		}
	}

	//找到x节点的序
	private int osRank(OsTreeNode x) {
		int r = x.left.size+1;
		OsTreeNode y=x;
		while(y != root) {
			if(y == y.parent.right) {
				r = r + y.parent.left.size + 1;
			}
			y = y.parent;
		}
		return r;
	}

	//查找某一子节点
	private OsTreeNode searchOsTreeNode(OsTreeNode x,int key) {
		while(x != NIL && key != x.key) {
			if(key < x.key) {
				x = x.left;
			} else {
				x = x.right;
			}
		}
		return x;
	}

	//插入某一子节点
	private void insertOsTreeNode(OsTreeNode z) {
		OsTreeNode y = NIL;
		OsTreeNode x = root;
		while(x != NIL) {
			y = x;
			if(z.key < x.key) {
				x = x.left;
			} else {
				x = x.right;
			}
		}
		z.parent = y;
		if(y == NIL) {
			root = z;
		} else if(z.key < y.key) {
			y.left = z;
		} else {
			y.right = z;
		}
		z.left = NIL;
		z.right = NIL;
		z.color = RbColor.RED;
		//插入后成了叶节点,叶节点size为1
		z.size = 1;
		sizeFixUp(z.parent);
		osInsertFixUp(z);									//插入修正
	}

	//插入修正
	private void osInsertFixUp(OsTreeNode z) {
		OsTreeNode y = null;
		while(z.parent.color == RbColor.RED) {				//当z的父节点是黑色时,不需要矫正
			if(z.parent == z.parent.parent.left) {			//左分支情况
				y = z.parent.parent.right;		//根据叔节点分情况
				if(y.color == RbColor.RED) {
					z.parent.color = RbColor.BLACK;
					y.color = RbColor.BLACK;
					z.parent.parent.color = RbColor.RED;
					z = z.parent.parent;
				} else {
					if(z == z.parent.right) {
						z = z.parent;
						leftRotate(z);
					}
					z.parent.color = RbColor.BLACK;
					z.parent.parent.color = RbColor.RED;
					rightRotate(z.parent.parent);
				}
			} else {
				y = z.parent.parent.left;		//根据叔节点分情况
				if(y.color == RbColor.RED) {
					z.parent.color = RbColor.BLACK;
					y.color = RbColor.BLACK;
					z.parent.parent.color = RbColor.RED;
					z = z.parent.parent;
				} else {
					if(z == z.parent.left) {
						z = z.parent;
						rightRotate(z);
					}
					z.parent.color = RbColor.BLACK;
					z.parent.parent.color = RbColor.RED;
					leftRotate(z.parent.parent);
				}
			}
		}
		root.color = RbColor.BLACK;
	}

	//删除某一子节点
	private void deleteOsTreeNode(OsTreeNode z) {
		OsTreeNode y = z;
		OsTreeNode x = NIL;
		RbColor yOriginalColor = y.color;
		if(z.left == NIL) {
			x = z.right;
			osTransplant(z,z.right);

			z.right.size--;
			sizeFixUp(z.right.parent);			//修复从根节点到z节点路径的size
		} else if(z.right == NIL) {
			z.parent.size--;
			sizeFixUp(z.right.parent);
			x = z.left;
			osTransplant(z,z.left);

			z.left.size--;
			sizeFixUp(z.left.parent);			//修复从根节点到z节点路径的size
		} else {
			y = searchMinNode(z.right);
			yOriginalColor = y.color;
			x = y.right;
			if(y.parent == z) {
				x.parent = y;
			} else {
				osTransplant(y,y.right);
				y.right = z.right;
				z.right.parent = y;
			}
			osTransplant(z,y);
			y.left = z.left;
			z.left.parent = y;
			y.color = z.color;

			x.parent.size--;
			sizeFixUp(x.parent.parent);			//修复从根节点到z节点路径的size
		}
		if(yOriginalColor == RbColor.BLACK) {
			osDeleteFixUp(x);
		}
	}

	private void sizeFixUp(OsTreeNode x) {
		OsTreeNode y = x;
		while(y != NIL) {
			y.size = y.left.size + y.right.size + 1;
			y = y.parent;
		}
	}

	private void osDeleteFixUp(OsTreeNode x) {
		//x总是指向一个具有双重黑色的非根节点
		OsTreeNode w = NIL;
		while(x != root && x.color == RbColor.BLACK) {
			if(x == x.parent.left) {
				w = x.parent.right;		//w指向兄节点
				if(w.color == RbColor.RED) {
					w.color = RbColor.BLACK;				//case 1
					x.parent.color = RbColor.RED;			//case 1
					leftRotate(x.parent);					//case 1
					w = x.parent.right;						//case 1
				}
				if(w.left.color == RbColor.BLACK
					&& w.right.color == RbColor.BLACK) {
					w.color = RbColor.BLACK;				//case 2
					x = x.parent;							//case 2
				}
				else {
					if(w.right.color == RbColor.BLACK) {
						w.left.color = RbColor.BLACK;		//case 3
						w.color = RbColor.RED;				//case 3
						rightRotate(w);						//case 3
						w = x.parent.right;					//case 3
					}
					w.color = x.parent.color;				//case 4
					x.parent.color = RbColor.BLACK;			//case 4
					w.right.color = RbColor.BLACK;			//case 4
					leftRotate(x.parent);					//case 4
					x = root;								//case 4
				}
			} else {
				w = x.parent.left;		//w指向兄节点
				if(w.color == RbColor.RED) {
					w.color = RbColor.BLACK;				//case 1
					x.parent.color = RbColor.RED;			//case 1
					rightRotate(x.parent);					//case 1
					w = x.parent.left;						//case 1
				}
				if(w.right.color == RbColor.BLACK
					&& w.left.color == RbColor.BLACK) {
					w.color = RbColor.BLACK;				//case 2
					x = x.parent;							//case 2
				}
				else {
					if(w.left.color == RbColor.BLACK) {
						w.right.color = RbColor.BLACK;		//case 3
						w.color = RbColor.RED;				//case 3
						leftRotate(w);						//case 3
						w = x.parent.left;					//case 3
					}
					w.color = x.parent.color;
					x.parent.color = RbColor.BLACK;
					w.left.color = RbColor.BLACK;
					rightRotate(x.parent);
					x = root;
				}
			}
		}

	}

	private void osTransplant(OsTreeNode u,OsTreeNode v) {
		if(u.parent == NIL) {
			root = v;
		} else if(u == u.parent.left) {
			u.parent.left = v;
		}  else {
			u.parent.right = v;
		}
		v.parent = u.parent;
	}

	//获取最小键值节点
	private OsTreeNode searchMinNode(OsTreeNode x) {
		while(x.left != NIL) {
			x = x.left;
		}
		return x;
	}

	//获取最大键值节点
	private OsTreeNode searchMaxNode(OsTreeNode x) {
		while(x.right != NIL) {
			x = x.right;
		}
		return x;
	}

	//左旋
	private void leftRotate(OsTreeNode x) {
		OsTreeNode y = x.right;
		x.right = y.left;
		if(x.right != NIL) {
			y.left.parent = x;
		}
		y.parent = x.parent;
		if(x.parent == NIL) {			//如果是根节点
			root = y;
		} else if(x == x.parent.left) {
			x.parent.left = y;
		} else {
			x.parent.right = y;
		}
		y.left = x;
		x.parent = y;
		//size属性维护
		y.size = x.size;
		x.size = x.left.size + x.right.size + 1;
	}

	//右旋
	private void rightRotate(OsTreeNode y) {
		OsTreeNode x = y.left;
		y.left = x.right;
		if(x.right != NIL) {
			x.right.parent = y;
		}
		x.parent = y.parent;
		if(y.parent == NIL) {
			root = x;
		} else if(y == y.parent.left) {
			y.parent.left = x;
		} else {
			y.parent.right = x;
		}
		x.right = y;
		y.parent = x;
		//size属性维护
		x.size = y.size;
		y.size = y.left.size + y.right.size + 1;
	}

	//红黑树节点类
	private static class OsTreeNode {
		OsTreeNode left = null;
		OsTreeNode right = null;
		OsTreeNode parent = null;
		RbColor color = RbColor.RED;
		int key = 0;
		int size = 0;

		public OsTreeNode(int key,RbColor color) {
			this.key = key;
			this.color = color;
		}
		public OsTreeNode(RbColor color,int size) {
			this.color = color;
			this.size = size;
		}
	}

	private enum RbColor {
		RED,BLACK
	}
}

时间: 2024-12-24 00:47:44

顺序统计树的相关文章

最大最小值以及前驱后继操作最坏情况都为O(1)的顺序统计树

问题:通过为结点增加指针的方式,试说明如何在扩张的顺序统计树上,支持每一动态集合查询操作MINIMUM,MAXIMUM,SUCCESSOR和PREDECESSOR在最坏时间O(1)内完成.顺序统计树上的其他操作的渐近性能不应受影响. 代码如下: //本程序在原有的红黑树基础上增加了子树结点个数,前驱后继结点以及最大小结点属性. #include <iostream> #include <time.h> using namespace std; #define BLACK 0 #de

完整的C++实现算法导论十三章红黑树以及十四章中的顺序统计树

#include<iostream> using namespace std; class BRTree; class BRTreeNode{ private: friend class BRTree; int key; bool color; int size; BRTreeNode *left; BRTreeNode *right; BRTreeNode *parent; public: //创建一个默认构造函数 BRTreeNode():key(-1),color(0),size(0),

算法导论--动态顺序统计与区间树

本文的基础是红黑树 算法导论–红黑树 通过在基础的数据结构中添加一些附加信息,来扩张一种标准的数据结构,然后编写新的操作来支持所需要的应用.下面是介绍在红黑树的基础上扩张的数据结构. 1.动态顺序统计 动态顺序统计可以在O(lgn)时间内确定任何的顺序统计量(即在n个元素的集合中,能在O(lgn)的时间内确定第i小的元素),同时也可以在O(lgn)的时间内计算一个元素的秩(即它在中序遍历下的位置顺序). 1 添加附加信息 结点x中加入x.size , size的大小为以x为根的子树(包含x本身)

顺序统计:寻找序列中第k小的数

最直观的解法,排序之后取下标为k的值即可. 但是此处采取的方法为类似快速排序分块的方法,利用一个支点将序列分为两个子序列(支点左边的值小于支点的值,支点右边大于等于支点的值). 如果支点下标等于k,则支点就是查找的值,如果支点的下标大于k,则在左子序列里继续寻找,如果支点下标小于k,则继续在支点右子序列里面继续寻找第(k-支点下标)小的值. c#实现算法如下: public class FindSpecialOrderElement<T> where T : IComparable<T&

FZU-2087 统计树边(最小生成树)

Problem 2087 统计树边 Accept: 223    Submit: 693Time Limit: 1000 mSec    Memory Limit : 32768 KB Problem Description 在图论中,树:任意两个顶点间有且只有一条路径的图. 生成树:包含了图中所有顶点的一种树. 最小生成树:对于连通的带权图(连通网)G,其生成树也是带权的.生成树T各边的权值总和称为该树的权,权最小的生成树称为G的最小生成树(Minimum Spanning Tree).最小生

顺序统计:寻找序列中的最大最小数

查找输入序列中的最大最小数值,要求时间复杂度为1.5n C#实现如下: public class MinMaxFinder<T> where T : IComparable<T> { public void FindMinMax(T[] array, int startIndex, int endIndex, out T minValue, out T maxValue) { maxValue = array[startIndex]; minValue = array[startI

zjoi 2008 树的统计——树链剖分

比较基础的一道树链剖分的题 大概还是得说说思路 树链剖分是将树剖成很多条链,比较常见的剖法是按儿子的size来剖分,剖分完后对于这课树的询问用线段树维护--比如求路径和的话--随着他们各自的链向上走,直至他们在同一条链上为止.比较像lca的方法,只不过这里是按链为单位,而且隔壁的SymenYang说可以用树链剖分做lca..吓哭 然后说说惨痛的调题经历:边表一定要开够啊! 不是n-1 而是2*(n-1)啊! 然后写变量时原始值和映射值要搞清楚啊! 不要搞错了! 还有就是下次求最小值一定看清下界是

《对寻找第i个顺序统计的数》一文的研究。

对于寻找第i个顺序统计的数,可以形式的定义如下: 对于这个问题,最原始的方法就是将1~n个数从小到大排序,然后输出第i个数.用快排的话,时间复杂度就是O(nlogn),但是我们其实可以对快速排序进行优化. 快速排序是以二分的思想,对分出的每边进行排序,然而当我们要求第i个数时,知道在快拍的哪一边的时候,我们还需对快排的另一边排序吗?毋庸置疑,这是不用的,所以这就是优化--只对快排的某一边进行处理. 设对A[L..R]进行划分.首先,按照快排的中心思想,选出(l+r) div 2这个元素作为"支点

FZU 2087 统计树边【MST相关】

 Problem 2087 统计树边 Accept: 212    Submit: 651 Time Limit: 1000 mSec    Memory Limit : 32768 KB  Problem Description 在图论中.树:随意两个顶点间有且仅仅有一条路径的图. 生成树:包括了图中全部顶点的一种树. 最小生成树:对于连通的带权图(连通网)G,其生成树也是带权的. 生成树T各边的权值总和称为该树的权,权最小的生成树称为G的最小生成树(Minimum Spanning Tree