学习笔记5-集合框架


集合Collection

集合类的由来

对象用于封装特有数据,对象多了需要存储,如果对象的个数不确定。就使用集合容器进行存储。

集合容器因为内部的数据结构不同,有多种数据结构容器。不断的向上抽取共性,就形成了集合框架。

Collection基本方法

1添加

boolean add(object):向该集合添加一个元素

boolean addAll(Collection);添加一个集合中的所有元素到该集合。

2删除

void clear():将集合中的元素全部删除,集合长度变为0

boolean  remove(obj):删除集合中指定的对象。

boolean  removeAll(collection c):从集合中删除集合c中的所有元素。

3判断。

boolean contains(obj):集合中是否包含指定元素。

boolean containsAll(Collection c):集合中是否包含集合c中所有的元素。

boolean isEmpty():集合是否为空。

4获取

int size():返回集合中元素的个数。

5取交集

boolean retainAll(Collection c):当前集合和指定集合中的元素是否有交集。

6将集合变成数组

Object[] toArray();把集合转换成数组,所有集合元素转换成对应的数组元素

7获取集合中所有元素

Iterator iterator():返回一个迭代器对象,用于遍历集合中的元素。

迭代器

public interface Collection<E> extends Iterable<E>

Ø 每个子集合存储的数据结构不同,所以获取集合中的元素的方式也是不同的,所以抽取了共性内容定义了接口,让子集合去实现。Iteratar接口隐藏底层集合的数据结构,向使用者提供了遍历各类集合的统一接口。

Ø Iterator仅用于遍历集合,Iterator本身并不提供盛装对象的能力。Iteator必须依附于Collection对象,它包含对所属集合的数据结构中的数据项的引用。如果需要创建Iterator对象,则必须有一个被迭代的集合。

Ø 当使用Iterator来迭代访问Collection集合元素时,Collection集合里的元素不能被改变,只有通过Iteratorremove方法才能删除上一次next方法返回的集合元素,否则将会引发java.util.ConcurrentModificationException异常。一旦在迭代过程中检测到该集合已经被修改(通常是程序中其他线程修改),程序立即引发ConcurrentModifcationException异常,而不是显示修改后的结果,这样可以避免共享资源而引发的潜在问题。

Ø 使用Iterator对集合元素进行迭代时,Iterator并不是把集合元素本身传给了迭代变量,而是把集合元素的值传给了迭代变量,所以修改迭代变量的值对集合元素本身没有任何改变。    

Ø Iterator接口隐藏了各种Collection实现类的底层细节,向应用程序提供了遍历Collection集合元素的统一编程接口。Iterator接口里的三个共性方法:

   boolean hasNext():如果被迭代的集合元素还没有被遍历,则返回true 

Object next():返回集合里下一个元素。

void remove():将迭代器新返回的元素删除。

ListIterator扩充的功能:可以逆序遍历,可以在遍历过程中增加或修改集合元素

Interface List extends Collection

Ø 特性:使用数组实现的List,可以操作索引,可以对元素快速的随机访问

Ø List接口主要有两个实现类:ArrayListLinkedList

Ø List只能对集合中的对象按索引位置排序,如果希望对List中的对象按其他特定方式排序,可以借助Comparator接口和Collections工具类。

• sort(List list):List中的对象进行自然排序。

• sort(List list,Comparator comparator):List中的对象进行comparator参数指定的排序规则排序

Ø java.util.Arrays.asList(T...a)把指定数组转换成该数组的List形式。注意转换后,元素不可进行增删操作。因为所有对List对象的操作都会被作用到底层的数组,而数组长度不能改变,因此不能调用这种List对象的add()remove ()方法,否则会抛出java.lang.UnsupportedOperationException运行时异常。

特有方法:

1添加

add(index,element):在指定的索引位插入元素。

addAll(index,collection):在指定的索引位插入一堆元素。

2删除

remove(index):删除指定索引位的元素。返回被删的元素。

3获取

Object get(index):通过索引获取指定元素。

int indexOf(obj)获取指定元素第一次出现的索引位,如果该元素不存在返回-1,通过-1,可以判断一个元素是否存在。

int lastIndexOf(Object o):反向索引指定元素的位置。

List subList(start,end):获取子列表。

