重写hashcode和equal方法让HashMap与HashSet更强大

最近,在进行编程的时候,对于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就不会相同,就不会找到两条两条重合的直线。
相信有了上面的一些讲解,一定会触发你的灵感,希望能对你解决问题有所帮助。

发布了27 篇原创文章 · 获赞 212 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_34666857/article/details/70792931
今日推荐