前言
最近在在看《Java資料結構和演算法》這本書,這本書很不錯,值得細看。看完了第二章-數組篇。所以寫這一篇章節小結,正好附上自己寫的編程作業源碼,供大家參考。 書裡小結 Java中的數組是對象,由new運算子操作。 無序數組可以提供快速的插入,但尋找和刪除很慢。 將數組封裝到類中可以保護數組不被隨意的更改。 類中的介面由類使用者可訪問的方法(有時還有欄位)組成。 有序數組可以使用二分尋找。 線性尋找需要的時間和數組中的資料項目的個數成正比。 二分尋找需要的時間與數組中資料項目的個數的對數成正比。 大O標記法為比較演算法的速度提供一個方便的方法。大O表示是一個可以描述演算法的速度是如何與資料項目的個數相聯絡的比較。 梳理知識點 在有序數組中,如果用二分法插入的話,插入20W條資料,自己測試的時間是43毫秒。如果用線性插入的話,所需的時間是很大的。線性插入的時間複雜度是O(n),二分法插入的時間複雜度是O(logN)。 在有序數組中,用線性尋找和二分法尋找,二分法尋找效率要比線性尋找效率高。線性尋找的時間複雜度是O(n),二分法尋找的時間複雜度是O(logN)。 O(1)意味著一個操作執行了常數的時間 簡單類型變數和對象都可以存入數組。 課後編碼作業
課後編碼作業還是有一點難的,也花了很長時間去寫,在此附上源碼。
2.1 向highArray.java程式(清單2.3)的HighArray類添加一個名為getMax()的方法,它返回 數組中最大關鍵字的值,當數組為空白時返回-1。向main()中添加一些代碼來使用這個方法。 可以假設所有關鍵字都是正數。
2.2 修改編程作業2.1中的方法,使之不僅返回最大的關鍵字,而且還將該關鍵字從數組中刪除。 將這個方法命名為removeMax()。
2.3 編程作業2.2中的removeMax()方法提供了一種通過關鍵字值進行數組排序的方法。實現一個 排序方案,要求不修改HighArray類,只需對main()中的代碼進行修改。這個方法需要第二個 數組,在排序結束時數組資料項目是逆序排列的。(這個方法是第3章“簡單排序”中選擇排序的 一個變體。)
public class HighArray { private long[] a; public int size; private HighArrayReverseSort highArrayReverseSort; public HighArray(HighArrayReverseSort highArrayReverseSort,int initialCapacity){ this.highArrayReverseSort=highArrayReverseSort; a=new long[initialCapacity]; size=0; } public boolean find(long findValue){ int j; for(j=0;j<size;j++){ if(a[j]==findValue){ break; } } if(j==size){ return false; }else{ return true; } } public void insert(long value){ a[size]=value; size++; } public boolean delete(long value){ int j; for(j=0;j<size;j++){ if(a[j]==value){ break; } } if(j==size){ return false; }else{ for(int k=j;k<size-1;k++){ a[k]=a[k+1]; } size--; return true; } } public void display(){ for(int j=0;j<size;j++){ System.out.print(" "+a[j]); } System.out.print("\n"); } public long getMax(){ if(size==0){ return -1; }else{ long max=a[0]; for(int j=0;j<size;j++){ if(a[j]>max){ max=a[j]; } } return max; } } public boolean removeMax(){ highArrayReverseSort.reverseSort(this); return delete(getMax()); } public int size(){ return size; } public long get(int index){ return a[index]; } public long set(int index,long value){ long oldValue=this.get(index); a[index]=value; return oldValue; }}
public interface HighArrayReverseSort { public void reverseSort(HighArray array);}
public class HighArrayTest{ public static void main(String[] args){ HighArray array=new HighArray(new HighArrayReverseSort() { @Override public void reverseSort(HighArray a) { class Inner{ public void swap(int m,int i){ long temp=a.get(m); a.set(m, a.get(i)); a.set(i, temp); } } // TODO Auto-generated method stub for(int i=0;i<a.size();i++){ //最大值的小標 int m=i; for(int k=i+1;k<a.size();k++){ if(a.get(k)>a.get(m)){ m=k; } } //如果待排序中的最大元素的下標等於i的話,那麼就不用排序 //i是每次迴圈預設的最大元素的下標 if(m!=i){ new Inner().swap(m,i); } } a.display(); } },100); array.insert(23); array.insert(343); array.insert(2543); array.insert(234); array.insert(23); array.insert(233); array.insert(230); array.insert(253); array.insert(223); array.insert(2); array.display(); System.out.println("最大數="+array.getMax()); array.removeMax(); array.display(); }}
2.4 修改orderedArray.java程式(清單2.4)使insert()、delete()與find()方法一樣都使用 二分尋找,正如書中所建議的那樣。
public class OrderedArray { private long[] a; private int size; public OrderedArray(int inititalCapacity){ a=new long[inititalCapacity]; size=0; } public int linearFind(long searchValue){ long startTime=System.currentTimeMillis(); int j; for(j=0;j<size;j++){ if(searchValue==a[j]){ break; } } if(j==size){ long noFoundTime=System.currentTimeMillis(); System.out.println("本次是線性查詢,查詢的數字="+searchValue+",耗時="+(noFoundTime-startTime)); return size; }else{ long endTime=System.currentTimeMillis(); System.out.println("本次是線性查詢,查詢的數字="+searchValue+",返回索引="+j+",查詢時間="+(endTime-startTime)); return j; } } public int fastFind(long searchValue){ System.out.println("進行了二分法查詢"); long startTime=System.currentTimeMillis(); int start=0; int end=size-1; int mid; while(start<=end){ mid=(start+end)>>1; System.out.println("start="+start+",end="+end+",mid="+mid); long value=a[mid]; if(searchValue>value){ start=mid+1; }else if(searchValue<value){ end=mid-1; }else{ long endTime=System.currentTimeMillis(); System.out.println("本次是二分法查詢,查詢的數字="+searchValue+",返回索引="+mid+",查詢時間="+(endTime-startTime)); return mid; } } long noFoundTime=System.currentTimeMillis(); System.out.println("本次是二分法查詢,沒找到該數字="+searchValue+",耗時="+(noFoundTime-startTime)); return -1; } public void fastInsert(long insertValue){ int start=0; int end=size-1; int mid; while(start<=end){ mid=(start+end)/2; long value=a[mid]; if(insertValue>value){ start=mid+1; }else{ end=mid-1; } } for(int k=size;k>start;k--){ a[k]=a[k-1]; } a[start]=insertValue; size++; } /** * 線性插入 * @param value */ public void linearInsert(long value){ int j; for(j=0;j<size;j++){ if(a[j]>value){ break; } } for(int k=size;k>j;k--){ a[k]=a[k-1]; } a[j]=value; System.out.println("線性插入,此時數組size="+size); size++; } public boolean delete(long value){ int i=fastFind(value); if(i==size){ return false; }else{ for(int k=i;k<size-1;k++){ a[k]=a[k+1]; } size--; return true; } } public void display(){ for(int j=0;j<size;j++){ System.out.println(""+a[j]); } } public int size(){ return size; } public void removeAll(){ size=0; } public long get(int index){ return a[index]; }}
public class OrderedArrayTest { public static void main(String[] args){ long t1,t2,t3,t4,t5,t6; int initialCapacity=400000; OrderedArray array=new OrderedArray(initialCapacity); //二分法插入 t1=System.currentTimeMillis(); for(int i=0;i<200000;i++){ array.fastInsert(i); } t2=System.currentTimeMillis(); t3=t2-t1; System.out.println("二分法插入"+array.size()+"條資料,耗時="+t3+"毫秒"); /**刪除123456** * */ boolean flag=array.delete(123456); String msg=flag?"刪除成功":"刪除失敗"; System.out.println("msg="+msg); /***************線性插入******************/ t4=System.currentTimeMillis(); for(int i=200000;i<400000;i++){ array.linearInsert(i); } t5=System.currentTimeMillis(); t6=t5-t4; System.out.println("線性插入"+200000+"條資料,耗時="+t6+"毫秒"); long searchValue=321234; /**二分法查詢**/ int index=array.fastFind(searchValue); /**線性查詢**/ array.linearFind(searchValue); }}
【2.5】 向orderedArray.java程式(清單2.4)的OrdArray類加入一個merge()方法,使之可以將兩個有序的源數組合并成一個有序的目的數組。在main()中添加代碼,向兩個源數組中插入隨機數,調用merge()方法,並將結果目的數組顯示出來。兩個源數組的資料項目個數可能不同。在演算法中需要先比較源數組中的關鍵字,從中選出最小的一個資料項目複製到目的數組。同時還要考慮如何解決當一個源數組的資料項目已經取完而另一個還剩一些資料項目情況。
public class NewOrderedArray extends OrderedArray{ public NewOrderedArray(int inititalCapacity) { super(inititalCapacity); // TODO Auto-generated constructor stub } public void merge(NewOrderedArray oldArray1){ NewOrderedArray oldArray2=this; NewOrderedArray newArray=new NewOrderedArray(oldArray1.size()+oldArray2.size()); for(int i=0;i<oldArray1.size();i++){ newArray.fastInsert(oldArray1.get(i)); } for(int j=0;j<oldArray2.size();j++){ newArray.fastInsert(oldArray2.get(j)); } newArray.display(); } @Override public void display() { // TODO Auto-generated method stub for(int j=0;j<this.size();j++){ System.out.print(" "+this.get(j)); } System.out.print("\n"); }}
public class NewOrderedArrayTest { public static void main(String[] args){ NewOrderedArray oldArray1=new NewOrderedArray(10); NewOrderedArray oldArray2=new NewOrderedArray(10); for(int i=0;i<10;i++){ oldArray1.fastInsert(new Random().nextInt(9999)); oldArray2.fastInsert(new Random().nextInt(666)); } oldArray1.display(); oldArray2.display(); oldArray1.merge(oldArray2); }}
【2.6】向highArray.java程式(清單2.3)的HighArray類中加入一個noDup()方法,使之可以將數組中的所有重複資料項目刪除。即如果數組中有三個資料項目的關鍵字為17,noDup()方法會刪除其中的兩個。不必考慮保持資料項目的順序。一種方法是先用每一個資料項目同其他資料項目比較,並用null (或是一個不會用在真正的關鍵字中的特殊值)將重複的資料項目覆蓋掉。然後將所有的null刪除,當然還要縮小數組的大小。
public class NewHighArray extends HighArray{ public NewHighArray(HighArrayReverseSort highArrayReverseSort, int initialCapacity) { super(highArrayReverseSort, initialCapacity); // TODO Auto-generated constructor stub } public void noDup(long value){ //第一種方法 int NULL=-1; for(int i=0;i<size;i++){ if(this.get(i)==value){ this.set(i,NULL); } } for(int j=0;j<this.size();j++){ if(this.get(j)==NULL){ System.out.println("j="+j); for(int k=j;k<size-1;k++){ this.set(k, get(k+1)); } size--; j--; //因為刪除了一個元素,j下標對應的元素會發生改變,所以j-1後才能正確訪問填充j下標的元素 System.out.println("size="+size); } } this.insert(value); }}
public class NewHighArrayTest { public static void main(String[] args){ int initialCapacity=10; NewHighArray array=new NewHighArray(new HighArrayReverseSort() { @Override public void reverseSort(HighArray array) { // TODO Auto-generated method stub } },initialCapacity); array.insert(56); array.insert(23); array.insert(15); array.insert(66); array.insert(67); array.insert(15); array.insert(100); array.insert(90); array.insert(15); array.insert(15); array.display(); long dupValue=15; array.noDup(dupValue); array.display(); }}
尾言
@豆豆,你也要加油。如果有夢,夢要夠瘋,夠瘋才能變成英雄,總會有一篇我們的傳說。五月天陪我們到出頭天。