4修改

Object set(index,element):对指定索引位进行元素的修改。

5获取所有元素

ListIterator listIterator():list集合特有的迭代器。

ListCollection多了修改的功能,当要对List集合中的数据遍历过程中需要修改数据,那就要用到list里的listIterator(),不然会发生异常。因为子类的特有数据修改时子类最清楚,父类是不知道的。

LinkedList集合的特有方法

1添加

addFirst();addLast();

jdk1.6以后offerFirst();offerLast();

2删除

removeFirst():获取并移除,如果链表为空,抛出NoSuchElementException.

removeLast();

jdk1.6以后

pollFirst();/获取并移除,如果链表为空,返回null.

pollLast();

3获取

getFirst():获取但不移除,如果链表为空,抛出NoSuchElementException.getLast()

jdk1.6以后

peekFirst();获取但不移除,如果链表为空,返回null.peekLast()

如何让ArrayList中的元素不重复?

public class MyArrayList extends ArrayList {

@Override

public boolean add(Object obj) {

// 假设obj的类型都是String 

String str = (String)obj;

if(this.contains(str)) {

return false;

}

super.add(obj);

return true;

}

}

Interface Set extends Collection

Ø 特性set集合中的对象无序,唯一。唯一是通过集合元素的equals()方法比较两个元素是否相等来确定的

Ø Set接口主要有两个实现类:HashsetTreeSet

HashSet 

Ø 内部数据结构是哈希表

Ø 不同步,线程高效但不安全

Ø HashSetHash算法来存储集合中的元素,因此具有很好的存取和查找性能。适用于内容规模较大的元素

Ø 取出时是无序的,随机的。

Ø HashSet的子类LinkedHashSet可以实现元素存储和取出的顺序一致,还能提高插入和删除元素的性能。

Ø 可以用HashSet来自定义存入的数据。需重写hashcode()equals()方法

Hash算法的功能

它能保证快速查找到对象。它是通过计算该对象的哈希值然后得到该元素的内存地址,从而快速找到该元素,就类似于数组中的索引。因此,当从HashSet中访问元素时,HashSet先计算该元素的hashCode(就是hashCod()的返回值),然后到该hashCode值对应的位置去取该元素—这就是HashSet速度很快的原因

HashSet如何保证元素唯一性呢?

是通过对象的hashCodeequals方法来完成对象唯一性的。必须保证equals() 比较的结果相等 hashCode() 相等hashCode ()相等, equals() 不一定相等。所以如果元素要存储到HashSet集合中,该元素必须覆盖hashCode方法和equals方法,且应尽量保证两个元素通过equals比较返回true时,它们的hashCode方法返回值也相等,而且元素中用作equals比较标准的属性,都应该用来计算hashCode值。

如果对象的hashCode值不同,则不用判断equals方法,就直接存储到哈希表中。如果对象的hashCode值相同,那么要再次判断对象的equals方法是否为true。如果为true,视为相同元素,不存。如果为false,那么视为不同元素,就进行存储。

TreeSet 

Ø 内部数据结构是二叉树。

Ø 不同步,线程高效但不安全

Ø 主要是用来给集合中的元素排序用的。

Ø 可以确保集合元素处于排序状态(默认采用自然排序)。自然排序就是TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间大小关系,然后将集合元素按升序排列。

如果试图把一个对象添加进TreeSet时,则该对象的类必须实现相比较的功能,否则当添加第二个元素时程序将会引发ClassCastException异常。向TreeSet中添加的应是同一个类的对象,否则调用compareTo(Object obj)方法也会引发C1assCastException异常

判断元素唯一性的方式:TreeSet会根据比较方法的返回结果是否为0,为0就是相同元素,不存。

元素默认是自然排序,那么如何让元素自定义排序?

1, 让元素自身具备比较功能,实现comparable接口的comparTo(Object obj)方法。

public class Person(集合元素) implements Comparable {

public int compareTo(Object o) {

自定义比较规则

}

}

2, 给集合增加一个比较器,创建集合对象时传入Comparator接口类型对象。

TreeSet  treeSet=new TreeSet(new Comparator(){

public int compare(Object o1,Object o2){

自定义比较规则

}

});

3, 如果同时实现上述二种方式,以比较器Comparator排序为主。

