导航:首页 > 源码编译 > java红黑树算法

java红黑树算法

发布时间:2022-06-11 04:23:31

java中的TreeMap为什么要用红黑树实现,而不用AVL树实现

这篇文章讲的很明白了。

http://blog.csdn.net/hustyangju/article/details/27214251?utm_source=tuicool
很疑惑,为什么大家碰到问题不先自己去网络呢?

算法中红黑树的删除方法问题.

了无适俗韵真可与晤语

❸ 请问java中HashMap是怎么实现的,还有treeMap的实现原理是红黑树,请解释一下红黑树

参考资料的网页上有比较的代码,你可以仔细看下~~~

java中HashMap,LinkedHashMap,TreeMap,HashTable的区别
java为数据结构中的映射定义了一个接口java.util.Map;它有四个实现类,分别是HashMap Hashtable LinkedHashMap 和TreeMap
Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复。
Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力,或者使用ConcurrentHashMap。
Hashtable与 HashMap类似,它继承自Dictionary类,不同的是:它不允许记录的键或者值为空;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了 Hashtable在写入时会比较慢。
LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。
TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。

一般情况下,我们用的最多的是HashMap,HashMap里面存入的键值对在取出的时候是随机的,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的选择。
TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。
LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。

❹ Java中HashMap和TreeMap的区别深入理解

首先介绍一下什么是Map。在数组中我们是通过数组下标来对其内容索引的,而在Map中我们通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value

首先介绍一下什么是Map。在数组中我们是通过数组下标来对其内容索引的,而在Map中我们通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value。这就是我们平时说的键值对。

HashMap通过hashcode对其内容进行快速查找,而
TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。

HashMap 非线程安全 TreeMap 非线程安全

线程安全

在Java里,线程安全一般体现在两个方面:

1、多个thread对同一个java实例的访问(read和modify)不会相互干扰,它主要体现在关键字synchronized。如ArrayList和Vector,HashMap和Hashtable

(后者每个方法前都有synchronized关键字)。如果你在interator一个List对象时,其它线程remove一个element,问题就出现了。

2、每个线程都有自己的字段,而不会在多个线程之间共享。它主要体现在java.lang.ThreadLocal类,而没有Java关键字支持,如像static、transient那样。

1.AbstractMap抽象类和SortedMap接口

AbstractMap抽象类:(HashMap继承AbstractMap)覆盖了equals()和hashCode()方法以确保两个相等映射返回相同的哈希码。如果两个映射大小相等、包含同样的键且每个键在这两个映射中对应的值都相同,则这两个映射相等。映射的哈希码是映射元素哈希码的总和,其中每个元素是Map.Entry接口的一个实现。因此,不论映射内部顺序如何,两个相等映射会报告相同的哈希码。

SortedMap接口:(TreeMap继承自SortedMap)它用来保持键的有序顺序。SortedMap接口为映像的视图(子集),包括两个端点提供了访问方法。除了排序是作用于映射的键以外,处理SortedMap和处理SortedSet一样。添加到SortedMap实现类的元素必须实现Comparable接口,否则您必须给它的构造函数提供一个Comparator接口的实现。TreeMap类是它的唯一一份实现。

2.两种常规Map实现

HashMap:基于哈希表实现。使用HashMap要求添加的键类明确定义了hashCode()和equals()[可以重写hashCode()和equals()],为了优化HashMap空间的使用,您可以调优初始容量和负载因子。

(1)HashMap(): 构建一个空的哈希映像
(2)HashMap(Map m): 构建一个哈希映像,并且添加映像m的所有映射

(3)HashMap(int initialCapacity): 构建一个拥有特定容量的空的哈希映像
(4)HashMap(int
initialCapacity, float loadFactor): 构建一个拥有特定容量和加载因子的空的哈希映像

TreeMap:基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。
(1)TreeMap():构建一个空的映像树

(2)TreeMap(Map m): 构建一个映像树,并且添加映像m中所有元素
(3)TreeMap(Comparator c):
构建一个映像树,并且使用特定的比较器对关键字进行排序
(4)TreeMap(SortedMap s):
构建一个映像树,添加映像树s中所有映射,并且使用与有序映像s相同的比较器排序

3.两种常规Map性能

HashMap:适用于在Map中插入、删除和定位元素。
Treemap:适用于按自然顺序或自定义顺序遍历键(key)。

4.总结

HashMap通常比TreeMap快一点(树和哈希表的数据结构使然),建议多使用HashMap,在需要排序的Map时候才用TreeMap。

复制代码
代码如下:

import java.util.HashMap;
import
java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

