算法_二叉查找树

  二叉查找树支持将链表插入的灵活性和有序数组查找的高效性结合起来.数据结构由节点组成.节点包含的链接可以为null或者指向其他节点.在二叉树中,除了根节点以外,每个节点都有自己的父节点,且每个节点都只有左右两个链接,分别指向自己的左子节点和右子节点.因此可以将二叉查找树定义为一个空链接或者是一个有左右两个链接的节点,每个节点都指向一棵独立的子二叉树.

  二叉查找树(BST)每个节点都包含有一个Comparable的键以及相关联的值,且每个节点的键都大于其左子树的任意节点的键而小于右子树的任意节点的键.

  和链表一样,嵌套定义了一个私有类来表示二叉查找树上的节点,每个节点都含有一个键,一个值,一条左链接,一条右链接,和一个结点计数器(给出了以该节点为根的子树的节点总数).通过对于节点的递归操作实现了二叉树的基本插入,获取,删除操作,此外还支持和有序性相关的方法.代码如下:

  1 import edu.princeton.cs.algs4.Queue;
  2
  3 public class BST<Key extends Comparable<Key>,Value> {
  4     private Node root;        //二叉查找树的根节点.
  5
  6     private class Node {
  7         private Key key;    //键
  8         private Value val;    //值
  9         private Node left,right;    //指向子树的链接
 10         private int N;                //以该结点为根的子树中的节点总数
 11         public Node(Key key, Value val,int N) {
 12             super();
 13             this.key = key;
 14             this.val = val;
 15             this.N=N;
 16         }
 17     }
 18
 19     public int size() {
 20         return size(root);    //满足size(x)=size(x.left)+size(x.right)+1
 21     }
 22
 23     private int size(Node x) {
 24         if(x==null) return 0;
 25         else return x.N;
 26     }
 27
 28     public Value get(Key key) {
 29         return get(root,key);
 30     }
 31
 32     private Value get(Node x, Key key) {
 33         //以x为根节点的子树中查找并返回key所对应的值.
 34         if(x==null) return null;
 35         int cmp=key.compareTo(x.key);        //与根节点的值作比较
 36         if(cmp<0) return get(x.left,key);    //如果小于根节点的值,那么在以x.left为根节点的子树寻找
 37         if(cmp>0) return get(x.right,key);    //如果大于根节点的值,那么在以x.right为根节点的子树寻找
 38         else return x.val;                    //返回根节点的值.
 39     }
 40
 41     public void put(Key key,Value val) {
 42         //查找key,找到则更新它的值,否则为它创建一个新的节点.
 43         root=put(root,key,val);
 44     }
 45
 46     private Node put(Node x, Key key, Value val)/*x表示插入什么根节点*/ {
 47         //如果key存在于以x为根节点的子树中则更新它的值.否则以key和val为键值对的新节点插入到该自述中
 48         if(x==null) return new Node(key,val,1);
 49         int cmp=key.compareTo(x.key);
 50         if(cmp<0)    x.left=put(x.left,key,val);        //比根节点的键值小,则在左子树寻找,并更新左侧的根节点
 51         else if(cmp>0)    x.right=put(x.right,key,val);//比根节点的键值大,则在右子树寻找,并更新右侧的根节点
 52         else x.val=val;                        //与根节点相同,更新值
 53         x.N=size(x.left)+size(x.right)+1;    //更新根节点的数目
 54         return x;                            //更新根节点
 55     }
 56     public Key min() {            //获取最小的键
 57         return min(root).key;    //从根节点开始向下获取
 58     }
 59
 60     private Node min(Node x) {
 61         if(x.left==null) return x;    //如果没有左节点,则跟根节点的键值就是最小的键值
 62         return min(x.left);            //如果有左节点,则在左节点中寻找最小的键值
 63     }
 64     public Key max() {
 65         return max(root).key;
 66     }
 67     public Node max(Node x) {
 68         return max(x.right);
 69     }
 70
 71     //小于等于key的最大键
 72     public Key floor(Key key) {
 73         Node x=floor(root,key);
 74         if(x==null) return null;
 75         return x.key;
 76     }
 77
 78     private Node floor(Node x, Key key) {
 79         if(x==null) return null;    //key是最小的键
 80         int cmp=key.compareTo(x.key);
 81         if(cmp==0)    return x;
 82         if(cmp<0)    return floor(x.left,key);    //key位于根节点的左侧,因此小于等于key的键一定也位于左侧
 83         Node t=floor(x.right,key);    //key位于根节点的右侧.
 84         if(t!=null) return t;    //如果存在则返回存在的键值,不存在根节点就是小于等于key的最大键
 85         else return x;
 86     }
 87     //返回排名为k的节点
 88     public Key select(int k) {
 89         return select(root,k).key;
 90     }
 91     private Node select(Node x, int k) {
 92         if(x==null) return null;    //
 93         int t=size(x.left);        //左子树的总个数
 94         if(t>k)    return select(x.left,k);    //在左子树中寻找
 95         if(t<k)    return select(x.right,k-t-1);    //在右子树中寻找
 96         else return x;    //返回x
 97     }
 98     public int rank(Key key) {
 99         return rank(key,root);
100     }
101 //返回以x为根节点的子树中小于x.key的键的数量.
102     private int rank(Key key,Node x) {
103         if(x==null) return 0;
104         int cmp=key.compareTo(x.key);
105         if(cmp<0) return rank(key,x.left);
106         else if(cmp>0) return 1+size(x.left)+rank(key,x.right);
107         else return size(x.left);
108     }
109 //删除键值最小的子节点
110     public void deleteMin() {
111         root=deleteMin(root);
112     }
113
114     private Node deleteMin(Node x) {
115         if(x.left==null) return x.right;        //将指向该结点的链接指向该结点的右子树.
116         x.left=deleteMin(x.left);        //改变左节点的值.
117         x.N=size(x.left)+size(x.right)+1;
118         return x;
119     }
120     public void delete(Key key) {
121         root=delete(root,key);
122     }
123
124     public Node delete(Node x, Key key) {
125         if(x==null) return null;
126         int cmp=key.compareTo(x.key);
127         if(cmp<0) x.left=delete(x.left,key);
128         if(cmp>0) x.right=delete(x.right,key);
129         else {
130             if(x.right==null) return x.left;
131             if(x.left==null) return x.right;
132             Node t=x;        //将要删除的节点赋值给t
133             x=min(t.right);    //新节点为右子树中最小的节点
134             x.right=deleteMin(t.right);    //将右子树更新
135             x.left=t.left;    //左子树不变
136         }
137         x.N=size(x.left)+size(x.right)+1;
138         return x;
139     }
140     //查找操作.
141     public Iterable<Key> keys() {
142         return keys(min(),max());
143     }
144
145     private Iterable<Key> keys(Key lo, Key hi) {
146         Queue<Key> queue=new Queue<Key>();
147         keys(root,queue,lo,hi);
148         return queue;
149     }
150
151     private void keys(Node x, Queue<Key> queue, Key lo, Key hi) {
152         if(x==null) return ;
153         int cmplo=lo.compareTo(x.key);
154         int cmphi=hi.compareTo(x.key);
155         if(cmplo<0) keys(x.left,queue,lo,hi);    //查找根节点的左子树
156         if(cmplo<=0&&cmphi>=0) queue.enqueue(x.key);    //查找根节点
157         if(cmphi>0) keys(x.right,queue,lo,hi);    //查找根节点的右子树
158     }
159 }

  性能:对于二叉查找树而言:最坏情况下查找所需时间为N,插入所需时间为N,(时间与树的高度成正比),平均情况下,查找和插入所需时间为2InN,为了防止最坏情况的发生,即引出了平衡二叉查找树.对于二叉查找树,还有一种非递归的实现方法,效率更高,代码如下:

 1 public class NonrecursiveBST<Key extends Comparable<Key>, Value> {
 2
 3     private Node root;
 4
 5     private class Node {
 6         private Key key;
 7         private Value value;
 8         private Node left, right;
 9
10         public Node(Key key, Value value) {
11             this.key   = key;
12             this.value = value;
13         }
14     }
15
16     public void put(Key key, Value value) {
17         Node z = new Node(key, value);
18         if (root == null) { root = z; return; }
19         Node parent = null, x = root;
20         while (x != null) {
21             parent = x;
22             int res = key.compareTo(x.key);
23             if      (res < 0) x = x.left;
24             else if (res > 0) x = x.right;
25             else { x.value = value; return; }   // overwrite duplicate
26         }
27         int res = key.compareTo(parent.key);
28         if (res < 0) parent.left  = z;
29         else         parent.right = z;
30     }
31
32
33
34     Value get(Key key) {
35         Node x = root;
36         while (x != null) {
37             int res = key.compareTo(x.key);
38             if      (res < 0) x = x.left;
39             else if (res > 0) x = x.right;
40             else return x.value;
41         }
42         return null;
43     }
44     public Iterable<Key> keys() {
45         Queue<Key> queue = new Queue<Key>();
46         keys(root, queue);
47         return queue;
48     }
49     private void keys(Node x, Queue<Key> queue) {
50         if (x == null) return;
51         keys(x.left, queue);
52         queue.enqueue(x.key);
53         keys(x.right, queue);
54     } 
时间: 2024-06-19 05:43:31

算法_二叉查找树的相关文章

STL_算法(21)_ STL_算法_填充新值

STL_算法_填充新值 fill(b, e, v) fill(b, n, v) generate(b, n, p) generate_n(b, n, p) #include<iostream> #include<algorithm> #include<vector> #include<list> // #include<string> using namespace std; int main() { list<string> sli

HDU 1162 Eddy&#39;s picture (prime算法_裸题)

Problem Description Eddy begins to like painting pictures recently ,he is sure of himself to become a painter.Every day Eddy draws pictures in his small room, and he usually puts out his newest pictures to let his friends appreciate. but the result i

监督学习算法_k-近邻(kNN)分类算法_源代码

因为自己想学着去写机器学习的源码,所以我最近在学习<机器学习实战>这本书. <机器学习实战>是利用Python2完成的机器学习算法的源代码,并利用机器学习方法来对实际问题进行分析与处理. (<机器学习实战>豆瓣读书网址:https://book.douban.com/subject/24703171/) 以下内容是我通过学习<机器学习实战>,以及我对k-近邻(kNN)分类算法的理解,所总结整理出的内容,其中kNN分类算法的源码为Python3的代码,希望大家

算法—8.二叉查找树

1.基本思想 我们将学习一种能够将链表插入的灵活性和有序数组查找的高效性结合起来的符号表实现.具体来说,就是使用每个结点含有两个链接(链表中每个结点只含有一个链接)的二叉查找树来高效地实现符号表,这也是计算机科学中最重要的算法之一. 定义:一棵二叉查找树(BST)是一棵二叉树,其中每个结点都含有一个Comparable的键(以及相关联的值)且每个结点的键都大于其左子树中的任意结点的键而小于右子树的任意结点的键. 2.具体算法 /** * 算法3.3 基于二叉查找树的符号表 * Created b

贪心算法_活动安排问题_哈弗曼编码

问题表述:设有n个活动的集合E = {1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源.每个活i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si < fi .如果选择了活动i,则它在半开时间区间[si, fi)内占用资源.若区间[si, fi)与区间[sj, fj)不相交,则称活动i与活动j是相容的.也就是说,当si >= fj或sj >= fi时,活动i与活动j相容. 由于输入的活动以其完成时间的非减序排列,所以算法

模拟算法_掷骰子游戏&amp;&amp;猜数游戏

模拟算法是用随机函数来模拟自然界中发生的不可预测的情况,C语言中是用srand()和rand()函数来生成随机数. 先来介绍一下随机数的生成: 1.产生不定范围的随机数 函数原型:int rand() 产生一个介于0~RAD_MAX间的整数,其具体值与系统有关系.Linux下为2147483647.我们可以在include文件夹中的stdlib.h中可以看到(Linux在usr目录下,Windows在安装目录下) 1 #include<stdio.h> 2 #include<stdlib

算法_博客

参考: 从头到尾彻底理解KMP http://blog.csdn.net/v_july_v/article/details/7041827 快速排序算法 http://blog.csdn.net/v_JULY_v/article/details/6116297 十二之续.快速排序算法的深入分析 http://blog.csdn.net/v_JULY_v/article/details/6211155 十二之再续.快速排序算法所有版本的c/c++实现 http://blog.csdn.net/v_

STL_算法_查找算法(find、find_if)

C++ Primer 学习中. .. 简单记录下我的学习过程 (代码为主) find . find_if /**********************线性查找O(n) find(); find_if(); 注意: 1.假设是已序区间,能够使用区间查找算法 2.关联式容器(set,map)有等效的成员函数find();时间复杂度O(log(n)) 3.string 有等效的成员函数find(); **********************/ #include<iostream> #inclu

算法_归并排序

归并排序的基本思想是:将两个已经有序的数组,归并成为更大的有序数组.这种操作称为归并排序.要让一个数组排序,可以先递归的把它分成两半分别排序,然后将结果归并起来.归并排序能够保证对一个任意长度为N的数组排序所需时间和NlogN成正比. 基本的归并方法代码如下:该方法先将所有的元素复制到aux[]中,然后再归并到a[]中.方法在归并的时候,进行了四次条件判断:左半边用尽(取右半边的元素),右半边用尽(取左半边的元素),右半边的当前元素小于左半边的当前元素(取右半边的元素)以及右半边的元素大于等于左