查找算法着重掌握:順序查找、二分查找、哈希表查找、二叉排序樹查找。算法
排序算法着重掌握:冒泡排序、插入排序、歸併排序、快速排序。數組
順序查找適合於存儲結構爲順序存儲或連接存儲的線性表。數據結構
順序查找也稱爲線形查找,屬於無序查找算法。從數據結構線形表的一端開始,順序掃描,依次將掃描到的結點關鍵字與給定值k相比較,若相等則表示查找成功;若掃描結束仍沒有找到關鍵字等於k的結點,表示查找失敗。函數
int sequenceSearch(int a[], int value, int len) { int i; for(i=0; i<len; i++) if(a[i]==value) return i; return -1; }
查找成功時的平均查找長度爲:(假設每一個數據元素的機率相等) ASL = 1/n(1+2+3+…+n) = (n+1)/2 ;查找不成功時,須要n+1次比較,時間複雜度爲O(n);因此,順序查找的時間複雜度爲O(n)。ui
元素必須是有序的,若是是無序的則要先進行排序操做。spa
也稱爲是折半查找,屬於有序查找算法。用給定值k先與中間結點的關鍵字比較,中間結點把線形表分紅兩個子表,若相等則查找成功;若不相等,再根據k與該中間結點關鍵字的比較結果肯定下一步查找哪一個子表,這樣遞歸進行,直到查找到或查找結束髮現表中沒有這樣的結點。注:折半查找的前提條件是須要有序表順序存儲,對於靜態查找表,一次排序後再也不變化,折半查找能獲得不錯的效率。但對於須要頻繁執行插入或刪除操做的數據集來講,維護有序的排序會帶來不小的工做量,那就不建議使用。code
//二分查找,常規版 int binarySearch1(int a[], int value, int len) { int low, high, mid; low = 0; high = len-1; while(low<=high) { mid = low+(high-low)/2; //防止溢出 if(a[mid]==value) return mid; if(a[mid]>value) high = mid-1; if(a[mid]<value) low = mid+1; } return -1; } //二分查找,遞歸版 int binarySearch2(int a[], int value, int low, int high) { int mid = low+(high-low)/2; if(a[mid]==value) return mid; if(a[mid]>value) return BinarySearch2(a, value, low, mid-1); if(a[mid]<value) return BinarySearch2(a, value, mid+1, high); }
最壞狀況下,關鍵詞比較次數爲log2(n+1),故時間複雜度爲O(log2n);blog
屬於交換類排序,穩定排序排序
比較相鄰的兩個數的大小,將最大的數放在右邊,計數器i++;遞歸
繼續重複操做1,直到a[n-2]和a[n-1]比較結束,數組a中最大的值已在a[n-1];
將進行排序的數組長度n減1,重複操做1和操做2,直到n爲1,排序完畢。
void bubbleSort(int* array, int length) { for (int i = 0; i < length - 1; ++i) { //bool is_Swap=false; for (int j = 0; j < length - 1 - i; ++j) { if (array[j] > array[j + 1]) { //is_Swap=true; int temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp; /* 交換還可以使用以下方式 a = a + b; b = a - b; a = a - b; 交換還可以使用以下方式 a=a^b; b=b^a; a=a^b; */ } } //if(is_Swap==false) //return; } }
平均時間複雜度:O(n^2)。最好的狀況:若是待排序數據序列爲正序,則一趟冒泡就可完成排序,排序的比較次數爲n-1次,且沒有移動,時間複雜度爲O(n)。要實現O(n)的複雜度,代碼裏須要加一個標誌位(Bool變量)。最壞的狀況:若是待排序數據序列爲逆序,則冒泡排序須要n-1次趟,每趟進行n-i次排序的比較和移動,即比較和移動次數均達到最大值:比較次數=n(n−1)/2=O(n^2),移動次數等於比較次數,所以最壞時間複雜度爲O(n^2)。
屬於插入類排序,穩定排序。
從待排序的數組的第二個元素開始,將其與前面的數進行大小比較,尋找合適的位置並插入,直到所有元素都已插入。
void insertSort(int* array,int length) { int i = 0, j = 0, temp = 0; for (i = 1; i < length; ++i) { //若是該元素小於前面的元素,大於該元素的元素所有後移一位, //直到找到該元素要插入的位置並插入之。 if (array[i] < array[i-1]) { temp = array[i]; for (j = i-1; temp < array[j] && j >= 0 ; --j) { array[j+1] = array[j]; } array[j + 1] = temp; } } }
平均時間複雜度:O(n^2)。最好的狀況:當待排序記錄已經有序,這時須要比較的次數爲n-1=O(n)。最壞的狀況:若是待排序記錄爲逆序,則最多的比較次數爲n*(n-1)/2=O(n^2)
應用較廣,穩定排序。
歸併排序是分治法的一個典型的應用,先使每一個子序列有序,再使每一個子序列間有序。將兩個有序子序列合併成一個有序表,稱爲二路歸併。 步驟:首先將有序數列一分二,二分四……直到每一個區都只有一個數據,此時每一個子序列均可看作有序序列。而後進行合併,每次合併都是有序序列在合併,
void MergeArray(int* array, int first, int mid, int last, int* temp) { //將a[first...mid]和a[mid+1...last]合併 int i = first, j = mid + 1, k = 0; int lengthA = mid+1, lengthB = last+1; while (i < lengthA&&j < lengthB) { if (array[i] < array[j]) temp[k++] = array[i++]; else temp[k++] = array[j++]; } while (i < lengthA) { temp[k++] = array[i++]; } while (j < lengthB) { temp[k++] = array[j++]; } for (i = 0; i < k; ++i) { array[first + i] = temp[i]; } } void MergeSort(int* array, int first, int last, int* temp) { if (first >= last) return; int mid = (first + last) / 2; MergeSort(array, first, mid, temp);//左邊有序 MergeSort(array, mid + 1, last, temp);//右邊有序 MergeArray(array, first, mid, last, temp);//合併兩個有序的子序列 }
平均、最好、最壞的時間複雜度都爲:O(n*log n)
能夠這樣理解:合併須要O(log n)步操做,每步將排好序的子序列合併須要O(n)的操做。那時間複雜度確定是O(n*log n)。
在交換類排序算法中,快排是速度最快的。採用分治的思想,不穩定排序。
從n個元素中選擇一個元素做爲分區的標準,通常選第一個元素;
把小於該元素的放在左邊,把大於等於該元素的放在右邊,中間就放該元素;
再分別對左右子序列重複操做1和2,直到每一個子序列裏只有一個元素,排序完畢。
//版本1 void QuickSort(int* array,int low,int high) { if (low >= high) return; int left = low; int right = high; int key = array[left];//選擇第一個元素做爲區分元素,固然也能夠選最後一個元素。 while (left != right) { while (left != right&&array[right] >= key)//從右往左,把小於key的元素放到key的左邊 --right; array[left] = array[right]; while (left != right&&array[left] <= key)//從左往右,把大於key的元素放到key的右邊 ++left; array[right] = array[left]; } array[left] = key;//此時left等於right //一分爲二,分治思想,遞歸調用。 QuickSort(array, low, left - 1); QuickSort(array, left + 1, high); }
衆所周知,Partition函數無論是在快速排序中,仍是在找第K大這類問題中,都有很重要的地位,故而分開寫,就有了版本2。
int Partition(int* array,int left,int right) { int key = array[left]; while (left != right) { while (left != right&&array[right] >= key)//從右往左,把小於key的元素放到key的左邊 --right; array[left] = array[right]; while (left != right&&array[left] <= key)//從左往右,把大於key的元素放到key的右邊 ++left; array[right] = array[left]; } array[left] = key; return left;//返回區分函數 } //快排主函數 void quicksort(int* arr, int left, int right) { if(left< right) { int middle = mypartition(arr, left, right); quicksort(arr, left, middle-1); quicksort(arr, middle+1, right); } }
平均時間複雜度:O(n*log n)。緣由:快排是將數組一分爲二到底,因此須要O(log n)次此操做,每次操做須要排序n次,因此,大多數狀況下,時間複雜度都是O(n*log n)。最好的狀況:是每趟排序結束後,每次劃分使兩個子文件的長度大體相等,時間複雜度爲O(n*log n)。最壞的狀況:是待排序元素已經排好序。第一趟通過n-1次比較後第一個元素保持位置不變,並獲得一個n-1個元素的子序列;第二趟通過n-2次比較,將第二個元素定位在原來的位置上,並獲得一個包括n-2個元素的子序列,依次類推,這樣總的比較次數是:n(n-1)/2=O(n^2)。