为什么一般需要同时存在两种比较方式? 

第一、因为有可能放入的对象本身并没有实现Comparable接口,而使用TreeSet集合的人又需要让对象具有比较功能,因此就必须存在Comparator比较器。

第二、因为对象本身的比较方式不能满足使用TreeSet集合的人的要求,这时候也需要比较器Comparator

Map集合接口

Ø Map(映射)是一种把键对象和值对象进行映射的集合,它的每一个元素都包含一对键对象和值对象,而值对象仍可以是Map类型,依此类推,这样就形成了多级映射。向Map集合中加入元素时,必须提供一对键对象和值对象

共性方法

1添加

value put(key,value):返回前一个和key关联的值,如果没有返回null.

2删除

void  clear():清空map集合。

value remove(key):根据指定的key翻出这个键值对。

3判断

boolean containsKey(key):

boolean containsValue(value):

boolean isEmpty();

4获取

value get(key):通过键获取值,如果没有该键返回null。当然可以通过返回null,来判断是否包含指定键。

int size(): 获取键值对的个数。

数组和map什么时候使用?

查表思想:当要操作的数据对象很多,且存在对应关系时,可以用Map集合来存储。如果其中一组数据是有序的排列时,可以使用数组来存储,将该组数据当做角标来对应另已一组数据。

Map

为了成功地在HashMap, Hashtable中存储、获取对象,用作key的对象必须实现hashCode方法和equals方法。

常用子类:

|--Hashtable :内部结构是哈希表,同步。不允许null作为键或值。

|--Properties:用来存储键值对型的配置文件的信息,可以和IO技术相结合。

|--HashMap 内部结构是哈希表,不同步。允许null作为键,null作为值。

|--TreeMap 内部结构是二叉树,不同步。可以对Map集合中的键进行排序。

List list = new ArrayList();//非同步的。

list = MyCollections.synList(list);//返回一个同步的list.

Properties

HashTable类的子类Properties一个可以将键值进行持久化存储的对象。

特点:

1,可以持久化存储数据。

2,键值都是字符串。

3,一般用于配置文件。

Ø getProperty(String key):返回系统中键对应的值

Ø Object setProperty(String key , String value):系统属性键值对存储Hashtable集合中。

Ø load():从输入流中读取属性列表(键和元素对),将流中的数据加载进集合。

原理:其实就是将读取流和指定文件相关联。并读取一行数据,因为数据是规则的key=value所以获取一行后。通过=对该行数据进行切割。左边就是键,右边就是值,将键值 存储到properties集合中。

Ø store()将此 Properties 中的属性列表写入输出流写入各个项后,刷新输出流。

Ø list():将集合的键值数据列出到指定的目的地

------------------------------------------------------------------------------

//Properties的基本功能:

public static void method()

{

Properties prop  = new Properties();

//添加元素:

prop.setProperty("02","zhangsan");

//通过键获取值:

//System.out.println(prop.getProperty("01"));

//获取所有的键值对:

Set<String> keySet = prop.stringPropertyNames();

for(String key : keySet)

{

System.out.println(key+":"+prop.getProperty(key));

}

}

集合图解

 

 

ArrayList: 数组结构用equals()

LinkedList: 链表结构用equals()

HashSet: 哈希表结构用 HashCode()equals()方法

TreeSet: 二叉数。用ComparableComparTo()方法或者CompartorCompar()方法

HashMap: 哈希表结构。用HashCode()equals()方法。

TreeMap: 二叉数。用Comparable()ComparTo()方法或者CompartorCompar()方法。

如果需要对键值储存与读写的顺序一致,那么就需要用到LinkedHashMap。

集合的使用技巧

需要唯一吗?

需要:Set

需要制定顺序吗

需要: TreeSet

不需要:HashSet

需要存储和取出的顺序一致吗?LinkedHashSet

不需要:List

需要频繁增删吗?

需要:LinkedList

不需要:ArrayList

如何记录每一个容器的结构和所属体系呢?

看名字!后缀名是该集合所属的体系。前缀名是该集合的数据结构。而且通常这些常用的集合容器都是不同步的。

看到array:就要想到数组,就要想到查询快,有角标.

看到link:就要想到链表,就要想到增删快,就要想要 add get remove+frist last的方法

