//插入排序 void InsertSort(int array[], int size) { for (int i=1;i<size;i++) { int end = i - 1; int key = array[i]; //尋找插入位置 while (end>=0&&array[end]>key) { array[end+1] = array[end]; end--; } //插入元素 array[end + 1] = key; } }
a. 元素集合越接近有序,直接插入排序算法的時間效率越高 算法
b. 時間複雜度:O(N^2) 數組
c.空間複雜度:O(1),它是一種穩定的排序算法 markdown
d. 穩定性:穩定 ide
//希爾排序 void ShellSort(int array[], int size) { int gap = size; while (gap > 1) { gap = gap / 3 + 1; for (int i = gap; i < size; i++) { int end = i - gap; int key = array[i]; while (end>=0&&array[end]>key) { array[end+gap] = array[end]; end=end-gap; } array[end + gap] = key; } } }
a. 希爾排序是對直接插入排序的優化 性能
b. 希爾排序的時間複雜度很差計算,須要進行推導,推導出來平均時間複雜度: O(N^1.3—N^2) 優化
c.穩定性:不穩定ui
void swap(int arr1[], int arr2[]) { int temp = 0; temp = *arr1; *arr1 = *arr2; *arr2 = temp; } //選擇排序 void SelectSort(int array[], int size) { for(int i=0;i<size-1;i++)//最後剩一個數就不用排了,所以是size-1 { int maxPos = 0; //尋找最大值的位置 for (int j = 1; j < size - i; j++) { if (array[j] > array[maxPos]) { maxPos = j; } } //將最大值放在數組最後 if (maxPos != size - 1 - i) { swap(&array[maxPos], &array[size - 1 - i]); } } }
//選擇排序另外一種方法 void SelectSortOP(int array[], int size) { int begin = 0,end = size - 1; while (begin < end) { //找最大最小元素位置 int maxPos = begin; int minPos = begin; int index = begin + 1; while (index <= end) { if (array[index] > array[maxPos]) { maxPos = index; } if (array[index] < array[minPos]) { minPos = index; } index++; } if (maxPos != end) { swap(&array[maxPos], &array[end]); } //若是最小的元素恰巧在end處,則上面操做會改變最小元素的位置 if (minPos == end) { minPos = maxPos; } if (minPos != begin) { swap(&array[minPos], &array[begin]); } begin++; end--; } }
a.直接選擇排序思考很是好理解,可是效率不是很好。實際中不多使用 code
b.時間複雜度:O(N^2)排序
c.空間複雜度:O(1) 遞歸
d.穩定性:不穩定
void swap(int arr1[], int arr2[]) { int temp = 0; temp = *arr1; *arr1 = *arr2; *arr2 = temp; } //向下調整算法 void HeapAdjust(int array[], int size, int parent) { //先標記左孩子,parent可能有左沒有右 int child = parent * 2 + 1; while (child<size) { //找到左右孩子中較大的,用child標記 if (child+1 < size && array[child] < array[child + 1]) { child += 1; } //若是雙親結點小於較大的子結點,則交換 if (array[parent] < array[child]) { swap(&array[parent], &array[child]); parent = child; child = parent * 2 + 1; } else { return; } } } //堆排序 void HeapSort(int array[], int size) { int end = size - 1; //建堆, 升序-->大堆 降序-->小堆 //從倒數第一個非葉子結點到根結點一直向下調整 for (int root = (end - 1) / 2; root >= 0; root--) { HeapAdjust(array, size, root); } //排序 while(end) { swap(&array[0], &array[end]); HeapAdjust(array, end , 0); end--; } }
a.堆排序使用堆來選數,效率就高了不少
b.時間複雜度:O(N*logN)
c.空間複雜度:O(1)
d.穩定性:不穩定
//冒泡排序 void BubbleSort(int array[], int size) { for (int i = 0; i < size - 1; i++) { int flag=0; //相鄰兩個元素比較,不知足就交換 for (int j = 0; j < size - i-1; j++) { if (array[j]>array[j+1]) { flag=1; swap(&array[j] ,&array[j+1]); } } if(!flag)//若是flag爲0,則沒有發生交換,則數組已經有序,就不用再比較了 { return; } } }
a.時間複雜度:O(N^2)
b.空間複雜度:O(1)
c.穩定性:穩定
//計數排序 void CountSort(int array[], int size) { //1.找數據範圍 int max = array[0]; int min = array[0]; int index = 0; for (int i = 0; i < size; i++) { if (array[i] > max) { max = array[i]; } if (array[i] < min) { min = array[i]; } } //2.申請空間 int* count = (int*)calloc(max - min + 1, sizeof(int)); if (NULL == count) { return NULL; } //3.統計每一個元素出現次數 for (int i = 0; i < size; i++) { count[array[i] - min]++; } //4.array數組排序 for (int i=0;i<max-min+1;i++) { while (count[i]--) { array[index++] = i + min; } } free(count); }
a. 計數排序在數據範圍集中時,效率很高,可是適用範圍及場景有限
b. 時間複雜度:O(MAX(N,範圍))
c. 空間複雜度:O(範圍)
d. 穩定性:穩定
//第一種:hoare法 int Partion1(int array[], int left, int right) { int begin = left; int end = right - 1; int key = array[end];//基準值是最後一個元素 while (begin < end) { while (begin<end&&array[begin] <= key) //保證有效區間 { begin++; } while (begin < end&&array[end] >= key) { end--; } if (begin < end) { swap(&array[begin], &array[end]); } } if (begin!=right-1) { swap(&array[begin], &array[right - 1]);//將基準值放在數組中間 } return begin;//返回基準值位置 } //第二種:挖坑法 int Partion2(int array[], int left, int right) { int begin = left; int end = right - 1; int key = array[end]; while (begin < end) { //begin從前日後找,找比基準值大的元素 while (begin < end&&array[begin] <= key) { begin++; } if (begin < end) { array[end] = array[begin]; end--; } while (begin < end&&array[end] >= key) { end--; } if (begin < end) { array[begin] = array[end]; begin++; } } array[begin] = key; return begin; } //第三種 int Partion3(int array[], int left, int right) { int cur = left; int prev = cur-1; int key = array[right - 1]; while (cur < right) { if (array[cur] < key&&++prev != cur) { swap(&array[cur], &array[prev]); } cur++; } if (++prev != right - 1)//將基準值放在正確的位置 { swap(&array[prev], &array[right-1]); } return prev; } void QuickSort(int array[], int left, int right) { int div = 0; if (right - left <= 1) { return; } //找基準值對區間中的數據進行劃分,div表述劃分好等候基準值位置 div = Partion3(array, left, right); //遞歸 QuickSort(array, left, div); QuickSort(array, div+1, right); }
a. 快速排序總體的綜合性能和使用場景都是比較好的,因此纔敢叫快速排序
b. 時間複雜度:O(N*logN)
c. 空間複雜度:O(logN)
d. 穩定性:不穩定
//合併兩個有序數組 void MergeData(int array[], int left, int mid, int right, int temp[]) { int begin1 = left, end1 = mid; int begin2 = mid , end2 = right; int index = left; while (begin1 < end1 && begin2 < end2) { if (array[begin1] <= array[begin2]) { temp[index++] = array[begin1++]; } else { temp[index++] = array[begin2++]; } } while (begin1<end1) { temp[index++] = array[begin1++]; } while (begin2 < end2) { temp[index++] = array[begin2++]; } } //歸併排序 void MergeSort(int array[], int left, int right, int temp[]) { if (right - left <= 1) { return; } int mid = left + ((right - left) / 2); MergeSort(array, left, mid, temp); MergeSort(array,mid , right, temp); MergeData(array, left, mid, right, temp); memcpy(array + left, temp+left, sizeof(array[0])*(right - left)); }
a. 歸併的缺點在於須要O(N)的空間複雜度,歸併排序的思考更多的是解決在磁盤中的外排序問題。
b. 時間複雜度:O(N*logN)
c. 空間複雜度:O(N)
d. 穩定性:穩定