最近,在进行编程的时候,对于hashmap中的Key与Value总是有些疑问,今天写这个博客来加深一下理解。
相信大家对简单的hashmap和hashset的使用都有些基础了,HashMap<k,v>中大都是Java基础类型的包装类,比如String,Integer,Byte,Character等;但是在实际应用中,我们可能需要更加复杂的数据结构,比如key为一个Set、Map或者是一个类,而value同样也可以更为复杂,接下来我就介绍一下这几种情况的使用:
演示以牛客网上的题目为例:变位词排序
请编写一个方法,对一个字符串数组进行排序,将所有变位词合并,保留其字典序最小的一个串。这里的变位词指变换其字母顺序所构成的新的词或短语。例如"triangle"和"integral"就是变位词。
给定一个string的数组str和数组大小int n,请返回排序合并后的数组。保证字符串串长小于等于20,数组大小小于等于300。
测试样例:
["ab","ba","abc","cba"]
返回:["ab","abc"]
第一种情况,HashSet中为Map,我们以字符串的存储为例,即将一个字符串存储为<Character:Integer>类型的一个Set:
HashSet<Map<Character,Integer> > data = new HashSet<Map<Character,Integer>>();
for(int i=0;i<a.length;i++){
Map<Character,Integer> tem = new HashMap<Character, Integer>();
for(int j=0;j<a[i].length();j++)
if(tem.containsKey(a[i].charAt(j))){
int x=tem.get(a[i].charAt(j));
x++;
tem.put(a[i].charAt(j), x);
}else
tem.put(a[i].charAt(j), 1);
if(data.contains(tem)){
continue;
}else
data.add(tem);
}
第二种情况,HashMap中为<Map<Character,Integer>,String>,这个例子里面的数据结构更加复杂,我同样以上面的输入为例,只是,在下面的代码中,我保存了String的初始
数据,所以虽然压缩后变为无序了,但不影响初始信息:
HashMap<Map<Character,Integer>,String> data = new HashMap<Map<Character,Integer>,String>();
for(int i=0;i<a.length;i++){
Map<Character,Integer> tem = new HashMap<Character, Integer>();
for(int j=0;j<a[i].length();j++)
if(tem.containsKey(a[i].charAt(j))){
int x=tem.get(a[i].charAt(j));
x++;
tem.put(a[i].charAt(j), x);
}else
tem.put(a[i].charAt(j), 1);
if(data.containsKey(tem)){
String tem2=data.get(tem);
if(tem2.compareTo(a[i])>0)
data.put(tem, a[i]);
}else
data.put(tem, a[i]);
}
且HashMap与HashSet都可以使用迭代器进行遍历:
Iterator it = data.entrySet().iterator();
ArrayList<String> res = new ArrayList<String>();
while(it.hasNext()){
Map.Entry tem=(Map.Entry) it.next();
String qq=(String) tem.getValue();
res.add(new String(qq));
}
接下来介绍更为复杂的情况,HashMap为<Class:Integer>的情况:
演示同样为牛客上的一道题:穿点最多的直线
在二维平面上,有一些点,请找出经过点数最多的那条线。
class Point {
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
class Line{
double k;
double j;
public Line(double k,double j){
this.k=k;
this.j=j;
}
public boolean isEqual(double a,double b){
return (Math.abs(a-b)<0.0001);
}
public boolean equals(Object obj){//重写equal方法
if(obj instanceof Line){
if(isEqual(k, ((Line) obj).k)&&isEqual(j, ((Line) obj).j))
return true;
return false;
}
return super.equals(obj);
}
public int hashCode() {//重写class的hashcode的方法
String str=String.valueOf(k)+String.valueOf(j);
return str.hashCode();
}
}
public double[] countK(double x1,double y1,double x2,double y2){//计算两点之间的斜率和截距
double res[]={0,0};
if(x1==x2){
res[0]=1.0;
res[1]=x1;
}else if(y1==y2){
res[0]=0.0;
res[1]=y1;
}else{
res[0]=(y2-y1)/(x2-x1);
res[1]=y1-res[0]*x1;
}
return res;
}
public double[] getLine(Point[] p, int n) {//求一条经过最多点的直线的斜率和截距
HashMap<Line,Integer> lineNum = new HashMap<Line,Integer>();
int max=0;
double res[]={0,0};
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(i==j) continue;
double []a=countK(p[i].x,p[i].y,p[j].x,p[j].y);
Line line = new Line(a[0],a[1]);
// System.out.println(line.hashCode());
if(lineNum.containsKey(line)){
int num = lineNum.get(line)+1;
lineNum.put(line, num);
if(num>max){
max=num;
res[0]=a[0];
res[1]=a[1];
}
System.out.println(num);
}else
lineNum.put(line, 1);
}
System.out.println(res[0]+" "+res[1]+" "+max);
return res;
}
double res[]={0,0};
if(x1==x2){
res[0]=1.0;
res[1]=x1;
}else if(y1==y2){
res[0]=0.0;
res[1]=y1;
}else{
res[0]=(y2-y1)/(x2-x1);
res[1]=y1-res[0]*x1;
}
return res;
}
public double[] getLine(Point[] p, int n) {//求一条经过最多点的直线的斜率和截距
HashMap<Line,Integer> lineNum = new HashMap<Line,Integer>();
int max=0;
double res[]={0,0};
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(i==j) continue;
double []a=countK(p[i].x,p[i].y,p[j].x,p[j].y);
Line line = new Line(a[0],a[1]);
// System.out.println(line.hashCode());
if(lineNum.containsKey(line)){
int num = lineNum.get(line)+1;
lineNum.put(line, num);
if(num>max){
max=num;
res[0]=a[0];
res[1]=a[1];
}
System.out.println(num);
}else
lineNum.put(line, 1);
}
System.out.println(res[0]+" "+res[1]+" "+max);
return res;
}
由上可以看到,当Key为一个对象时,需要我们重写hashcode和equal方法,否则,因为对象地址不同,key就不会相同,就不会找到两条两条重合的直线。
相信有了上面的一些讲解,一定会触发你的灵感,希望能对你解决问题有所帮助。