看到hash:就要想到哈希表,就要想到唯一性,就要想到元素需要覆盖hashcode方法和equals方法。

看到tree:就要想到二叉树,就要想要排序,就要想到两个接口ComparableComparator 

数组与集合、不同集合的区别

集合与数组的区别?

1, 集合能自动改变自身的大小,而数组容量固定。数组通过length()知道它的容量,不知其实际容纳了多少个元素,而集合可以通过size()知道实际容纳了多少个元素

2, 集合只能存放引用数据,数组基本数据和引用数据都可以存放。但当集合存放基本数据类型时,会自动装箱。

3, 集合可以存放不同类型引用数据或映射关系数据,数组只能放相同类型数据。

4, 数组元素的存储是连续的,集合的存储是多种方式的

MapCollection的区别?

1.  Map按键值对存储.Collection是按个存储.是单列集合

2.  Map存储的键值唯一.CollectionList集合元素可以重复

3.  Map添加元素的方法是put,Collection添加元素的方法是add

4.  Map需要通过Map.keySet()Map.entrySet()方法获得单列集合,然后才可以遍历.Collection可以直接遍历

ArrayList集合,linkedList集合,Vector集合的区别?

1,ArrayList底层是用数组结构,不安全,查改速度快,因为是用角标的。

2LinkedList底层是用链表结构,不安全,增删速度快。它每个元素都只记住前后两个元素的地址值,

它也有角标,但是不用角标进行查找增删操作,跟没有一样。

3Vector是老版本的,已经被ArrayList取代,它安全但效率低,底层也是用数组结构。

CollectionCollections的区别

1.Collection是集合中的顶层接口,而Collections是集合的工具类。

  2.Collections类中的方法都是静态的,而Collection接口中的方法则不一定是。

  3.Collection接口存在子接口ListSet,是在一个集合体系中,而Collections没有子类。

Collecitons工具类

Collections

添加:Collections.addAll(Collection<? super T>c,T...elements)将所有指定元素添加到指定collection

Collections.copy(List<? super T>dest,List<? extends T>src)dest集合的所有元素复制到src集合中

Collections.fill(List<? super T>list,T obj)使用指定元素替换list集合中所有元素

查找:Collections.binarySeach(List<? extends Comparable<? super T>>list,T key)使用二分查找法查找指定集合,获取指定对象的索引

Collections.max(Collection<? extends T>coll,Comparator<? super T>comp)根据指定比较器的顺序,返回给定coll的最大元素

修改:Collections.shuffle(List<?> list,Random rnd)使用指定随机源对指定列表进行置换

Collections.sort(List<T> list,Comparator<? super T> c)使用指定比较器的顺序对list进行排序

Collections.swap(List<?> list,int i,int j)在指定列表的指定位置交换元素

Collections.synchronizedSet(Set<T> s)返回指定set支持的同步set

转化成数组:toArray()可以将集合转化成数组。如果数组定义小了,集合就再定义一个跟集合长度一样的数组把元素放入。如果定义长了,把集合元素放入,余下的角标全部为Null

数据结构

概述

数据:信息的载体,可以被计算机识别、存储和处理

数据元素:数据的基本单位

数据项:数据的最小单位,即数据元素是由若干个数据项组成

数据结构

Ø 数据结构是数据之间的相互关系,即数据在计算机存储空间中或磁盘中的组织形式。数据结构包括数组、链表、栈、二叉树、哈希表等等。正确选择数据结构会使程序的效率大大提高。

Ø 算法是指通过对这些结构中的数据进行各种处理,以完成特定任务的过程。在Java中,算法经常通过类的方法实现。例如数组就是一个数据结构,用for循环来顺序访问该数组,这就构造了一个简单的算法。

Ø 数据结构和算法是有关数据存储和编程的细致入微的基本规则。数据结构是为了加快增删改查的速度

Ø 通用数据结构:数组,链表,树,哈希表,它们通过关键字的值来存储并查找数据。数组和链表速度最慢,树相对较快,哈希表最快。

Ø 对于大多数数据结构来说,都需要知道如何寻找某一特定的数据项,如何插入一条新的数据项,如何删除某一特定的数据项以及如何迭代地访问某一数据结构中的各数据项,以便进行显示或其他操作。

