Java常用資料結構(個人筆記)
寫在前面:
樓主剛打完ACM徐州現場賽,也算是退役了,現在準備重新補一遍Java,之前一直用的是C++,所以我會結合C++來整理Java的資料結構,同時也便於理解。
那麼我將按照以下順序進行講解,感覺難度也是逐步提升
ArrayList、Vector和Linkedlist的用法
Stack、Queue的用法
Set 用法
Map 用法
下面開始我的表演
①ArrayList
ArrayList是最常用的List實現類,內部是通過陣列實現的,它允許對元素進行快速隨機訪問
其實吧,個人理解他就是個陣列,只不過封裝了,有各種操作。
定義:
ArrayList a = new ArrayList(); ArrayList<Integer> b = new ArrayList<Integer>();
這裡的Integer可以換成任何其他類。
第一種定義可以不指明ArrayList的型別,那麼插入的資料可以是任意型別;
第二種明確了型別,只能插入相應型別的資料。
操作:
1. add( Object obj ); 加入元素到尾部
a.add(2);
a.add( new person("小明",1) );
b.add(4);
b.add(5);
因為之前的a我們沒指名型別,所以我們可以add任意型別的東西進去,b就只能add Integer型別的。
這個絕逼是最常用的,相當於C++裡面的push_back();
至於他的返回值,是boolean,也就是C++的bool,表示是否add成功,但是返回值我們一般不用
然後add還可以指定位置
add( int index,Object obj);
b.add(1, 222); //在1位置處插入222,後面的元素index加1(如果有的話)
這個帶插入位置的add就相當於C++的insert,在某個位置插入一個元素,使後面的元素後移。
但是個人建議不要用這個,這個插入效率比較低。
2.get( int index ); 得到指定位置的元素
int t = (Integer)a.get(0); //下標是從0開始的 person p = (person)a.get(1); int t2 = b.get(0); int t3 = b.get(1);
這裡我們注意到a的get都要強制轉換,而b不需要,因為a在定義時候就沒有明確,所以這是必然的。
3.remove( int index ) 刪除指定位置的元素,後面元素向前挪
a.remove(0);
它的返回值也是boolean,表示是否刪除成功。
同樣,因為是陣列實現,所以刪除效率就很低。
4.int size(); 得到ArrayList的大小
int t = b.size();
常用而又簡單
5.sort( Comparator c ); 進行排序,還需要定義比較器,個人覺得比較麻煩
b.sort( new mycomparator() );
//定義 mycomparator
class mycomparator implements Comparator<Integer>
{
public int compare(Integer o1, Integer o2)
{
if( o1 > o2 )
return 1;
return -1;
}
}
如果覺得不太理解可以去查查Java排序的相關知識
6.void clear(); 清空
a.clear();
就和C++的clear一樣
下面是ArrayList用法小彙總,大家可以舉一反三
import java.util.*;
public class Main
{
public static void main( String args[] )
{
ArrayList a = new ArrayList(); //定義ArrayList 不明確型別
a.add(1);
a.add( new Person("小明",12) );
a.add(0, 123); //在0位置處插入123
int t = (int)a.get(0); //不加強制轉化 會報錯
System.out.println(t); //輸出t 結果是123
a.remove(0); //刪除位置0處的元素,後面的向前面移動
for( int i = 0 ; i < a.size() ; i++ ) //遍歷ArrayList
System.out.println( a.get(i) );
a.clear(); //清空
if( a.isEmpty() ) //呼叫 isEmpty方法
System.out.println("ArrayList已經空了");
}
}
class Person
{
String name;
int age;
Person( String name,int age )
{
this.name = name;
this.age = age;
}
public String toString()
{
return "name "+name+"\n"+"age "+age;
}
}
②Vector的用法
其實Vector和ArrayList簡直是一模一樣,至少操作是這樣
如果想了解它們的區別,可以參考
③LinkedList
LinkedList的基本用法其實和ArrayList差不多,但是它的儲存方式和之前的不一樣,所以還是有一丟丟不同。
總的來說,LinkedList 增加和刪除效率要比ArrayList要高。 畢竟是連結串列,改一下指標就行了
但是訪問的效率並不高。
定義
LinkedList l = new LinkedList();
LinkedList<Person> ll = new LinkedList<Person>();
操作:
add( Object obj)、remove(int index)、size()、isEmpty()、sort()、clear()這些都和之前的一樣,我就不講啦
不同的有:
void addFirst( Object obj ); //隊首插入
void addLast( Object obj ); //隊尾插入,和add( Object obj )效果一樣
l.addFirst(1);
l.addLast(2);
同樣remove也有兩種
Object removeFirst( );
Object removeLast( );
當然,返回值可以要,也可以不要
l.removeFirst();
l.removeLast();
int t = (int)l.removeLast();
int t2 = (int)l.removeFirst();
下面是LinkedList的用法小彙總
import java.lang.reflect.Array;
import java.math.*;
import java.util.*;
public class Main
{
public static void main(String[] args)
{
Person p1 = new Person("小明",12);
Person p2 = new Person("小紅",16);
Person p3 = new Person("小哥哥",13);
LinkedList<Person> ll = new LinkedList<Person>(); //定義一個LinkedList
ll.add(p1);
ll.add(p2);
ll.add(p3);
ll.sort( new mycomparator() ); //進行排序
ll.addFirst( new Person("大哥",22) );
for( int i = 0 ; i < ll.size() ; i++ )
System.out.println( ll.get(i) );
ll.removeFirst();
ll.removeLast();
Person temp = ll.removeFirst(); //刪除第一個
ll.removeFirst();
if( ll.isEmpty() ) //呼叫isEmpty方法
System.out.println("LinkedList空了");
else
{
Person tt = ll.get(0); //get函式
ll.removeFirst();
}
ll.clear(); //清空
}
}
class Person
{
String name;
int age;
public Person( String name,int age )
{
this.name = name;
this.age = age;
}
public String toString()
{
return "name "+name+"\n"+"age "+age;
}
}
class mycomparator implements Comparator<Person>
{
public int compare(Person a, Person b ) //年齡從大到小排序
{
if( a.age < b.age )
return 1;
return -1;
}
}
④Stack用法
Stack意思是棧,具有先進後出的特點
與C++不同的是,Java的Stack遍歷方式可以多樣,因為Stack可以取到任意位置的值,而C++只能中規中矩的遍歷。
可見Java的操作比C++更多
定義:
Stack<Integer> s = new Stack<Integer>();
Stack ss = new Stack();
操作:
push( Object obj ); 插入元素到棧頂
add( Object obj ); 插入元素到尾部 效果和push一樣
Stack<Integer> s = new Stack<Integer>();
s.push(1);
s.add(2);
boolean empty(); 判斷佇列是否為空
Object peek(); 取棧頂元素
Object pop(); 刪除棧頂元素,返回的是刪除的元素
int size(); 返回棧的大小
結合以上幾個方法,我們可以寫出Stack的兩種遍歷方法
System.out.println("遍歷");
for( int i = s.size()-1 ; i >= 0 ; i-- ) //從後往前遍歷
System.out.println(s.get(i) );
System.out.println("遍歷");
while( s.empty() == false )
{
int t = s.peek();
s.pop();
System.out.println(t);
}
void sort(); 之前已經講過啦,參加ArrayList的sort
void clear(); 清空
下面是Stack用法小彙總
public class Main
{
public static void main(String[] args)
{
Stack<Integer> s = new Stack<Integer>();
s.push(1);
s.add(2); //add和push效果一樣
s.push(3);
System.out.println( "位置為 1的地方是 "+ s.elementAt(1) ); //呼叫elementAt方法
System.out.println("從前向後遍歷");
for( Integer i:s ) //從前向後遍歷 用到了foreach迴圈
System.out.println(i);
System.out.println("從後向前遍歷");
for( int i = s.size()-1 ; i >= 0 ; i-- ) //從後往前遍歷
System.out.println(s.get(i) );
System.out.println("類似C++Stack的遍歷");
while( s.empty() == false )
{
int t = s.peek();
s.pop();
System.out.println(t);
}
s.clear(); //清空棧
}
}
⑤Queue用法
Queue就是佇列,具有先進先出的特點
在Java中,沒有Queue這個類,而是用到了LinkedList,所以我們定義的時候有點特殊
定義:
Queue q = new LinkedList();
Queue<String> qq = new LinkedList<String>();
操作:
boolean add( Object obj ); 向佇列中插入一個元素
boolean offer( Object obj ); 向佇列中插入一個元素
可以看出兩個方法的功能一樣,但是推薦使用第二個,在網上看的說add操作失敗時會丟擲異常,有點不是很明白
如果有問題的可以自己去百度一下吧
Object peek(); 返回隊首元素
Object poll(); 刪除並返回隊首元素
當然因為是LinkedList實現的,所以LinkedList有的操作它都有,那麼我就偷一下懶,不寫啦
下面是Queue用法小彙總
public class Main
{
public static void main(String[] args)
{
Queue<String> q = new LinkedList<String>(); //定義一個Sting類的Queue
q.add("1"); //向隊首加入元素
q.offer("1"); //功能與上一個一樣,但是推薦使用第二個
q.offer("2");
q.offer("3");
q.poll(); //刪除隊首元素
String t = q.peek(); //取隊首元素
System.out.println("foreach 遍歷佇列");
for( String s:q )
System.out.println(s);
System.out.println("類似C++的佇列遍歷");
while( q.isEmpty() == false )
{
String s = q.peek();
q.poll();
System.out.println(s);
}
q.clear();
}
}
⑥Set用法
Set表示集合,不能允許元素重複
Set又包括HashSet和TreeSet,第一個不自動排序,第二個自動排序
C++中STL有MultiSet(允許元素重複),而Java中自帶的沒有,似乎要自己去下載。
另外,Set是一個藉口,不能例項化一個Set物件
Set繼承Collection藉口,所以有Collection的常見操作
定義:
Set s1 = new HashSet();
Set s2 = new TreeSet();
//或者
HashSet s3 = new HashSet();
TreeSet s4 = new TreeSet();
操作:
這裡我偷一下懶,直接放張圖片,嘻嘻
下面是Set用法小彙總
public class Main
{
public static void main(String[] args)
{
Set<String> s1 = new HashSet<String>();
Set<String> s2 = new TreeSet<String>();
s1.add("ABC");
s1.add("ABC");
s1.add("AAA");
s2.add("AB");
s2.add("BB");
s2.add("CC");
System.out.println("遍歷HashSet");
Iterator<String> it = s1.iterator();
while( it.hasNext() )
{
String t = it.next();
System.out.println(t);
}
s1.remove("ABC"); //刪除ABC
if( s1.contains("ABC") ) //呼叫contains方法,判斷Set是否包含某個元素
System.out.println("ABC 還在");
if( s1.isEmpty() ) //使用 isEmpty方法
System.out.println("s1空了");
System.out.println("遍歷TreeSet");
Iterator<String> it2 = s2.iterator(); //TreeSet結果會自動排序
while( it2.hasNext() )
{
String t = it2.next();
System.out.println(t);
}
s1.clear(); //清空
s2.clear();
}
}
⑦Map用法
個人感覺Map是常用的資料結構裡面最難的。
首先我們要知道map儲存資料的方式,map儲存資料的形式是一個key和一個value對應,即Map<String,String> map = new HashMap<String,String>(); 其儲存的資料型別可以是任意的。
定義:
Map<String,Integer> m = new HashMap<String,Integer>(); //String 到 int的對映
操作:
put( Object Key,Object Value ); 插入一組值
remove( Object Key ); 刪除鍵值為Key的那一組
get( Object Key ); 得到鍵值為Key的那一組的Value
entrySet(); 得到Pair集合(個人是這樣理解的,pair就是一組)
keySet(); 得到Key集合
values(); 得到values集合
要想搞清楚Map,就要先搞清楚Key,Value和Entry的區別,
例如 Map<String,Integer> m = new HashMap<String,Integer>();
中,String就是Key,Integer就是Value,而<String,Integer> 是一組Entry
所有組Entry構成了EntrySet
所有Key構成KeySet,同樣所有Value構成ValueSet
下面是Map用法小彙總:
主要理解遍歷啊
public class Main
{
public static void main(String[] args)
{
Map<String,Integer> m = new HashMap<String,Integer>(); //String 到 int的對映
m.put("小明", 12);
m.put("小紅", 11); //向Map中插入一組值
m.put("小呆", 20);
m.remove("小呆"); //刪除Key為小呆的一組值
Integer t = m.get("小明"); //得到key為小明所在的值
System.out.println(t); //得到結果為12
//下面是Map的4種遍歷方法
System.out.println("Map遍歷方法1:KeySet遍歷"); //通過Key找Value,可想效率不是很高
for( String key: m.keySet() )
System.out.println(" Key:"+key+" "+"value:"+m.get(key) );
System.out.println("Map遍歷方法2:ValueSet遍歷"); //只遍歷Map的value,不能遍歷Key,所以有缺陷,但是比較快
for( Integer i:m.values() )
System.out.println("value "+i);
System.out.println("Map遍歷方法3: EntrySet遍歷"); //遍歷Map的每一組,推薦使用這種方法
for( Map.Entry<String, Integer> entry : m.entrySet() )
System.out.println(" Key "+entry.getKey()+ " "+"value: "+entry.getValue() );
System.out.println("Map遍歷方法4: EntrySet+Iterator遍歷"); //比較複雜
Iterator< Map.Entry<String,Integer> > it = m.entrySet().iterator();
while( it.hasNext() )
{
Map.Entry<String, Integer> entry = it.next();
System.out.println(" Key "+entry.getKey()+ " "+"value: "+entry.getValue() );//這一步和上一種遍歷一樣
}
}
}
另外Map還有一個HashTable,但是兩者的差別是非常小的,而且HashTable已經快被淘汰
感興趣的可以參考下面連結
總結:
雖然我將的順序是這樣,但是分類的順序卻有些不一樣
List介面是被四個類實現了
分別是ArrayList、LinkedList、Vector、Stack
Map介面是兩個
HashMap、HashTable
Set介面是兩個
HashSet、TreeSet
Queue介面是一個
所以我想說的是,程式設計時應該養成使用介面定義的好習慣,
即如果定義ArrayList ,用 List a = new ArrayList(); 而不是 ArrayList a = new ArrayList();
如果定義LinkedList ,用 List ll = new LinkedList(); 而不是 LinkedList ll = new LinkedList();
至於為什麼,
一句話,更靈活一些。
----------------------------------------------------------------------------------------------------------------------------------------------------
以上就是Java的常用資料結構啊,樓主知識短淺,還望多多指正。
第一次編輯,以後還會再回來看的。
---------------------2018/11/1