java散列映射,树集,树映射,自动装箱与拆箱

散列映射

HashMap< K,V>泛型类

HashMap<K,V>泛型类实现了泛型接口Map<K,V>,HashMap<K,V>类中的绝大部分方法都是Map<K,V>接口方法的实现。编程时,可以使用接口回调技术,即把HashMap<K.V> 对象的引用赋给Map<K,V>接口变量,那么接口变量就可以调用类实现的接口方法。
HashMap<K,V>对象采用散列表这种数据结构存储数据,习惯上称HashMap<K.V> 对象为散列映射。散列映射用于存储“键/值”对,允许把任何数量的“键/值”对存储在一起。

不可以发生逻辑冲突,即两个数据项不要使用相同的键,如果两个数据项对应相同的键,那 么,先前散列映射中的“键/值”对将被替换。散列映射在需要更多的存储空间时会自动增大容量,例如,如果散列映射的装载因子是0.75,那么当散列映射的容量被使用了75%时,它就把容量增加到原始容量的两倍。对于数组表链表两种数据结构,如果要查找它们存储的某个特定的元素却不知道位置,则需要从头开始访问元素直到找到匹配的为止。如果数据结构中包含很多元素,就会浪费时间,这时最好使用散列映射来存储要查找的数据,使用散列映射可以减少检索的开销。

HashMap<K,V>泛型类创建的对象称为散列映射,例如:
HashMap < String, Student > hashtable = new HashSet < String, Student>();
那么,hashtable 就可以存储“键/值”对数据,其中的键必须是一个String对象,键对应的值必是Student 对象。hashtable 可以调用public V put(K key, V value)键/值对数据存放到散列映射中,该方法同时返回键所对应的值。

HashMap<K,V>泛型类的常用方法


public void clear():清空散列映射。
public Object clone():返回当前散列映射的一个克隆。

publie boolean containsKey(Object key):如果散列映射有“键/值”对使用了参数指定的键,则该方法返回true,否则返回false。

public boolean contains Value(Object value) :如果散列映射有“键/值”对的值是参数指定的值,则该方法返回true,否则返回false。
public V get(Object key):返回散列映射中使用key作为键的“键/值”对中的值
public boolean isEmpty():如果散列映射不含任何“键/值”对,则该方法返回true,否则返回false。
public V remove(Object key):删除散列映射中键为参数指定的“键/值”对,并返回键对应的值。
public int size():返回散列映射的大小,即散列映射中“键/值”对的数目

遍历散列映射

public Collection<V>values()方法返回一个实现Collection<V>接口类创建的对象,可以使用接口回调技术,即将该对象的引用赋给Collection<V>接口变量,该接口变量可以回调iterator()方法获取一个Iterator对象,这个Iterator对象存放着散列映射中所有“键/值”对中的“值”。

基于散列映射的查询

对于经常需要进行查找的数据可以采用散列映射来存储,即为数据指定一个查找它的关键字,然后按照“键/值”对将关键字和数据一起存入散列映射中。

下面是一个英语单词查询的GUI程序,用户在界面的一个文本框中输入一个 英文单词并按Enter键确认,另一个文本框显示英文单词的汉语翻译。使用一个文本文件word. txt来管理若干个英文单词及汉语翻译

即文档word.txt用空白分隔单词。

wordPolice类使用Scanner解析word.txt单词,然后将英语单词-汉语翻译作为“键/值”存储到散列映射中供用户查询。

public class Example13_7 {

	public static void main(String args[]) {
		// TODO Auto-generated method stub
		WindowWord win = new WindowWord();
		win.setTitle("英-汉小字典");
	}

}

import java.awt.*;

import javax.swing.*;

public class WindowWord extends JFrame {
	JTextField inputText=null,showText=null;
	WordPolice police; //监视器
	WindowWord(){
		setLayout(new FlowLayout());
		inputText = new JTextField(6);
		add(inputText);
		add(showText);
		police = new WordPolice();
		police.setView(this);
		inputText.addActionListener(police);
		setBounds(100,100,400,200);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
}

import java.io.File;
import java.util.HashMap;
import java.util.*;
import java.awt.event.*;

public class WordPolice implements ActionListener{

	WindowWord view;
	//散列表
	HashMap<String,String>hashtable;
	File file = new File("word.txt");
	Scanner sc = null;
	WordPolice(){
		hashtable = new HashMap<String,String>();
		try {
			sc=new Scanner(file);
			while(sc.hasNext()) {
				String englishWord = sc.next();
				String chineseWord = sc.next();
				hashtable.put(englishWord,chineseWord);
				
			}
		}catch(Exception e){}
	}
	
