線性表、佇列和棧
集合操作------線性表
1、 List
2、 List的排序
3、 佇列和棧
List:
1、 get和set
List除了繼承Collection定義的方法外,還根據其線性表的資料結構定義了一系列方法,其中最常用的就是基於下表的get和set方法:
--E get(int index):獲取集合中指定下標對應的元素,下標從0開始。
--E set(intindex,E element):將給定元素存入給定位置,並將原位置的元素返回。
2、插入和刪除
List根據下標的操作還支援插入與刪除操作。
--add(int index,E element):將給定的元素插入到指定的位置,原位置及後續元素都順序向後移動。
--remove(int index)
3、ArrayList(變長陣列)和LinkedList(雙向迴圈列表)
List介面是Collection的子介面,用於定義線性表資料結構。可以將List理解為存放物件的陣列,只不過其元素個數可以動態的增加或減少。
List介面的兩個常見實現類為ArrayList和LinkedList,分別用動態陣列和連結串列的方式實現了List介面。
可以認為ArrayList和LinkedList的方法再邏輯上完全一樣,只是在效能上有一定的差別。ArrayList更適合隨機訪問,而LinkedList更適合在頭部和尾部插入和刪除。在效能要求不是特別苛刻的情況下可以忽略這個差別。
public void testList1() { Random rand=new Random(); ArrayList<Integer> list1=new ArrayList<Integer>(); LinkedList<Integer> list2=new LinkedList<Integer>(); for(int i=0;i<10000;i++) { int j=rand.nextInt(); list1.add(j); list2.add(j); } //反覆在集合的頭部(0號位置)新增刪除元素 long t1=System.nanoTime();//納秒 for(int i=0;i<10000;i++) { list1.add(0,5);//將5插入到0號位置,後面元素將順序向後移動,是很消耗效能的。 list1.remove(0);//將0號元素刪掉,後面元素將順序向前移動,是很消耗效能的。 } long t2=System.nanoTime(); for(int i=0;i<10000;i++) { list2.add(0,5);//插入,按位置插入 list2.remove(0);//刪除,按位置刪除 } long t3=System.nanoTime(); System.out.println("順序表消耗的時間:"+(t2-t1));//順序表消耗的時間:26815138 System.out.println("雙向連結串列消耗的時間:"+(t3-t2));//雙向連結串列消耗的時間:3252906 //結論:LinkedList頭尾新增和刪除效能好於ArrayList t1=System.nanoTime(); for(int i=0;i<10000;i++) { int n=list1.get(5000);//獲取指定index位置的元素 } t2=System.nanoTime(); for(int i=0;i<10000;i++) { int n=list2.get(5000); } t3=System.nanoTime(); System.out.println("順序表消耗的時間:"+(t2-t1));//順序表消耗的時間:596195 System.out.println("雙向連結串列消耗的時間:"+(t3-t2));//雙向連結串列消耗的時間:102743580 //結論:ArrayList(中部)的讀取效能好於LinkedList //當不知道該選用哪個List的時候,就選用ArrayList。 }
public void testList() {
List<String> list=new ArrayList<String>();
list.add("Tom");//在尾部新增
list.add("Jerry");//在尾部新增
System.out.println(list);//[Tom, Jerry]
// 0 1
String name=list.get(1);//返回1號位置的元素
System.out.println(name);//Jerry
String one=list.set(1, "Nemo");//set 將1號位置的Jerry換成Nemo,並且將Jerry返回
System.out.println(one);//Jerry
System.out.println(list);//[Tom, Nemo]
list.add(1, "Jerry");//在1的位置新增Jerry,其餘的元素順序後移
System.out.println(list);//[Tom, Jerry, Nemo]
list.remove(0);//將0號位置的元素刪除,其餘元素順序向前移動
System.out.println(list);//[Jerry, Nemo]
//以上方法都是與index(位置)有關的操作方法,是List擴充套件的方法,此外List還從Collection繼承了全部的集合操作方法
}
4、 subList:
List的subList方法用於獲取子List。需要注意的是,subList獲取的List與原List佔有相同的儲存空間,對subList的操作會影響原List。
List<E>subList(int fromIndex,int toIndex);fromIndex和toIndex是擷取List的首尾下標,包括fromIndex,不包括toIndex。
public void testSublist() {
List<String> cards=new ArrayList<String>();
cards.add("黑桃2");//0
cards.add("紅桃2");//1
cards.add("紅桃10");//2
cards.add("梅花10");//3
cards.add("方片10");//4
cards.add("黑桃10");//5
cards.add("黑桃3");//6
List<String> bomb=cards.subList(2, 6);//炸彈是從2到6,包括2,不包括6
System.out.println(bomb);//[紅桃10, 梅花10, 方片10, 黑桃10]
bomb.clear();
System.out.println(cards);//[黑桃2, 紅桃2, 黑桃3]
//list和sublist共享一塊記憶體空間
}
總結List:
List繼承了Collection,擴充套件了與位置有關的操作方法,實現類有兩個:ArrayList和LinkedList,兩個實現類的方法一致,都是List。任何時候,需要使用集合,但是不能確定使用哪個實現類的時候,首先選擇ArrayList。
5、 List轉換為陣列
List的toArray方法用於將集合轉換為陣列。但實際上該方法是在Collection中定義的,所以所有的集合都具備這個功能。
其有兩個方法:
Object[] toArray;這個只能轉換成Object型別的陣列
public void testToArry1() {
//Java先編譯後執行,編譯階段沒有物件,只有變數的型別,執行期間才有物件,物件可能是多型的。
Collection<String> list=new ArrayList<String>();
list.add("Tom");
list.add("Andy");
list.add("Nemo");
list.add("Jerry");
Object[] names=list.toArray();
//names的每個元素變數型別是Object型別,元素變數型別不是String型別!不是String[]!
//[Object[0],Object[1],...]
System.out.println(Arrays.toString(names));//[Tom, Andy, Nemo, Jerry]
//返回“執行期間”物件的型別!
System.out.println(names[0].getClass().getName());//java.lang.String
}
<T>T[] toArray(T[] a);可以轉換成指定型別的陣列,如果這個陣列的長度小於陣列元素的個數,則返回新陣列。如果陣列的長度大於陣列元素的個數,返回原陣列,沒有值的陣列位置存放null。
public void testToArray2() {
Collection<String> list=new ArrayList<String>();
list.add("Tom");
list.add("Andy");
list.add("Nemo");
list.add("Jerry");
String[] name1=new String[2];//新建一個String型別的陣列,長度為2,但是新增的元素個數是4,陣列長度不夠,則返回新陣列
String[] name2=new String[6];//新建一個String型別的陣列,長度為6,但是新增的元素個數是4,沒有值的填充0,返回原陣列
String[] name3=new String[list.size()];//最理想的情況下
//返回的是String[]型別的陣列
name1=list.toArray(name1);//返回新陣列
name2=list.toArray(name2);//返回原陣列
name3=list.toArray(name3);//返回原陣列
System.out.println(Arrays.toString(name1));//[Tom, Andy, Nemo, Jerry]
System.out.println(Arrays.toString(name2));//[Tom, Andy, Nemo, Jerry, null, null]
System.out.println(Arrays.toString(name3));//[Tom, Andy, Nemo, Jerry]
}
6、 陣列轉換為List
Arrays類中提供了一個靜態方法asList,使用該方法我們可以將一個數組轉換為對應的List集合。返回的List的集合元素型別由傳入的陣列的元素型別決定。並且需要注意的是,返回的集合我們不能對其進行增刪元素,否則會丟擲異常。並且對集合的元素進行修改會影響陣列對應的元素。
public void testAsList() {
//陣列轉換為List
String[] names= {"Tom","Andy","Jerry"};
//list是靜態的list,長度不能改變,也就是不能呼叫add和remove
List<String> list1=Arrays.asList(names);
//靜態list和name共享同一個記憶體空間,改陣列,list也會被更改
//不是ArrayList也不是LinkedList,這個list的型別是內部類
System.out.println(list1.getClass().getName());//java.util.Arrays$ArrayList是一個內部類
System.out.println(list1);//[Tom, Andy, Jerry]
//list1.remove(0);//會出現執行異常,不支援的操作
//list1.add();
//陣列轉換為List的第二種方法
List<String> list2=new ArrayList<String>();
//list2和name不共享記憶體空間,更改陣列,對list沒有影響
Collections.addAll(list2, names);//將names中所有元素新增到list2中
System.out.println(list2.getClass().getName());//java.util.ArrayList
System.out.println(list2);
//靜態List與陣列names共享相同的儲存空間
//修改陣列names影響線性表List
names[1]="Lee";
System.out.println(list1);//[Tom, Lee, Jerry]
System.out.println(list2);//[Tom, Andy, Jerry]
}
List的排序:
排序:按照一定的大小順序排序
比較大小:比較兩個元素的大小
public void testStringCompare() {
//String型別如何比較大小
//在String類中有一個方法compareTo
String s1;
String s2;
s1="A";
s2="B";
if(s1.compareTo(s2)>0) {
System.out.println("s1大於s2");
}
if(s1.compareTo(s2)<0) {
System.out.println("s1小於s2");
}
if(s1.compareTo(s2)==0) {
System.out.println("s1等於s2");
}
//String是可以比較大小的,包含預設
//比較大小的方法compareTo
//Java中凡是可以預設比較大小的型別,都有compareTo,比如:包裝類Date
//有compareTo方法的類,稱為可以自然的類
//compareTo是compareable介面定義的方法,可以自然排序的類都實現了這個介面
//凡是實現compareable,實現了compareTo方法的類,都可以進行自然(預設)排序。
}
1、 Collections.sort方法實現排序
Collections是集合的工具類,它提供了很多便於我們操作集合的方法,其中就有用於集合排序的sort方法。
該方法的定義為:
--voidsort(List<T> list):該方法的作用是對給定的集合元素進行自然排序。
List的每個元素要有預設比較規則,sort根據元素的預設比較規則進行排序,若沒有預設的比較規則,則不能排序。
public void testSort1() {
List<Integer> list=new ArrayList<Integer>();
Random ran=new Random();
for(int i=0;i<10;i++) {
list.add(ran.nextInt(100));
}
System.out.println(list);//[16, 44, 85, 60, 19, 98, 31, 57, 78, 97]
Collections.sort(list);
System.out.println(list);//[16, 19, 31, 44, 57, 60, 78, 85, 97, 98]
}
public void testSort2() {
//預設的自然排序:呼叫比較規則compareTo
List<String> names=new ArrayList<String>();
Collections.addAll(names, "Tom","Jerry","Andy","John");
System.out.println(names);//[Tom, Jerry, Andy, John]
Collections.sort(names);
System.out.println(names);//[Andy, Jerry, John, Tom]
}
2、 Comparator:自定義排序
一旦Java類實現了Comparable介面,其比較邏輯就已經確定;如果希望在排序的操作中臨時指定比較規則,可以採用Comparable介面回撥的方式。Comparable介面要求實現類必須重寫其定義的方法:
--int compare(To1,T o2)
該方法的返回值要求:
--若o1>o2,則返回值應>0
--若o1<o2,則返回值應<0
--若o1==o2,則返回值應為0
利用方法:
Collections.sort(list,構造器)
就可以進行任意規則的排序
public void testSort3() {
//自定義的比較器:按照字元長度比較大小
Comparator<String> byLength=new Comparator<String>() {
public int compare(String o1,String o2) {
return o1.length()-o2.length();
}
};//內部類
String s1="abcde";
String s2="好好學習we";
System.out.println(byLength.compare(s1,s2));
List<String> names=new ArrayList<String>();
Collections.addAll(names, "Tom","Jerry","Andy","John");
System.out.println(names);//[Tom, Jerry, Andy, John]
//對names按照字串長度比較大小進行排序,這是Andy和John誰在前面都可以,因為長度一樣
Collections.sort(names, byLength);
System.out.println(names);//[Tom, Andy, John, Jerry]
//sort方法封裝了排序演算法,按照從小到大排序,是依照byLength中的compare()方法的結果比較大小排序
}
public void testSort4() {
//實現按字串倒序排序的演算法
String s1="abc";
String s2="zde";
//s1.compareTo(s2)<0
Comparator<String> byValue=new Comparator<String>() {
public int compare(String o1,String o2) {
return -(o1.compareTo(o2));//按照z到a的順序排序
}
};
System.out.println(s1.compareTo(s2));//-25
System.out.println(byValue.compare(s1, s2));//25
List<String> list=new ArrayList<String>();
Collections.addAll(list, "abc","d","f","z");
System.out.println(list);//[abc, d, f, z]
Collections.sort(list, byValue);
System.out.println(list);//[z, f, d, abc]
}
public void testSort5() {
Comparator<Person> byAgeHeight=new Comparator<Person>() {
public int compare(Person o1, Person o2) {
////先按照年齡比較,年齡如果相同就按照身高比較
if(o1.age==o2.age) {
return o1.height-o2.height;
}
return o1.age-o2.age;
}
};
//先按照年齡比較,年齡如果相同就按照身高比較
List<Person> list=new ArrayList<Person>();
list.add(new Person("Tom",4,35));
list.add(new Person("Jerry",10,22));
list.add(new Person("Andy",20,11));
list.add(new Person("Nemo",2,35));
list.add(new Person("Lee",4,20));
System.out.println(list);//[Tom:4:35, Jerry:10:22, Andy:20:11, Nemo:2:35, Lee:4:20]
Collections.sort(list, byAgeHeight);
System.out.println(list);//[Nemo:2:35, Lee:4:20, Tom:4:35, Jerry:10:22, Andy:20:11]
}
class Person{
String name;
int age;
int height;
public Person(String name,int age,int height) {
this.name=name;
this.age=age;
this.height=height;
}
public String toString() {
return name+":"+age+":"+height;
}
}
關於自定義排序:
1、Comparable可比較的,這個介面不常用,是預設比較規則介面,實現這個介面的類可以進行“自然排序”。Java API中有些型別實現了這個介面:String、包裝類、時間等。實現這個介面必須保證:equals compareTo hashCode的一致性,當兩個物件equals結果為true的時候,compareTo結果為0,同時具有相同的hashCode。
2、Comparator:比較器,用於實現某兩個物件的自定義比較大小,沒有限定,可以按照任何屬性和演算法比較,是常用的比較規律,可以利用這個比較器,進行任意的排序。
3、Java自帶的排序演算法都是升序排序,可以利用比較規則影響排序結果。
Collections:
Collections是集合的工具類,包含大量的集合工具方法(演算法):填充Collections.addAll(),排序Collections.sort()、查詢、二分查詢等。去java2s.com這個網站中檢視具體的。
佇列和棧:
1、Queue
佇列遵循先進先出原則,一端進,一端出。
JDK提供了Queue介面,同時使得LinkedList實現了該介面。選擇LinkedList實現Queue的原因在於Queue經常要進行新增和刪除的操作,而LinkedList在這方面效率高。
Queue介面主要方法如下:
1、boolean offer(E e):將一個物件新增至隊尾,如果新增成功則返回true。
2、E poll():從隊首刪除並返回一個元素。
3、E peek():返回隊首的元素(但不刪除)。
4、queue.isEmpty();
5、queue.size();
public void testQueue() {
Queue<String> queue=new LinkedList<String>();
queue.offer("a");
queue.offer("b");
queue.offer("c");
System.out.println(queue);//[a,b,c]
String str=queue.peek();//返回隊首的元素
System.out.println(str);//a
while(queue.size()>0) {
str=queue.poll();//從隊首刪除並返回一個元素。
System.out.print(str+" ");//a b c
}
}
1、 Deque
Deque是Queue的子介面,定義了所謂的雙端佇列,即從佇列的兩端分別可以入隊(offer)和出隊(poll),LinkedList實現了該介面。
2、 棧
如果將Deque限制為只能從一端入隊和出隊,則可實現棧(Stack)的資料結構,對於棧而言,入棧稱之為push,出棧稱之為pop。棧遵循先進後出的原則。
public void testStack() {
Deque<String> stack=new LinkedList<String>();
stack.push("a");
stack.push("b");
stack.push("c");
System.out.println(stack);//[c,b,a]
String str=stack.peek();//c
System.out.println(str);
while(stack.size()>0) {
str=stack.pop();
System.out.print(str+" ");//c b a
}
}
棧的方法:
1、stack.push();
2、stack.pop();
3、stack.peek();
4、stack.isEmpty();
5、stack.empty();
6、stack.size();