數據結構與算法(一)
數據結構
數據結構是計算機存儲、組織數據的方式,指相互之間存在一種或多種特定關系的數據元素的集合。
常見數據結構有:
1、數組 插入快 查找刪除慢 大小固定 元素單一
2、有序數組 查找快 插入刪除慢 大小固定 元素單一
3、棧 先進後出
4、隊列 先進先出
5、鏈表 插入刪除快 查找慢
6、二叉樹 樹是平衡的則增刪改都快,刪除算法復雜
7、紅黑樹 增刪改都快,樹總是平衡的,算法復雜
8、2-3-4樹 增刪改都快,樹總是平衡的, 算法復雜
9、哈希表 知道關鍵字則查詢插入都快,刪除慢,不知道關鍵字存取慢,對存儲空間使用不充分
10、堆 插入刪除快,對最大數據項存取快,對其它數據項慢‘
11、圖 對現實世界建模 有些算法慢且復雜
算法
算法簡單來說就是解決問題的步驟
在Java中,算法通常都是由類的方法來實現的。前面的數據結構,比如鏈表為啥插入、刪除快,而查找慢,平衡的二叉樹插入、刪除、查找都快,這都是實現這些數據結構的算法所造成的。
算法的特征:
1、有窮性:對於任意一組合法輸入值,在執行又窮步驟之後一定能結束,即:算法中的每個步驟都能在有限時間內完成。
2、確定性:在每種情況下所應執行的操作,在算法中都有確切的規定,使算法的執行者或閱讀者都能明確其含義及如何執行。並且在任何條件下,算法都只有一條執行路徑。
3、可行性:算法中的所有操作都必須足夠基本,都可以通過已經實現的基本操作運算有限次實現之。
4、有輸入:作為算法加工對象的量值,通常體現在算法當中的一組變量。有些輸入量需要在算法執行的過程中輸入,而有的算法表面上可以沒有輸入,實際上已被嵌入算法之中。
5、有輸出:它是一組與“輸入”有確定關系的量值,是算法進行信息加工後得到的結果,這種確定關系即為算法功能。
算法設計原則:
1、正確性
2、可讀性
3、健壯性
4、高效率與低存儲量需求:通常算法效率值得是算法執行時間;存儲量是指算法執行過程中所需要的最大存儲空間,兩者都與問題的規模有關。
數組
數組的局限性分析:
1、插入快,對於無序數組,上面我們實現的數組就是無序的,即元素沒有按照從大到小或者某個特定的順序排列,只是按照插入的順序排列。無序數組增加一個元素很簡單,只需要在數組末尾添加元素即可,但是有序數組卻不一定了,它需要在指定的位置插入。
2、查找慢,當然如果根據下標來查找是很快的。但是通常我們都是根據元素值來查找,給定一個元素值,對於無序數組,我們需要從數組第一個元素開始遍歷,直到找到那個元素。有序數組通過特定的算法查找的速度會比無需數組快,後面我們會講各種排序算法。
3、刪除慢,根據元素值刪除,我們要先找到該元素所處的位置,然後將元素後面的值整體向前面移動一個位置。也需要比較多的時間。
4、數組一旦創建後,大小就固定了,不能動態擴展數組的元素個數。如果初始化你給一個很大的數組大小,那會白白浪費內存空間,如果給小了,後面數據個數增加了又添加不進去了。
簡單排序算法
冒泡算法的運作規律如下:
1、比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
2、對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步做完後,最後的元素會是最大的數(也就是第一波冒泡完成)。
3、針對所有的元素重復以上的步驟,除了最後一個。
4、持續每次對越來越少的元素重復上面的步驟,直到沒有任何一對數字需要比較。
public class BubbleSort { public static int[] sort(int[] array){ for(int i=1;i<array.length;i++){ boolean flag = true; for(int j =0;j<array.length-i;j++){ if(array[j]>array[j+1]){ int temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; flag = false; } } if(flag){ break; } } return array; } public static void main(String[] args) { int[] array ={3,2,5,6,8,7,9,1,4}; Arrays.stream(array).forEach(System.out::println); array = sort(array); Arrays.stream(array).forEach(System.out::println); } }
選擇排序運作規律:
1、從待排序序列中,找到關鍵字最小的元素
2、如果最小元素不是待排序序列的第一個元素,將其和第一個元素互換
3、從余下的 N - 1 個元素中,找出關鍵字最小的元素,重復(1)、(2)步,直到排序結束
public class ChoiceSort { public static int[] sort(int[] array){ for(int i=0;i<array.length;i++){ for(int j =i+1;j<array.length;j++){ if(array[i]>array[j]){ int temp = array[i]; array[i] = array[j]; array[j] =temp; } } } return array; } public static void main(String[] args) { int[] array ={3,2,5,6,8,7,9,1,4}; Arrays.stream(array).forEach(System.out::println); array = sort(array); Arrays.stream(array).forEach(System.out::println); } }
直接插入排序:
基本思想是每一步將一個待排序的記錄,插入到前面已經排好序的有序序列中去,直到插完所有元素為止。
public class InsertSort { public static int[] sort(int[] array){ for(int i =1;i<array.length;i++){ int temp =array[i]; int j =i; while(j>0 && temp <array[j-1]){ array[j] =array[j-1]; j--; } array[j] = temp; } return array; } public static void main(String[] args) { int[] array ={3,2,5,6,8,7,9,1,4}; Arrays.stream(array).forEach(System.out::println); array = sort(array); Arrays.stream(array).forEach(System.out::println); } }
冒泡、選擇、插入用大 O 表示法都需要 O(N2) 時間級別。一般不會選擇冒泡排序,雖然冒泡排序書寫是最簡單的,但是平均性能是沒有選擇排序和插入排序好的。
選擇排序把交換次數降低到最低,但是比較次數還是挺大的。當數據量小,並且交換數據相對於比較數據更加耗時的情況下,可以應用選擇排序。
在大多數情況下,假設數據量比較小或基本有序時,插入排序是三種算法中最好的選擇。
基於數組實現棧
這裏順帶做個小測試,證明java中泛型是一個語法糖,僅在編譯時起作用,當我們使用反射時,就可以越過泛型檢查
public class ArrayStock<E>{ private Object[] elements; private int top; private int size; public ArrayStock(){ this.elements = new Object[10]; this.top = -1; this.size = 10; } public ArrayStock(int size) { if(size<=0){ throw new IllegalArgumentException("size不能小於0"); } this.elements = new Object[size]; this.top = -1; this.size = size; } public E push(E e){ if(size<= top+1){ grow(); } elements[++top] = e; return e; } // public E poll() { // if(top==-1){ // throw new EmptyStackException(); // } // E e =(E) elements[top]; // elements[top--] = null; // // return e; // } public Object poll() { if(top==-1){ throw new EmptyStackException(); } Object e = elements[top]; elements[top--] = null; return e; } private void grow(){ System.out.println("kuorong "); int oldCapacity = size; int newCapacity = oldCapacity<<1; Object[] newArray = new Object[newCapacity]; System.arraycopy(elements,0,newArray,0,size); this.elements = newArray; this.size = newCapacity; } public static void main(String[] args) throws Exception{ ArrayStock<String> arrayStock = new ArrayStock(3); arrayStock.push("asd"); Method method =ArrayStock.class.getDeclaredMethod("push",Object.class); method.invoke(arrayStock,13); arrayStock.push("sdf"); arrayStock.push("qwe"); arrayStock.push("sdfsdfsf"); System.out.println(arrayStock.poll()); System.out.println(arrayStock.poll()); System.out.println(arrayStock.poll()); System.out.println(arrayStock.poll()); System.out.println(arrayStock.poll()); } }
基於數組實現循環隊列和優先級隊列
public class ArrayQueue { private Object[] queueArray; private int maxSize; private int front; private int rear; private int items; public ArrayQueue(){ this.queueArray = new Object[3]; maxSize =3; front =0; rear = -1; items = 0; } public void push(Object o){ if(isFull()){ System.out.println("已滿"); }else{ if(rear ==maxSize-1){ rear =-1; } queueArray[++rear] = o; items++; } } public Object poll(){ Object returnValue = null; if(!isEmpty()){ returnValue = queueArray[front]; queueArray[front] =null; front++; if(front==maxSize){ front = 0; } items--; } return returnValue; } private boolean isFull(){ return items ==maxSize; } public boolean isEmpty(){ return (items ==0); } public static void main(String[] args) { ArrayQueue arrayQueue = new ArrayQueue(); arrayQueue.push(12); arrayQueue.push(13); arrayQueue.push(14); System.out.println(arrayQueue.poll()); System.out.println(arrayQueue.poll()); arrayQueue.push(34); arrayQueue.push(56); arrayQueue.push(6756); arrayQueue.push(2342); System.out.println(arrayQueue.poll()); System.out.println(arrayQueue.poll()); System.out.println(arrayQueue.poll()); System.out.println(arrayQueue.poll()); } }
public class PriorityQueue { private int maxSize; private int[] priQueArray; private int nItems; public PriorityQueue(int s){ maxSize = s; priQueArray = new int[maxSize]; nItems = 0; } public void push(int value){ if(nItems==0){ priQueArray[0] =value; }else{ int j ; j = nItems-1; while(j>=0&& value>priQueArray[j]){ priQueArray[j+1] = priQueArray[j]; j--; } priQueArray[j+1] = value; } nItems++; } public int poll(){ int returnValue =priQueArray[nItems-1]; priQueArray[nItems-1] = -1; nItems--; return returnValue; } public static void main(String[] args) { PriorityQueue arrayQueue = new PriorityQueue(10); arrayQueue.push(12); arrayQueue.push(13); arrayQueue.push(14); System.out.println(arrayQueue.poll()); System.out.println(arrayQueue.poll()); arrayQueue.push(34); arrayQueue.push(56); arrayQueue.push(6756); arrayQueue.push(2342); System.out.println(arrayQueue.poll()); System.out.println(arrayQueue.poll()); System.out.println(arrayQueue.poll()); System.out.println(arrayQueue.poll()); System.out.println(arrayQueue.poll()); } }
數據結構與算法(一)