Ø 专用数据结构:栈,队列,优先级队列。这些结构不是为了用户可访问的数据库而建立的

 

数据的存储结构:在进行数据处理时,所有要处理的数据都要存入计算机的存储器中。

数据的逻辑结构:指的是数据元素之间的关系,不同的关系可分为:集合、线性结构、树形结构、图形结构。同种数据的逻辑结构可以根据需要表现成任意一种或多种不同的存储结构

数据结构的使用场景

Ø 当存储和操作数据时,在大多数情况下数组首先考虑。以下是数据结构的使用图解

ü 当数据量较小且数据量的多少可预测时,用数组。如果插入速度很重要,用无序数组;如果查找速度很重要,用有序数组

当数据量较小且数据量不能预知或需要频繁地插入删除数据元素时,用链表。

ü 当确认数组和链表过慢时,考虑二叉树。哈希表速度最快,这使它成为计算机与数据交互时的必需。

平衡树<—不是—

数据库与数据结构

Ø 数据库是指由许多类似的记录组成的数据存储的集合。数据库中的每一条数据都被认为是相同格式的。记录是指数据库划分成的单元,它为存储信息提供了一个结构格式。一条记录通常被划分为几个字段,每个字段存储着由这个记录所描述事物的一条特性(某一种特定类型的数据)。在java中,记录经常被表示为一个相应类的对象,该对象的字段被称为字段。一个关键字是一条记录中的一个字段,通过它可以对数据执行增删改查

Ø 数据库一旦建立,就会根据某些需求对数据进行不同方式的排序。比如对姓名按字母序排序,对国内销售品按价格排序,对城市按人口增长率排序等等。对数据进行排序是检索的一个初始步骤。

数组与链表

数组结构

Ø 为什么不用数组表示一切?仅使用数组似乎就可以完成所有工作,为什么不用它们来进行所有的数据存储呢?因为在无序数组中插入快但查找慢,而有序数组查找快但插入慢。而且数组大小尺寸固定,但通常在开始设计程序时,并不知道会有多少数据项将会被放入

链表

Ø 链表是继数组之后第二种使用得最广泛的通用存储结构。除非需要频繁通过下标随机访问各个数据,否则在很多使用数组的地方都可以用链表代替。

Ø 链表包含一个linkedList对象和许多Link对象。linkedList对象包含一个引用叫fiirst,它指向链表的第一个链结点。每个Link对象包含数据和一个引用,叫next,它指向链表的下一个链结点。next字段为null值意味着链表的结尾。遍历链表是从first开始的,然后通过每个链结点的next字段找到下一个链结点。通过遍历可以找到拥有特定值的链结点,然后可以显示、删除或插入新链结点。

 

Ø 链表查找效率低。在链表中,查找数据项必须从头开始,依次访问链表中的数据项,直到找到该数据项为止。即使是有序链表还是必须从头开始依次访问数据项,因为链表中不能直接访问某个数据项,必须通过数据项间的链式引用才可以。

Ø 链表增、删效率高。因为当插入和删除链结点时,链表不需要移动任何东西。链表比数组优越的另外一个重要方面是链表需要多少内存就用多少内存,容量可以扩展。

Ø 对于编程而言,链表比数组复杂,但比哈希表或树简单。

栈、队列和优先级队列

概述

Ø 程序员的工具:栈、队列和优先级队列数据结构主要作为构思算法的辅助工具,更多的是作为程序员的工具来运用,而不是完全的数据存储工具。这些数据结构的生命周期比那些数据库类型的结构要短得多。在程序操作执行期间它们才被创建,通常用它们去执行某项特殊的任务;当完成任务之后,它们就被销毁。

Ø 受限访问:在数组中可以访问到各数据项。而堆和堆栈的数据结构,访问是受限的,即在特定时刻只有一个数据项可以被读取或被删除  

Ø 更加抽象:栈、队列和优先级队列是比其他数据存储结构更为抽象的结构。主要通过接口对栈、队列和优先级队列进行定义,这些接口表明通过它们可以完成的操作,而它们的主要实现机制对用户来说是不可见的。

Ø 栈、队列和优先级队列是经常用于简化某些程序操作的数据结构。在这些数据结构中,只有一个数据项可以被访问。

