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.
結語:
本案例涉及肯定不夠全面,只是通過一個案例來演示自己的思考過程,還是需要自己去掌握集合的基本知識選擇出合適自己專案的集合。