//插入排序 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. 稳定性:稳定