JAVA集合框架之List、Map、Set之间的选择~小案例分析

时间:2021-05-21 19:24:11

案例分析

案例介绍:简易扑克牌游戏。

功能描述:

JAVA集合框架之List、Map、Set之间的选择~小案例分析

二:实现洗牌

三:实现发牌

四:得出输赢

集合(list、set、map)的选择

既然要比较,我们还是先从JAVA集合的祖先来介绍。

数组

时间本没有集合,但有人想要,所以有了集合
有人想有可以自动扩展的数组,所以有了List
有的人想有没有重复的数组,所以有了set
有人想有自动排序的组数,所以有了TreeSet,TreeList,Tree**

1.数组是固定大小的,你在创建的时候必须确定它的大小,你并不能知道数组内实际存储了多少数据,除非你创建的时候是知道自己用多大的,而集合则是根据需要动态增长。

2.数组内必须存储同类型的数据,而集合内的对象全是以object存储的,取出来要进行数据类型转换。

3.数组是既可以读又可以写的,而集合集合提供的ReadOnly方法,以只读方式来使用集合。

list、set、map的比较

list:有序,可重复,善于随机访问、删除和插入。
set:无序,不克重复,善于比较和查询对象。(这里的无序是指当读取时不是按插入的顺序,但是它是按某种顺序来排序的,所以运行几次出来的顺序都是一样的
map:映射,相当于小型数据库,键相当于数据库的主键(只有一个),值相当于整条数据,方便我们根据键(特定标识)访问。

案例集合的选择

洗牌:需要每次发牌时和原来“不完全一样”,我们是否能能利用set的无序呢?
上面比较的时候已经说明了,只能人为的打乱顺序了,所以还是用list吧,方便读取,再来打乱顺序?
打乱顺序用随机数?

比较输赢: set善于比较。

所以我们决定用set。装整幅牌用ArryList,装牌友的牌用treeset

大家在要根据自己项目的性质选择合适的集合,选择合适的子类。

具体代码

1.牌类(Poker)代码和介绍

package PokerGame;

public class Poker implements Comparable<Poker> {
private String point;
private String color;

public Poker(String point, String color) {
this.point = point;
this.color = color;
}

public String getPoint() {
return point;
}

public void setPoint(String point) {
this.point = point;
}

public String getColor() {
return color;
}

public void setColor(String color) {
this.color = color;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((color == null) ? 0 : color.hashCode());
result = prime * result + ((point == null) ? 0 : point.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Poker other = (Poker) obj;
if (color == null) {
if (other.color != null)
return false;
} else if (!color.equals(other.color))
return false;
if (point == null) {
if (other.point != null)
return false;
} else if (!point.equals(other.point))
return false;
return true;
}

/*
* 先比较点数在比较花色,如果点数不同就不用比较花色了。
*/

@Override
public int compareTo(Poker o) {
// TODO Auto-generated method stub
/*
* 先比较点数
*/

int num = 0;
if (this.PointTransformatio() > o.PointTransformatio()) {
num = 1;
}
// 如果点数相等,再比较花色
else if (this.PointTransformatio() == o.PointTransformatio()) {
if (this.ColorTransformatio() > o.ColorTransformatio()) {
num = 1;
}
if (this.ColorTransformatio() == o.ColorTransformatio()) {
num = 0;
}
if (this.ColorTransformatio() < o.ColorTransformatio()) {
num = -1;
}
} else
num = -1;
return num;

}

/*
* 写一个方法把 J、Q、K、A转化为int类型的11 12 13 14 2——10转化为int类型的2——10
*/

public int PointTransformatio() {
String c = this.point;

int it;
switch (c) {
case "J":
it = 11;
break;
case "Q":
it = 12;
break;
case "K":
it = 13;
break;
case "A":
it = 14;
break;
default:
it = Integer.parseInt(c);
}
return it;
}
/*
* 写一个方法把黑桃、红桃、梅花、方块转换为int类型的1-4
*/


public int ColorTransformatio() {
String s = this.color;
int it = 0;
switch (s) {
case "黑桃":
it = 1;
break;
case "红桃":
it = 2;
break;
case "梅花":
it = 3;
break;
case "方块":
it = 4;
break;

}

return it;
}

/*
* 写一个方法合计point和color得出最终的大小数值, 这种通过最终值来比较牌的大小是不行的, 因为牌的大小是先看点数再看花色,
* 还是得一步一步比较, 所以此方法作废
*/

/*
* public int FinalValue() { int fv; fv = this.PointTransformatio() +
* this.ColorTransformatio(); return fv;
*
* }
*/


}

注意:

1.我们把玩家的牌是放在treeset中的(可以实现插入后直接比较),所以一定要实现牌的比较(先比较点数在比较花色,重写compareTo()方法)。

2.我的比较是把点数和花色原来的char型认为赋为int值,方便比较。

实现发牌、洗牌、得出胜负的代码

package PokerGame;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;

public class PokerSetTest {

private List<Poker> hs;// 用来装一副牌的
private TreeSet<Poker> ts1;// 玩家一用来装牌的
private TreeSet<Poker> ts2;// 玩家二用来装牌的
private int i[] = new int[52];

public PokerSetTest() {
this.hs = new ArrayList<Poker>();
this.ts1 = new TreeSet<Poker>();
this.ts2 = new TreeSet<Poker>();
}

/*
* 添加牌
*/

public void addpoker() {

String s1[] = { "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A" };
String s2[] = { "黑桃", "红桃", "梅花", "方块" };
for (int i = 0; i < s1.length; i++)
for (int j = 0; j < s2.length; j++) {
hs.add(new Poker(s1[i], s2[j]));
}

}

/*
* 利用Iterator访问
*/

public void testIterator(Collection<Poker> hs) {
Iterator it = hs.iterator();
int size = hs.size();

System.out.println("取出集合内的元素如下:");
// System.out.println("本集合的大小为:" + hs.size());
while (it.hasNext()) {
Poker po = (Poker) it.next();
System.out.print(po.getPoint() + ":" + po.getColor() + "...");
}
System.out.println();
}

/*
* 打乱list里面元素的数据‘ 利用随机数,取出0-51中52个不同的随机数 返回数组
*/

public static int[] randomCommon(int min, int max, int n) {
// System.out.println("////"+n);
if (n > (max - min) || max < min) {
// System.out.println("sdsd////"+n);
return null;
}
int[] result = new int[n];
int count = 0;
while (count < n) {
int num = (int) (Math.random() * (max - min));
boolean flag = true;
for (int j = 0; j <= count; j++) {
if (num == result[j]) {
flag = false;

break;
}
}
if (flag) {
result[count] = num;
// System.out.println("第"+count+"个:"+num);
count++;
}
/*
* 因为总是要和原来的数组比较,而数组默认值为0, 如果开始第一个数随机取出不是0还好,
* 如果第一个随机数是0那样就和默认的值相等了,flag就变成false
* 但是0是可以放进去的,如果想应变这样的情况还要写判断语句等方法, 比较麻烦,所以采取默认最后一个值不取随机数,默认为0
*/

// 到最后一个的时候退出语句
if (count == n - 1) {
break;
}

}
return result;
}

/*
* 打乱牌 每一张牌和随机比这张下标大的牌互相交换
*/

public void UpsetCards() {

int in[];
int wo;
// in=randomCommon(0,hs.size(),hs.size());这种方法没有用
for (int i = 0; i < hs.size(); i++) {

Poker p1 = hs.get(i);
do {
wo = (int) (Math.random() * 51);
} while (wo > i);
Poker p2 = hs.get(wo);
hs.set(i, p2);
hs.set(wo, p1);
i++;
}
}

/*
* 1.发牌,没人每次只发两张牌,轮流发 2.比较大小
*/

public void givepoker() {
// 每次发牌都刷新
UpsetCards();
testIterator(hs);
for (int i = 0; i < 4; i++) {
ts1.add(hs.get(i));
ts2.add(hs.get(++i));

}
System.out.println("给玩家一发牌:");
testIterator(ts1);
System.out.println("给玩家二发牌:");
ts2.add(hs.get(3));
testIterator(ts2);
/*
* 比较大小
*/

if(ts1.last().compareTo(ts2.last())>0)
{
System.out.println("恭喜玩家一赢了本次比赛");
}
else
{
System.out.println("恭喜玩家二赢了本次比赛");
}
// 发完牌了清空
ts1.clear();
ts2.clear();
}

public static void main(String[] args) {
// TODO Auto-generated method stub
PokerSetTest po = new PokerSetTest();
po.addpoker();
// po.testIterator(po.hs);
// System.out.println();
// System.out.println(".........第一次打乱牌.........");
// po.UpsetCards();
// po.testIterator(po.hs);
// System.out.println();
// System.out.println(".........第二次打乱牌.........");
// po.UpsetCards();
// po.testIterator(po.hs);
po.givepoker();

}

}

注意:

1.本来洗牌我是想通过,随机产生52个随机数再把这些随机数下标元素赋从头开始赋值给集合的每个元素,但是这会产生问题~随机取会取出重复的值,原因是你把随机数下标的元素赋值后,随机数很可能取出被赋值的数,这样就产生重复了,虽然52个随机数保证了不同。最后的解决方案代码已写。(具体看代码,和自己测试)

2.每次抓两张牌,抓完了要clear.

结语:

本案例涉及肯定不够全面,只是通过一个案例来演示自己的思考过程,还是需要自己去掌握集合的基本知识选择出合适自己项目的集合。