|
前面我们说了二叉树前序中序后序遍历的递归非递归算法的实现,下面我们再来说说二叉搜索树~
二叉排序树分为静态查找(find)和动态查找(insert、delete) 二叉搜索树:一棵二叉树,可以为空;如果不为空,满足下列性质: 1.非空左子树的所有键值小于其根结点的键值。 2.非空右子树的所有键值大于其根结点的键值 3.左右子树都是二叉搜索树!!
2.以上是二叉搜索树(也叫二叉排序树)的一些基本操作,此处我们先说一下二叉树的结点定义??
代码中判断当前结点位置情况的辅助方法以及简单的 get 方法都在常数时间内可以完成,实现也相应非常简单。下面主要讨论 updateHeight ()、 updateSize ()、 sever()、setLChild(lc)、 getRChild(rc)的实现与时间复杂度。
1)<??http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPgo8c3Ryb25nPiAgICAvLyC4/NDCtbHHsL3hteO8sMbk1+bPyLXEuN+2yDwvc3Ryb25nPgo8c3Ryb25nPnB1YmxpYyB2b2lkIHVwZGF0ZUhlaWdodCgpIHs8L3N0cm9uZz4KPHN0cm9uZz4gICAgaW50IG5ld0ggPSAwOy8vINDCuN+2yLP1yry7r86qIDAsuN+2yLXI09rX89PS19PK97jftsi80yAxINbQtcS089XfPC9zdHJvbmc+CjxzdHJvbmc+ICAgIGlmIChoYXNMQ2hpbGQoKSk8L3N0cm9uZz4KPHN0cm9uZz4gICAgICAgIG5ld0ggPSBNYXRoLm1heChuZXdILCAxICYjNDM7IGdldExDaGlsZCgpLmdldEhlaWdodCgpKTsvL7e1u9jBvdXf1tC9z7TztcTSu7j2PC9zdHJvbmc+CjxzdHJvbmc+ICAgIGlmIChoYXNSQ2hpbGQoKSk8L3N0cm9uZz4KPHN0cm9uZz4gICAgICAgIG5ld0ggPSBNYXRoLm1heChuZXdILCAxICYjNDM7IGdldFJDaGlsZCgpLmdldEhlaWdodCgpKTs8L3N0cm9uZz4KPHN0cm9uZz4gICAgaWYgKG5ld0ggPT0gaGVpZ2h0KTwvc3Ryb25nPgo8c3Ryb25nPiAgICAgICAgcmV0dXJuOyAvLyC437bIw7vT0Leiyfqx5Luv1PLWsb3Tt7W72Dwvc3Ryb25nPgo8c3Ryb25nPiAgICBoZWlnaHQgPSBuZXdIOyAvLyC38dTyuPzQwrjftsg8L3N0cm9uZz4KPHN0cm9uZz4gICAgaWYgKGhhc1BhcmVudCgpKTwvc3Ryb25nPgo8c3Ryb25nPiAgICAgICAgZ2V0UGFyZW50KCkudXBkYXRlSGVpZ2h0KCk7IC8vILXduem4/NDC1+bPyLXEuN+2yDwvc3Ryb25nPgo8c3Ryb25nPn08L3N0cm9uZz4KPHN0cm9uZz51cGRhdGVIZWlnaHQgKCmjusj0tbHHsL3hteMgdiC1xLqi19O3osn6seS7r6Osvs3Q6NKqyrnTwyB1cGRhdGVIZWlnaHQKICgpt723qLj80MK1scewveG147ywxuTX5s/IveG147XEuN+2yKGjx+vXotLio6zTydPa0ru49r3hteO1xLjftsi3osn6seS7r6Osu+HTsM/stb3G5Nfmz8i94bXjtcS437bIo6zU2tXiwO/O0sPH1MrQ7daxvdO21MjOus694bXj1rTQ0NXi0ruy2df3oaPS8s6q1Nq2/rLmyvfW0MjOus7Su7j2veG147XEuN+2yKOstry1yNPaxuTX89PS19PK97XEuN+2yNbQtPPV37zTIDGjrLb41/PT0tfTyve1xLjftsjWu9Do0qq78cihuMO94bXj1/PT0rqi19O1xLjftsijrNa70OjSqqaoICgxKcqxvOSho7zMtvi00yB2ILP2t6LR2HBhcmVudCDS/dPDxObQ0M/yyc+jrNLAtM64/NDCuPfX5s/IveG147XEuN+2yLy0v8mho8jnufvU2snPyva5/bPM1tCjrLeiz9bEs7j2veG147XEuN+2yMO709C3osn6seS7r6Osy+O3qL/J0tTWsb3T1tXWuaGj19vJz8v5yvajrLWxttTSu7j2veG14yB2ILX308MgdXBkYXRlSGVpZ2h0CiAoKbe9t6jKsaOsyPQgdiC1xLLjyv3OqiBsZXZlbCh2KaOs1PLX7rbg1rvQ6NKquPzQwiBsZXZlbCh2KSYjNDM7MSC49r3hteO1xLjftsijrNLytMvL47eotcTKsbzkuLTU07bIIFQobikKID0gpq8gKGxldmVsKHYpKaGjPC9zdHJvbmc+CjxzdHJvbmc+ICAgIDKjqSA8L3N0cm9uZz4KPHN0cm9uZz4gICAgLy8KILj80MK1scewveG147ywxuTX5s/ItcTX08vvyv08L3N0cm9uZz4KPHN0cm9uZz5wdWJsaWMgdm9pZCB1cGRhdGVTaXplKCkgezwvc3Ryb25nPgo8c3Ryb25nPiAgICBzaXplID0gMTsgLy8KILP1yry7r86qIDEsveG147G+ye08L3N0cm9uZz4KPHN0cm9uZz4gICAgaWYgKGhhc0xDaGlsZCgpKTwvc3Ryb25nPgo8c3Ryb25nPiAgICAgICAgc2l6ZSAmIzQzOz0gZ2V0TENoaWxkKCkuZ2V0U2l6ZSgpOyAvLwogvNPJz9fz19PK97nmxKM8L3N0cm9uZz4KPHN0cm9uZz4gICAgaWYgKGhhc1JDaGlsZCgpKTwvc3Ryb25nPgo8c3Ryb25nPiAgICAgICAgc2l6ZSAmIzQzOz0gZ2V0UkNoaWxkKCkuZ2V0U2l6ZSgpOyAvLwogvNPJz9PS19PK97nmxKM8L3N0cm9uZz4KPHN0cm9uZz4gICAgaWYgKGhhc1BhcmVudCgpKTwvc3Ryb25nPgo8c3Ryb25nPiAgICAgICAgZ2V0UGFyZW50KCkudXBkYXRlU2l6ZSgpOyAvLwogtd256bj80MLX5s/ItcS55sSjPC9zdHJvbmc+CjxzdHJvbmc+fTwvc3Ryb25nPgo8c3Ryb25nPnVwZGF0ZVNpemUKICgpo7rNrNH5yOe5+73hteMgdiC1xLqi19O3osn6seS7r6Os06a4w7j80MK1scewveG149LUvLDG5Nfmz8i1xLnmxKOho9LyzqrU2rb+subK99bQyM66ztK7uPa94bXjtcS55sSjo6y2vLXI09rG5Nfz09LX08r3tcS55sSj1q66zbzTyc+94bXj19TJ7aOstvjX89PS19PK97XEuebEo9a70OjSqrvxyKG4w73htePX89PSuqLX07XEuebEo7y0v8m78bXDo6zWu9Do0qqmqCAoMSnKsbzkoaPS8rTLy+O3qLXEyrG85Li01NO2yCBUKG4pCiA9IKavIChsZXZlbCh2KSmhozxicj4KICAgIDOjqTwvc3Ryb25nPgo8c3Ryb25nPiAKICAgLy8gts+/qtPruLjH17XEudjPtTwvc3Ryb25nPgo8c3Ryb25nPnB1YmxpYwogdm9pZCBzZXZlcigpIHs8L3N0cm9uZz4KPHN0cm9uZz4gCiAgIGlmICghaGFzUGFyZW50KCkpPC9zdHJvbmc+CjxzdHJvbmc+IAogICAgICAgcmV0dXJuOzwvc3Ryb25nPgo8c3Ryb25nPiAKICAgaWYgKGlzTENoaWxkKCkpPC9zdHJvbmc+CjxzdHJvbmc+IAogICAgICAgcGFyZW50LmxDaGlsZCA9IG51bGw7PC9zdHJvbmc+CjxzdHJvbmc+IAogICBlbHNlPC9zdHJvbmc+CjxzdHJvbmc+IAogICAgICAgcGFyZW50LnJDaGlsZCA9IG51bGw7PC9zdHJvbmc+CjxzdHJvbmc+IAogICBwYXJlbnQudXBkYXRlSGVpZ2h0KCk7IC8vILj80MK4uL3hteO8sMbk1+bPyLjftsg8L3N0cm9uZz4KPHN0cm9uZz4gICAgcGFyZW50LnVwZGF0ZVNpemUoKTsgLy8guPzQwri4veG147ywxuTX5s/IuebEoyA8L3N0cm9uZz4KPHN0cm9uZz4gCiAgIHBhcmVudCA9IG51bGw7PC9zdHJvbmc+CjxzdHJvbmc+IH0gPC9zdHJvbmc+CjxzdHJvbmc+c2V2ZXIoKaO6x9C2z73hteMgdiDT67i4veG14yBwINauvOS1xLnYz7Who7jDy+O3qNDo0qrQ3rjEIHYg0+sgcCC1xNa41evT8qOs0OjSqrOjyv3KsbzkoaOz/bTL1q7N4tPJ09ogcCC94bXjtcS6otfTt6LJ+sHLseS7r6Os0vK0y9Do0qq199PDIHVwZGF0ZUhlaWdodAogKCm6zXVwZGF0ZVNpemUgKCnAtLj80MK4uL3hteMgcCC8sMbk1+bPyLXEuN+2yNPruebEo6GjxuTKsbzkuLTU07bIIFQobikKID0gpq8gKGxldmVsKHYpKaGjPGJyPgogICAgNKOpPC9zdHJvbmc+CjxzdHJvbmc+IAogICAvLyDJ6NbDtbHHsL3hteO1xNfzuqLX0yy3tbvY1K3X87qi19M8L3N0cm9uZz4KPHN0cm9uZz5wdWJsaWMKIEJpblRyZWVOb2RlIHNldExDaGlsZChCaW5UcmVlTm9kZSBsYykgezwvc3Ryb25nPgo8c3Ryb25nPiAKICAgQmluVHJlZU5vZGUgb2xkTEMgPSB0aGlzLmxDaGlsZDs8L3N0cm9uZz4KPHN0cm9uZz4gCiAgIGlmIChoYXNMQ2hpbGQoKSkgezwvc3Ryb25nPgo8c3Ryb25nPiAKICAgICAgIGxDaGlsZC5zZXZlcigpOzwvc3Ryb25nPgo8c3Ryb25nPiAKICAgfSAvLyC2z7+qtbHHsNfzuqLX09PrveG147XEudjPtTwvc3Ryb25nPgo8c3Ryb25nPiAKICAgaWYgKGxjICE9IG51bGwpIHs8L3N0cm9uZz4KPHN0cm9uZz4gCiAgICAgICBsYy5zZXZlcigpOyAvLyC2z7+qIGxjINPrxuS4uL3hteO1xLnYz7U8L3N0cm9uZz4KPHN0cm9uZz4gCiAgICAgICB0aGlzLmxDaGlsZCA9IGxjOyAvLyDIt7aouLjX07nYz7U8L3N0cm9uZz4KPHN0cm9uZz4gCiAgICAgICBsYy5wYXJlbnQgPSB0aGlzOzwvc3Ryb25nPgo8c3Ryb25nPiAKICAgICAgIHRoaXMudXBkYXRlSGVpZ2h0KCk7IC8vILj80MK1scewveG147ywxuTX5s/IuN+2yDwvc3Ryb25nPgo8c3Ryb25nPiAKICAgICAgIHRoaXMudXBkYXRlU2l6ZSgpOyAvLyC4/NDCtbHHsL3hteO8sMbk1+bPyLnmxKM8L3N0cm9uZz4KPHN0cm9uZz4gCiAgIH08L3N0cm9uZz4KPHN0cm9uZz4gCiAgIHJldHVybiBvbGRMQzsgLy8gt7W72NSt1/O6otfTPC9zdHJvbmc+CjxzdHJvbmc+fTwvc3Ryb25nPgo8c3Ryb25nPjxicj4KPC9zdHJvbmc+CjxzdHJvbmc+IAogICAvLyDIodPSuqLX0zwvc3Ryb25nPgo8c3Ryb25nPnB1YmxpYwogQmluVHJlZU5vZGUgZ2V0UkNoaWxkKCkgezwvc3Ryb25nPgo8c3Ryb25nPiAKICAgcmV0dXJuIHJDaGlsZDs8L3N0cm9uZz4KPHN0cm9uZz59PC9zdHJvbmc+CjxzdHJvbmc+PGJyPgo8L3N0cm9uZz4KPHN0cm9uZz4gCiAgIC8vIMno1sO1scewveG147XE09K6otfTLLe1u9jUrdPSuqLX0zwvc3Ryb25nPgo8c3Ryb25nPnB1YmxpYwogQmluVHJlZU5vZGUgc2V0UkNoaWxkKEJpblRyZWVOb2RlIHJjKSB7PC9zdHJvbmc+CjxzdHJvbmc+IAogICBCaW5UcmVlTm9kZSBvbGRSQyA9IHRoaXMuckNoaWxkOzwvc3Ryb25nPgo8c3Ryb25nPiAKICAgaWYgKGhhc1JDaGlsZCgpKSB7PC9zdHJvbmc+CjxzdHJvbmc+IAogICAgICAgckNoaWxkLnNldmVyKCk7PC9zdHJvbmc+CjxzdHJvbmc+IAogICB9IC8vILbPv6q1scew09K6otfT0+u94bXjtcS52M+1PC9zdHJvbmc+CjxzdHJvbmc+IAogICBpZiAocmMgIT0gbnVsbCkgezwvc3Ryb25nPgo8c3Ryb25nPiAKICAgICAgIHJjLnNldmVyKCk7IC8vILbPv6ogbGMg0+vG5Li4veG147XEudjPtTwvc3Ryb25nPgo8c3Ryb25nPiAKICAgICAgIHRoaXMuckNoaWxkID0gcmM7IC8vIMi3tqi4uNfTudjPtTwvc3Ryb25nPgo8c3Ryb25nPiAKICAgICAgIHJjLnBhcmVudCA9IHRoaXM7PC9zdHJvbmc+CjxzdHJvbmc+IAogICAgICAgdGhpcy51cGRhdGVIZWlnaHQoKTsgLy8guPzQwrWxx7C94bXjvLDG5Nfmz8i437bIPC9zdHJvbmc+CjxzdHJvbmc+IAogICAgICAgdGhpcy51cGRhdGVTaXplKCk7IC8vILj80MK1scewveG147ywxuTX5s/IuebEozwvc3Ryb25nPgo8c3Ryb25nPiAKICAgfTwvc3Ryb25nPgo8c3Ryb25nPiAKICAgcmV0dXJuIG9sZFJDOyAvLyC3tbvY1K3T0rqi19M8L3N0cm9uZz4KPHN0cm9uZz59PC9zdHJvbmc+CjxzdHJvbmc+c2V0TENoaWxkKGxjKaGiIGdldFJDaGlsZChyYymjusG9uPbL47eotcS5psTcz+C21KOs0ru49srHyejWw73hteMgdiC1xNfzuqLX06Os0ru49srHyejWw73hteMgdiC1xNPSuqLX06Gjwb249svjt6i1xMq1z9bKx8DgJiMyMDI4NDu1xKOs0tQgc2V0TENoaWxkKCnOqsD9y7XD96GjytfPyKOsyOe5+yB2INPQ1/O6otfTIG9sZExDo6zU8tOmtbG199PDIG9sZExDLgogc2V2ZXIoKbbPv6ogdiDT68bk1/O6otfTtcS52M+1oaMKIMbktM6jrCC199PDIGxjLiBzZXZlcigpts+/qsbk0+u4uL3hteO1xLnYz7Who9fuuvOjrL2owaIgdiDT6yBsYyDWrrzktcS4uNfTudjPtaOssqK199PDIHYuCiB1cGRhdGVTaXplICgp0+sgdi51cGRhdGVIZWlnaHQgKCm4/NDCIHYgvLDG5Nfmz8i1xLnmxKPT67jftsihozwvc3Ryb25nPgo8c3Ryb25nPs/Cw+bKx9PDtPrC68q1z9a1xMr3uN+2yLrNsunRr8r30rbX073hteO1xLLZ1/ehozwvc3Ryb25nPgo8c3Ryb25nPjwvc3Ryb25nPjxwcmUgY2xhc3M9"brush:java;">public class BinSearchTreeTest01 { public Point root; //访问结点 public static void visitKey(Point p){ System.out.println(p.getKey() + " "); } //构造树 public static Point Tree(){ Point a = new Point('A', null, null); Point b = new Point('B', null, a); Point c = new Point('C', null, null); Point d = new Point('D', b, c); Point e = new Point('E', null, null); Point f = new Point('F', e, null); Point g = new Point('G', null, f); Point h = new Point('H', d, g); return h;// root } //求二叉树的高度 height = max(HL , HR) + 1 public static int height(Point p){ int HL , HR , MaxH; if(p != null){ HL = height(p.getLeftChild()); HR = height(p.getRightChild()); MaxH = Math.max(HL, HR); return MaxH + 1; } return 0; } //求二叉树的叶子结点 public static void OrderLeaves(Point p){ if(p != null){ if(p.getLeftChild() == null && p.getRightChild() == null) visitKey(p); OrderLeaves(p.getLeftChild()); OrderLeaves(p.getRightChild()); } } public static void main(String[] args) { System.out.println("二叉树的高度为:" + height(Tree())); System.out.print("二叉树的叶子结点为:"); OrderLeaves(Tree()); } } class Point{ private char key; private Point LeftChild , RightChild; public Point(char key , Point LeftChild , Point RightChild){ this.key = key; this.LeftChild = LeftChild; this.RightChild = RightChild; } public Point(char key){ this(key , null ,null); } public char getKey() { return key; } public void setKey(char key) { this.key = key; } public Point getLeftChild() { return LeftChild; } public void setLeftChild(Point leftChild) { LeftChild = leftChild; } public Point getRightChild() { return RightChild; } public void setRightChild(Point rightChild) { RightChild = rightChild; } } 3.下面开始今天的正题,二叉搜索树的查询,插入和删除操作 1)Find ?查找从根结点开始,如果树为空,返回NULL ?若搜索树非空,则根结点关键字和X进行比较,并进行不同处理: 1)若X小于根结点键值,只需要在左子树进行搜索; 2)若X大于根结点键值,在右子树进行搜索; 3)若两者比较结果相同,搜索完成,返回此结点。 import java.util.Scanner;
/**
* 二叉搜索树的操作集锦
*
* @author Administrator
*
*/
class BinSearchTreeTest02 {
public Point1 root;
// 访问结点
public static void visitKey(Point1 p) {
System.out.println(p.getKey() + " ");
}
// 构造树
public static Point1 Tree() {
Point1 m = new Point1(4, null, null);
Point1 a = new Point1(6, m, null);
Point1 b = new Point1(5, null, a);
Point1 c = new Point1(14, null, null);
Point1 d = new Point1(10, b, c);
Point1 e = new Point1(24, null, null);
Point1 f = new Point1(25, e, null);
Point1 g = new Point1(20, null, f);
Point1 h = new Point1(15, d, g);
return h;// root
}
// 构造空树
public static Point1 EmptyTree(int t) {
Point1 a = new Point1(t, null, null);
return a;
}
// *********************************查找操作****************************
/**
* 二叉搜索树查找操作方法1
*
* @param t
* @param node
* @return
*/
public static boolean contains(int t, Point1 node) {
if (node == null)
return false;// 结点为空,查找失败
String st = Integer.toString(t);// 把要查找的结点转化为String类型
int result = compareTo(st, node);
if (result == 1) {
return true;
} else {
return false;
}
}
public static int compareTo(String a, Point1 p) {
// String b = Integer.toString(p.getKey());
// if(a.equals(b))和下面这行是等价的
if (a.equals(p.getKey() + ""))
return 1;
int i = 0, j = 0;
if (p.getLeftChild() != null) {
i = compareTo(a, p.getLeftChild());
}
if (p.getRightChild() != null) {
j = compareTo(a, p.getRightChild());
}
if (i == 1) {
return i;
} else if (j == 1) {
return j;
} else {
return -1;
}
}
/**
* 二叉搜索树查找操作方法2(递归算法) 尾递归的方式
*
* @param t
* @param node
* @return
*/
public static Point1 contains2(int t, Point1 node) {
if (node == null)
return null;// 结点为空,查找失败
if (t > node.getKey())
return contains2(t, node.getRightChild());// 查找右子树
else if (t < node.getKey())
return contains2(t, node.getLeftChild());// 查找左子树
else
return node;
}
/**
* 二叉搜索树查找的搜索方法2的变形,非递归算法的效率更高 将尾递归改为迭代函数
*
* @param args
*/
public static Point1 contains3(int t, Point1 node) {
while (node != null) {
if (t > node.getKey())
node = node.getRightChild();
else if (t < node.getKey())
node = node.getLeftChild();
else
return node;
}
return null;
}
/**
* 二叉搜索树的最大元素 根据其性质可以得出二叉搜索树的最大元一定位于右子树的最右端,最小元则相反
*
* @param args
*/
public static int findMax(Point1 point) {
if (point != null) {
while (point.getRightChild() != null) {
point = point.getRightChild();
}
}
return point.getKey();
}
public static int findMin(Point1 point) {
if (point == null)
return 0;// 先判断树是否为空
else if (point.getLeftChild() == null)
return point.getKey();// 在判断左子树是否为空
else
return findMin(point.getLeftChild());
}
public static void main(String[] args, Point1 p) {
System.out.println("此二叉树的最大结点为:" + findMax(Tree()));
System.out.println("此二叉树的最小结点为:" + findMin(Tree()));
@SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
System.out.println("输入一个结点,将判断是否是此二叉树的结点");
int a = scanner.nextInt();
if (contains2(a, Tree()) != null)
System.out.println(a + " 是此二叉树的结点");
else
System.out.println(a + " 不是此二叉树的结点");
}
}
class Point1 {
private int key;
private Point1 LeftChild, RightChild;
public Point1(int key, Point1 LeftChild, Point1 RightChild) {
this.key = key;
this.LeftChild = LeftChild;
this.RightChild = RightChild;
}
public Point1(int key) {
this(key, null, null);
}
public int getKey() {
return key;
}
public void setKey(char key) {
this.key = key;
}
public Point1 getLeftChild() {
return LeftChild;
}
public void setLeftChild(Point1 leftChild) {
LeftChild = leftChild;
}
public Point1 getRightChild() {
return RightChild;
}
public void setRightChild(Point1 rightChild) {
RightChild = rightChild;
}
}
(给出了三种不同的查找的思路,不过确实要比另外两种好实现一些,希望可以有所借鉴,插入和删除晚些时候放上)
|