import java.util.TreeMap;
public class HashMaps {
public static void
main(String[] args) {
Map<String, String> map = new HashMap<String,
String>();
map.put("a", "aaa");
map.put("b", "bbb");
map.put("c",
"ccc");
map.put("d", "ddd");
Iterator<String> iterator =
map.keySet().iterator();
while (iterator.hasNext()) {
Object key =
iterator.next();
System.out.println("map.get(key) is :" + map.get(key));

}
// 定义HashTable,用来测试
Hashtable<String, String> tab = new
Hashtable<String, String>();
tab.put("a", "aaa");
tab.put("b",
"bbb");
tab.put("c", "ccc");
tab.put("d", "ddd");

Iterator<String> iterator_1 = tab.keySet().iterator();
while
(iterator_1.hasNext()) {
Object key = iterator_1.next();

System.out.println("tab.get(key) is :" + tab.get(key));
}

TreeMap<String, String> tmp = new TreeMap<String, String>();

tmp.put("a", "aaa");
tmp.put("b", "bbb");
tmp.put("c", "ccc");

tmp.put("d", "cdc");
Iterator<String> iterator_2 =
tmp.keySet().iterator();
while (iterator_2.hasNext()) {
Object key =
iterator_2.next();
System.out.println("tmp.get(key) is :" + tmp.get(key));

}
}
}

运行结果如下:
map.get(key) is :ddd

map.get(key) is :bbb
map.get(key) is :ccc
map.get(key) is :aaa

tab.get(key) is :bbb
tab.get(key) is :aaa
tab.get(key) is :ddd

tab.get(key) is :ccc
tmp.get(key) is :aaa
tmp.get(key) is :bbb

tmp.get(key) is :ccc
tmp.get(key) is :cdc

HashMap的结果是没有排序的,而TreeMap输出的结果是排好序的。
下面就要进入本文的主题了。先举个例子说明一下怎样使用HashMap:

复制代码
代码如下:

import java.util.*;
public class Exp1 {

public static void main(String[] args){
HashMap h1=new HashMap();

Random r1=new Random();
for (int i=0;i<1000;i++){
Integer t=new
Integer(r1.nextInt(20));
if (h1.containsKey(t))

((Ctime)h1.get(t)).count++;
else
h1.put(t, new Ctime());
}

System.out.println(h1);
}
}
class Ctime{
int count=1;

public String toString(){
return Integer.toString(count);
}
}

在HashMap中通过get()来获取value,通过put()来插入value,ContainsKey()则用来检验对象是否已经存在。可以看出,和ArrayList的操作相比,HashMap除了通过key索引其内容之外,别的方面差异并不大。

前面介绍了,HashMap是基于HashCode的,在所有对象的超类Object中有一个HashCode()方法,但是它和equals方法一样,并不能适用于所有的情况,这样我们就需要重写自己的HashCode()方法。下面就举这样一个例子:

复制代码
代码如下:

