最近,在进行编程的时候,对于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);}elsetem.put(a[i].charAt(j), 1);if(data.contains(tem)){continue;}elsedata.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);}elsetem.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]);}elsedata.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);}elselineNum.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);}elselineNum.put(line, 1);}System.out.println(res[0]+" "+res[1]+" "+max);return res;}
由上可以看到,当Key为一个对象时,需要我们重写hashcode和equal方法,否则,因为对象地址不同,key就不会相同,就不会找到两条两条重合的直线。
相信有了上面的一些讲解,一定会触发你的灵感,希望能对你解决问题有所帮助。