Ø 栈允许访问最后一个插入的数据项。栈中重要的操作是在栈顶插入(压入)一个数据项,以及从栈顶移除(弹出)一个数据项。

队列只允许访问第一个插入的数据项。队列的重要操作是在队尾插入数据项和在队头移除数据项。优先级队列允许访问优先级最大的数据项。优先级队列的重要操作是有序地插入新数据项和移除优先级最小的数据项。

Ø 栈只允许访问一个数据项:即最后插入的数据项。移除这个数据项后才能访问倒数第二个插入的数据项,依此类推(后进先出)。大部分微处理器运用基于栈的体系结构。当调用一个方法时,把它的返回地址和参数压入栈,当方法结束返回时,那些数据出栈。栈操作就嵌入在微处理器中。

Ø 例如,许多人在工作时收到信后,会随手将它放在桌子上的信堆上,或把它投入一个“专门的”筐里。等他们有空闲时间时,就会从上到下处理这些堆积的邮件。第一封信处理完后,接下来会处理下一封信,此时它正处于信堆的最上面。按此方法处理下去,直到最后轮到信堆最下面的一封(此时它在信堆的最上面)。只有能在合理的时间内处理完所有的信件,这种“先处理最上面邮件”的工作方法才不会产生麻烦。否则,会发生很久也处理不到栈底信件的危险

Ø 栈的容量通常很小,是临时的数据结构,操作效率高。

Ø 栈往往通过数组或链表实现,通过数组实现更有效率,因为最后被插入的数据总是在数组的最后,这个位置的数据很容易被删除。栈的溢出有可能出现,但当数组的大小被合理的规划后,溢出并不常见,因为栈很少会拥有大量的数据。如果栈拥有许多数据,并且数量不可精确预测时,用链表更好,这是由于从表头的位置删除或插入一个元素很方便。除非整个内存满了,栈的溢出不可能出现。链表比数组稍慢一些,因为对于插入一个新链接必须分配内存,从表中某链接点上删除元素后也需回收分配的内存

队列

Ø 只允许在表的一端进行插入,而在另一端进行删除。被称作先进先出的线性表

Ø 队列类似栈,只是在队列中第一个插入的数据项也会最先被移除(先进先出),而在栈中,操作效率高

Ø 在计算机操作系统里,有各种队列在安静地工作着。当在键盘上敲击时,有一个存储键入内容的队列。同样,如果使用文字处理程序敲击一个键,而计算机又暂时要做其他的事,敲击的内容不会丢失,它会排在队列中等待,直到文字处理程序有时间来读取它。利用队列保证了键入内容在处理时其顺序不会改变。

Ø 同栈相比,队同样可以通过数组和链表实现。这两种方法都很有效率。数组需要附加的程序来处理队在数组尾部回绕的情况。链表必须是双端的,这样才能从一端插入从另一端删除。 用数组还是链表来实现队的选择是通过数据量是否确定来决定的。

优先级队列

Ø 优先级队列是比栈和队列更专用的数据结构。它在很多的情况下都很有用。像普通队列一样,优先级队列有一个队头和一个队尾,并且也是从队头移除数据项。不过在优先级队列中,数据项优先级最大的数据项在队头。数据项插入的时候会按照优先级顺序插入到合适的位置以确保队列的顺序。

Ø 优先级队列用在只对访问最高优先级数据项访问的时候。例如,在抢先式多任务操作系统中,程序排列在优先级队列中,这样优先级最高的程序就会先运行。

二叉树、红-黑树与2-3-4

二叉树

Ø 为什么要用到二叉树呢?因为它结合了有序数组和链表的优点。在二叉树中查找数据项的速度和在有序数组中查找一样快,并且插入和删除数据项的速度也和链表一样快。

Ø 二叉树中,节点表示保存在树中的数据对象,根是树中最顶端的节点。节点最多有两个子节点。

Ø 二叉搜索树中,所有节点左边子孙节点的值都比该节点小,而右边子孙节点的值都>=该节点。

Ø 查找节点需要比较要找的关键字值和节点值,如果要找的节点值比相比较的节点值小就转向比较的这个节点的左子节点,如果大就转向右子节点。插入需要找到要插入新节点的位置并改变它父节点的子字段来指向它。