import java.util.*;
public class Exp2 {

public static void main(String[] args){
HashMap h2=new HashMap();

for (int i=0;i<10;i++)
h2.put(new Element(i), new Figureout());

System.out.println("h2:");
System.out.println("Get the result for
Element:");
Element test=new Element(5);
if (h2.containsKey(test))

System.out.println((Figureout)h2.get(test));
else

System.out.println("Not found");
}
}
class Element{
int
number;
public Element(int n){
number=n;
}
}
class
Figureout{
Random r=new Random();
boolean
possible=r.nextDouble()>0.5;
public String toString(){
if (possible)

return "OK!";
else
return "Impossible!";
}
}

在这个例子中,Element用来索引对象Figureout,也即Element为key,Figureout为value。在Figureout中随机生成一个浮点数,如果它比0.5大,打印"OK!",否则打印"Impossible!"。之后查看Element(3)对应的Figureout结果如何。

结果却发现,无论你运行多少次,得到的结果都是"Not found"。也就是说索引Element(3)并不在HashMap中。这怎么可能呢?

原因得慢慢来说:Element的HashCode方法继承自Object,而Object中的HashCode方法返回的HashCode对应于当前的地址,也就是说对于不同的对象,即使它们的内容完全相同,用HashCode()返回的值也会不同。这样实际上违背了我们的意图。因为我们在使用
HashMap时,希望利用相同内容的对象索引得到相同的目标对象,这就需要HashCode()在此时能够返回相同的值。在上面的例子中,我们期望 new
Element(i) (i=5)与
Elementtest=newElement(5)是相同的,而实际上这是两个不同的对象,尽管它们的内容相同,但它们在内存中的地址不同。因此很自然的,上面的程序得不到我们设想的结果。下面对Element类更改如下:

复制代码
代码如下:

class Element{
int number;
public
Element(int n){
number=n;
}
public int hashCode(){
return
number;
}
public boolean equals(Object o){
return (o instanceof
Element) && (number==((Element)o).number);
}
}

在这里Element覆盖了Object中的hashCode()和equals()方法。覆盖hashCode()使其以number的值作为
hashcode返回,这样对于相同内容的对象来说它们的hashcode也就相同了。而覆盖equals()是为了在HashMap判断两个key是否相等时使结果有意义(有关重写equals()的内容可以参考我的另一篇文章《重新编写Object类中的方法》)。修改后的程序运行结果如下:

h2:
Get the result for Element:
Impossible!

请记住:如果你想有效的使用HashMap,你就必须重写在其的HashCode()。
还有两条重写HashCode()的原则:

[list=1]

不必对每个不同的对象都产生一个唯一的hashcode,只要你的HashCode方法使get()能够得到put()放进去的内容就可以了。即"不为一原则"。

生成hashcode的算法尽量使hashcode的值分散一些,不要很多hashcode都集中在一个范围内,这样有利于提高HashMap的性能。即"分散原则"。至于第二条原则的具体原因,有兴趣者可以参考Bruce
Eckel的《Thinking in Java》,在那里有对HashMap内部实现原理的介绍,这里就不赘述了。

掌握了这两条原则,你就能够用好HashMap编写自己的程序了。不知道大家注意没有,java.lang.Object中提供的三个方法:clone(),equals()和hashCode()虽然很典型,但在很多情况下都不能够适用,它们只是简单的由对象的地址得出结果。这就需要我们在自己的程序中重写它们,其实java类库中也重写了千千万万个这样的方法。利用面向对象的多态性——覆盖,Java的设计者很优雅的构建了Java的结构,也更加体现了Java是一门纯OOP语言的特性。

❺ 红黑树和平衡二叉树 区别

红黑树和平衡二叉树的主要区别如下:
平衡二叉树(AVL)树是严格的平衡二叉树,平衡条件必须满足(所有节点的左右子树高度差不超过1)。不管我们是执行插入还是删除操作,只要不满足上面的条件,就要通过旋转来保持平衡,而的英文旋转非常耗时的。所以平衡二叉树(AVL)适合用于插入与删除次数比较少,但查找多的情况。
红黑树在二叉查找树的基础上增加了着色和相关的性质使得红黑树相对平衡,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log
n)。所以红黑树适用于搜索,插入,删除操作较多的情况。
(5)java红黑树算法扩展阅读:
平衡二叉树在Windows
NT内核中广泛存在。
红黑树的应用:
1、在C
++的STL中,地图和集都是用红黑树实现的;
2、着名的Linux的的进程调度完全公平调度程序,用红黑树管理进程控制块,进程的虚拟内存区域都存储在一颗红黑树上,每个虚拟地址区域都对应红黑树的一个节点,左指针指向相邻的地址虚拟存储区域,右指针指向相邻的高地址虚拟地址空间;
3、IO多路复用的epoll的的的实现采用红黑树组织管理的sockfd,以支持快速的增删改查;
4、Nginx的的的中用红黑树管理定时器,因为红黑树是有序的,可以很快的得到距离当前最小的定时器;
5、Java中的TreeMap中的实现。
参考资料:
网络-平衡二叉树
网络-红黑树

❻ Java数据结构与算法有哪些

《Java数据结构和算法》(第2版)介绍了计算机编程中使用的数据结构和算法,对于在计算机应用中如何操作和管理数据以取得最优性能提供了深入浅出的讲解。全书共分为15章,分别讲述了基本概念、数组、简单排序、堆和队列、链表、递归、进阶排序、二叉树、红黑树、哈希表及图形等知识。附录中则提供了运行专题Applet和例程、相关书籍和问题解答。《Java数据结构和算法》(第2版)提供了学完一门编程语言后进一步需要知道的知识。本书所涵盖的内容通常作为大学或学院中计算机系二年级的课程,在学生掌握了编程的基础后才开始本书的学习。

❼ java的monitor机制中,为什么阻塞队列用list等待队列用set

java阻塞队列应用于生产者消费者模式、消息传递、并行任务执行和相关并发设计的大多数常见使用上下文。

BlockingQueue在Queue接口基础上提供了额外的两种类型的操作,分别是获取元素时等待队列变为非空和添加元素时等待空间变为可用。

BlockingQueue新增操作的四种形式:

3.2.1.3 HashMap类

对Map类的另外一个实现是HashMap。HashMap使用Hash表数据结构。HashMap假定哈希函数能够将元素适当的分布在各桶之间,提供一种接近O(1)的查询和更新操作。但是如果需要对集合进行迭代,则与HashMap的容量和桶的大小有关,因此HashMap的迭代效率不会很高(尤其是你为HashMap设置了较大的容量时)。