	public void setView(WindowWord view) {
		this.view = view;
	}
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		String englishWord = view.inputText.getText();
		if(hashtable.containsKey(englishWord)) {
			String chineseWord = hashtable.get(englishWord);
			view.showText.setText(chineseWord);
		}
		else {
			view.showText.setText("没有此单词");
		}
	}
	

}

树集

TreeSet<E>泛型类

TreeSet<E>类是实现Set<E>接口的类,它的大部分方法都是接口方法的实现。

TreeSet<E>类创建的对象称为树集。树集采用树结点中的数据会按存放数据的“大小”顺序一层一层地依次排列,在同一层中的结点从左到右按字从小到大的顺序递增排列,下一层的都比上一层的小。

TreeSet<String> mytree = new TreeSet<String>();

然后使用add方法为树集添加结点

mytree.add("boy");
mytree.add("zoo");
mytree.add("girl")

结点的大小关系

 树集结点的排列和链表不同,不按添加的先后顺序排列。树集用add方法添加结点,结点会按其存放数据的“大小”顺序一层一层地依次排列,在同一层中的结点从左到右按“大小”顺序递增排列,下一层的都比上一层的小。
String 类现了 Comparable接口中的 compareTo(Object str) 方法,字符串对象调用compareTo(String s)方法字典序与参数s 指定的字符串比较大小,也就是说,两个字符串对象知道怎样比较大小。
实现Comparable接口类创建的对象可以调用compareTo (Object str)方法和参数指定的对象比较大小关系。假如a和b是实现Comparable接口类创建的两个对象,当a. compareTo (b)<o 时,称a小于b;当a. compareTo(b)>0时,称a大于b;当a. compareTo(b) =0时,称a等 于b。
当一个树集中的数据是实现Comparable接口类创建的对象时,结点就按对象的大小关系顺序排列。


TreeSet类的常用方法


下面介绍TreeSet类的常用方法。
public boolean add(E o):向树集添加结点,结点中的数据由参数指定,若添加成功则返回true,否则返回false。
.
public void clear():删除树集中的所有结点。
public void contains (Object o):如果树集中有包含参数指定的对象,则该方法返回 true,否则返回false.
public E first():返回树集中第一个结点中的数据(最小的结点)。

public E last():返回最后一个结点中的数据(最大的结点)。

public isEmpty():判断是否空树集,如果树集不含任何结点,该方法返回true

public boolean remove(Object o):删除树集中存储参数指定的对象的最小结点,如果删除成功,则该方法返回true,否则返回false.

public int size():返回数集中结点的数目。

import java.util.*;
class Student implements Comparable{

	int english=0;
	String name;
	Student(int english,String name){
		this.name = name;
		this.english = english;
	}
	@Override
	public int compareTo(Object b) {
	
		// TODO Auto-generated method stub
		Student st = (Student)b;
		this.english = english;
		return(this.english-st.english);
	
	}
}

public class E13_8 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TreeSet<Student> mytree = new TreeSet<Student>();
		Student st1,st2,st3,st4;
		st1=new Student(90,"小花");
		st2=new Student(66,"小李");
		st3=new Student(86,"小黄");
		st4=new Student(99,"小司");
		mytree.add(st1);
		mytree.add(st2);
		mytree.add(st3);
		mytree.add(st4);
		Iterator<Student>te=mytree.iterator();
		while(te.hasNext()) {
			Student stu = te.next();
			System.out.println(""+stu.name+""+stu.english);
		}	
	}
}

 运输结果:

小李66
小黄86
小花90
小司99

所以把一个元素插入树集的合适位置要比插入数组或链表中的合适位置效率。 


 树映射

树集TreeSet<E>适合用于数据的排序,结点按照存储对象的大小升序排序。TreeMap<K,V>类实现了Map<K,V>接口,称TreeMap<K,V>对象树映射。树映射使用"public V put(<K key,V value>);"“方法添加结点,该结点不仅存储数据value,而且存储着和其关联的关键字key,树映射的结点存储“关键字/值”对。和树集不同的是,树映射保证结点是按照结点中的关键字升序排列。

使用TreeMapp分别按照学生的英语成绩和数学成绩排序结点

import java.util.*;
class StudentKey implements Comparable{
	double d=0;
	StudentKey(double d){
		this.d=d;
	}
	@Override
	public int compareTo(Object b) {
		// TODO Auto-generated method stub
		StudentKey st = (StudentKey)b;
		if((this.d-st.d)==0) {
			return -1;
		}
		else {
			return(int)((this.d-st.d)*1000);
		}
	}
}