Ø 遍历二叉树是按某种顺序访问树中所有的节点。

 

红黑树

Ø 二叉搜索树如果插入的是随机数据,则执行效果很好。但如果插入的是有序的数据,速度就特别慢。因为当插入的数值有序时,二叉树就是非平衡的了。而对于非平衡树,它的快速查找〔插入,删除)指定数据项的能力就丧失了。

Ø 非平衡树是指根左边的后代比右边多或右边的后代比左边多。这些节点近似排列在一条直线上,大部分节点都在根的一侧,没有分支,这棵树属于不平衡的情况。当树没有分支时,它其实就是一个链表,所以查找速度慢

Ø 红一黑树是增加了某些特点的二叉搜索树,用于解决非平衡树问题,在平衡树中使用最广泛。为了保证树大概是平衡的,红一黑树在插入等过程中会检查不会破坏树的平衡,如果破坏了,程序就会进行纠正,根据需要更改树的结构以保持树的平衡。

Ø 在红一黑树中,每个节点或是黑的或是红色,也可以是任意的两种颜色,节点都有颜色。在插入和删除的过程中,要遵循保持这些颜色的不同排列的规则。它们被称为红一黑规则。如果遵循这些规则,树就是平衡的。

Ø 具体规则是:1.每一个节点不是红色就是黑色。2.根总是黑色的。3.如果节点是红色的,则它的子节点必须是黑色的。4,从根到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点。

2-3-4

 

Ø 在二叉树中,每个节点有一个数据项,最多有两个子节点。如果允许每个节点可以有更多的数据项和更多的子节点,就是多叉树。2-3-4树就是多叉树,它的每个节点最多有四个子节点和三个数据项

Ø 2-3-4树名字中的234的含义是指一个节点可能含有的子节点的个数。有一个数据项的节点总是有两个子节点。 有两个数据项的节点总是有三个子节点。有三个数抿项的节点益早有四个子节占。

Ø 2-3-4树像红一黑树一样是平衡树。它的效率比红一黑树稍差,但编程容易。更重要的是,通过学习2-3-4树可以更容易地理解B-树。B-树是另一种多叉树,专门用在外部存储中来组织数据(主存储的外部;通常指磁盘驱动器)B一树中的节点可以有几十或几百个子节点。

哈希表

Ø 哈希表可以提供快速的插入和查找操作,不论哈希表中有多少数据。哈希表运算得非常快,通常用于拼写检查器和作为计算机语言编译器中的符号表。哈希表的速度明显比树快,哈希表不仅速度快,编程实现也相对容易。

Ø 哈希表也有一些缺点:它是基于数组的,创建后难于扩展。某些哈希表被基本填满时,性能下降得非常严重,所以程序员必须要清楚表中将要存储多少数据(或者准备好定期地把数据转移到更大的哈希表中,这是个费时的过程)

Ø 而且,哈希表并不能提供任何形式的有序遍历,或对最大最小值元素进行存取。如果这些功能重要的话,使用二叉搜索树更好一些。然而,如果可以提前预测数据量的大小,并且不需要有序遍历数据,那么哈希表在速度和易用性方面是无与伦比的。

Ø 哈希化简介:在哈希表中,把关键字转换成数组下标的过程就是哈希化,是通过哈希函数完成的。然而,对于特定的关键字,并不需要哈希函数,关键字的值可以直接用于数组下标。经典的例子是字典。如果想要把一本英文字典的每个单词,从azyzzyva(这当然是一个单词),都写入计算机内存,以便快速读写,那么哈希表是一个不错的选择。

Ø 一个关键字哈希化到已占用的数组单元,这种情况叫做冲突。冲突可以用两种方法解决:开放地址法和链地址法。在开放地址法中,把冲突的数据项放在数组的其他位置。在链地址法中,每个数组单元包含一个链表。把所有映射到同一个数组下标的数据项都插在这个链表中。

Ø 哈希表需要有额外的存储空间,尤其是对于开放定址法。因为哈希表用数组作为基本结构,所以,必须预先精确地知道待存储的数据量。用链地址法处理冲突的哈希表是最健壮的实现办法。若能预先精确地知道数据量,用开放定址法编程最简单。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值