与HashMap性能有影响的两个参数是,初始容量和加载因子。容量是哈希表中桶的数量,初始容量是哈希表在创建时的容量。加载因子是哈希表在容器容量被自动扩充之前,HashMap能够达到多满的一种程度。当hash表中的条目数超出了加载因子与当前容量的乘积时,Hash表需要进行rehash操作,此时Hash表将会扩充为以前两倍的桶数,这个扩充过程需要进行完全的拷贝工作,效率并不高,因此应当尽量避免。合理的设置Hash表的初始容量和加载因子会提高Hash表的性能。HashMap自身不是线程安全的,可以通过Collections的synchronizedMap方法对HashMap进行包装。

3.2.1.4 ConcurrentHashMap类

ConcurrentHashMap类实现了ConcurrentMap接口,并提供了与HashMap相同的规范和功能。实际上Hash表具有很好的局部可操作性,因为对Hash表的更新操作仅会影响到具体的某个桶(假设更新操作没有引发rehash),对全局并没有显着影响。因此ConcurrentHashMap可以提供很好的并发处理能力。可以通过concurrencyLevel的设置,来控制并发工作线程的数目(默认为16),合理的设置这个值,有时很重要,如果这个值设置的过高,那么很有可能浪费空间和时间,使用的值过低,又会导致线程的争用,对数量估计的过高或过低往往会带来明显的性能影响。最好在创建ConcurrentHashMap时提供一个合理的初始容量,毕竟rehash操作具有较高的代价。

3.2.2 ConcurrentSkipListSet类

实际上Set和Map从结构来说是很像的,从底层的算法原理分析,Set和Map应当属于同源的结构。所以Java也提供了TreeSet和ConcurrentSkipListSet两种SortedSet,分别适合于非多线程(或低并发多线程)和多线程程序使用。具体的算法请参考前述的Map相关介绍,这里不在累述。

3.2.3 CopyOnWriteArrayList类

CopyOnWriteArrayList是ArrayList的一个线程安全的变体,其中对于所有的可变操作都是通过对底层数组进行一次新的复制来实现的。

由于可变操作需要对底层的数据进行一次完全拷贝,因此开销一般较大,但是当遍历操作远远多于可变操作时,此方法将会更有效,这是一种被称为“快照”的模式,数组在迭代器生存期内不会发生更改,因此不会产生冲突。创建迭代器后,迭代器不会反映列表的添加、移除或者更改。不支持在迭代器上进行remove、set和add操作。CopyOnWriteArraySet与CopyOnWriteArrayList相似,只不过是Set类的一个变体。

3.2.3 Collections提供的线程安全的封装

Collections中提供了synchronizedCollection、synchronizedList、synchronizedMap、synchronizedSet、synchronizedSortedMap、synchronizedSortedMap等方法可以完成多种集合的线程安全的包装,如果在并发度不高的情况下,可以考虑使用这些包装方法,不过由于Concurrent相关的类的出现,已经不这么提倡使用这些封装了,这些方法有些人称他们为过时的线程安全机制。

3.2.4简单总结

提供线程安全的集合简单概括分为三类,首先,对于并发性要求很高的需求可以选择以Concurrent开头的相应的集合类,这些类主要包括:ConcurrentHashMap、ConcurrentLinkedQueue、ConcurrentSkipListMap、ConcurrentSkipSet。其次对于可变操作次数远远小于遍历的情况,可以使用CopyOnWriteArrayList和CopyOnWriteArraySet类。最后,对于并发规模比较小的并行需求可以选择Collections类中的相应方法对已有集合进行封装。

此外,本章还对一些集合类的底层实现进行简单探讨,对底层实现的了解有利于对何时使用何种方式作出正确判断。希望大家能够将涉及到原理(主要有循环队列、堆、HashMap、红黑树、SkipList)进行仔细研究,这样才能更深入了解Java为什么这样设计类库,在什么情况使用,应当如何使用。

阅读全文

与java红黑树算法相关的资料

热点内容
積架小型空气压缩机 浏览:555
绿盾文档加密系统哪里有卖 浏览:637
我的世界怎么开挂在服务器里面 浏览:789
西门子自锁正反转编程图 浏览:749
出国英语pdf 浏览:920
算法线性匹配 浏览:674
山东省dns服务器云主机 浏览:554
安卓5g软件怎么隐藏 浏览:839
编译内核空间不足开不了机 浏览:887
汉纪pdf 浏览:474
在哪里下载国家医保app 浏览:657
没有与文件扩展关联的编译工具 浏览:426
我的世界反编译mcp下载 浏览:19
安卓手柄下载什么软件 浏览:70
pushrelabel算法 浏览:850
硬盘资料部分文件夹空白 浏览:617
cssloader的编译方式 浏览:941
java面板大小 浏览:506
怎么用命令方块打出字体 浏览:500
台湾加密货币研究小组 浏览:299