class Student{
	String name = null;
	double math,english;
	Student(String s,double m,double e){
		name=s;
		math=m;
		english=e;
	}
}
public class Example13_9 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TreeMap<StudentKey,Student> treemap = new TreeMap<StudentKey,Student>();
		String str[]= {"小一","小二","小晓","小李"};
		double math[] = {89,88,68,79};
		double english[] = {67,55,67,88};
		Student student[]= new Student[4];
		for(int k=0;k<student.length;k++) {
			student[k]=new Student(str[k],math[k],english[k]);
		}
		StudentKey key[]=new StudentKey[4];
		for(int k=0;k<key.length;k++) {
			key[k]=new StudentKey(student[k].math); //关键字按数学成绩排列大小
		}
		for(int k=0;k<student.length;k++) {
			treemap.put(key[k],student[k]);
		}
		int number = treemap.size();
		System.out.println("树映射中有"+number+"个对象,按数学成绩排序:");
		Collection<Student>collection=treemap.values();
		Iterator<Student>iter=collection.iterator();
		while(iter.hasNext()) {
			Student stu = iter.next();
			System.out.println("姓名"+stu.name+"数学"+stu.math);
			
		}
		treemap.clear();
		for(int k=0;k<key.length;k++) {
			key[k]=new StudentKey(student[k].english); //关键字按英语成绩排列大小
		}
		for(int k=0;k<student.length;k++) {
			treemap.put(key[k],student[k]);
		}
		number = treemap.size();
		System.out.println("树映射中有"+number+"个对象,按英语成绩排序:");
		collection = treemap.values();
		iter = collection.iterator();
		while(iter.hasNext()) {
			Student stu = (Student)iter.next();
			System.out.println("姓名"+stu.name+"英语"+stu.english);
		}
	}

}

运行效果:

树映射中有4个对象,按数学成绩排序:
姓名小晓数学68.0
姓名小李数学79.0
姓名小二数学88.0
姓名小一数学89.0
树映射中有4个对象,按英语成绩排序:
姓名小二英语55.0
姓名小晓英语67.0
姓名小一英语67.0
姓名小李英语88.0
 

自动装箱与拆箱的使用

基本类型数据与相应对象之间相互的自动转换的功能,称为基本数据类型的自动装箱与拆箱。在没有自动装箱与拆箱功能之前,不能将基本数据类型数据添加到类似链表的数据结构中。

程序允许把一个基本数据类型添加到类似链表等数据结构中,系统会自动完成基本类型相应对象的转换(自动装箱)。当从一个数据结构中获取对象时,如果该对象是基本数据的封装对象,那么系统将自动完成对象到基本类型的转换(自动拆箱)。

例如:

import java.util.*;
public class Example13_10 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ArrayList<Integer> list=new ArrayList<Integer>();
		for(int i=0; i<10; i++) {
			list.add(i); //自动装箱,实际添加到list中的new Integer(i)
		}
		for(int k=list.size()-1; k>=0; k--) {
			int m=list.get(k); //自动装箱,获取Integer对象中的int型数据
			System.out.printf("%3d",m);
		}
	}
}

运行结果: 9  8  7  6  5  4  3  2  1  0


所谓自动装箱就是允许把一个基本数据类型的值直接赋给基本数据类型相对应的类的实例

例如:

Integer number = 100

int m = 100;
Integer number = m;

上述语句的装箱过程:

Integer number = new Integer(m);

自动拆箱就是允许把基本数据类型相对应的类的实例直接赋给相对应的基本数据类型变量,或把基本数据类型相对应的类的实例当作相应的基本数据类型来使用。

例如number是一个Integer对象,

int x = number + number;

说述语句的拆箱过程如下:

int x = number.intValue()+number.intValue();

例:

public class Example4_19 {
public static void main(String args[]){
Integer x= 100, y= 12; //装箱: Integer x = new Integer(100), y = new Integer(12);
Integer m=x+y; //先拆箱再装箱: Integer m = new Integer(x.intValue() + y.intValue());
int ok =m; //拆箱: int ok = m.intValue();
System.out.println(ok);
}
}

自动装箱与拆箱仅仅是形式上的方便,在性能上并没有提高,而且装箱时必须保证类型一致。

例如:
Float c =12;
这是一个错误的装箱,正确的装箱应该是:
Float c=12.0f;
“Float c=new Float(12):”总是正确的。对于习惯了对象的编程人员,反面觉得自动装箱与拆箱很别扭。

猜你喜欢

转载自blog.csdn.net/m0_46965984/article/details/124332681