目录
快速排序(双指针法)
原理
代码
快速排序(非递归)
原理
代码
归并排序
介绍
优点
缺点
图片
原理
代码
归并排序(非递归)
代码
快速排序(双指针法)
快速排序的精髓在于将数组根据关键值分成左右两块,由此衍生出霍尔快排,挖坑法等一系列方法,在这里我们要介绍一下双指针法
原理
第一个指针pre指向开头,第二个指针cur指向第二个元素
cur持续向前查找,找到某个位置小于关键值时,将cur指向的值与pre的下一个值进行交换(没错,是下一个,这样就可以将第一个位置的关键值保存下来)
交换还有个限制条件就是pre的下一个位置不能是cur
交换完成后cur与pre指向下一个位置
循环退出条件为cur超出数组范围
退出循环后,将pre位置的值与关键值进行交换(因为pre位置始终小于关键值)
最后和普通的递归一样递归执行左右两侧即可
代码
void quicksort(int* arr, int left, int right) {//双指针if (left >= right)return;int cur = left + 1, pre = left;while (cur <= right) {if (arr[cur] < arr[left] && ++pre < cur)swap(&arr[cur], &arr[pre]);cur++;}swap(&arr[left], &arr[pre]);quicksort(arr, left, pre - 1);quicksort(arr, pre + 1, right);
}
快速排序(非递归)
原理
我们可以使用栈进行模拟递归,首先创建一个栈,将数组的左右边界打入栈中,进入循环
当栈不为空时持续执行循环
根据自己的实际情况判断左右边界,如果先打入的是右边界,那么栈顶元素就是左边界
取出左右边界后,执行一次快排并返回关键值所在位置
如果关键值左侧不止一个元素,那么就打入左侧的左右边界
右侧同理
这样,我们就实现了非递归的快速排序
代码
int part(int* arr, int left, int right) {if (left >= right)return 0;int cur = left + 1, pre = left;while (cur <= right) {if (arr[cur] < arr[left] && ++pre < cur)swap(&arr[cur], &arr[pre]);cur++;}swap(&arr[left], &arr[pre]);return arr[pre];
}
void quicksort1(int* arr, int left, int right) {//非递归Stack stack;StackInit(&stack);StackPush(&stack, right);StackPush(&stack, left);while (!StackEmpty(&stack)) {int begin = StackTop(&stack);StackPop(&stack);int end = StackTop(&stack);StackPop(&stack);int key = part(arr, begin, end);if (key - 1 > begin) {StackPush(&stack, key-1);StackPush(&stack, begin);}if (key + 1 < end) {StackPush(&stack, end);StackPush(&stack, key + 1);}}
}
归并排序
介绍
归并排序是通过不断细分左右边界,使局部有序后扩大范围使整体有序的排序
优点
效率较高,且不会受原数组排列顺序影响
缺点
需要额外开辟一块等大的数组
图片
原理
创建等大的辅助数组
拆分为两块数组
先递归自身使左右两边有序
与链表类似
比较分成的两块有序数组的元素大小并排列在辅助数组中
整体有序后拷贝到原数组中
代码
void _Mergesort(int* arr, int*tmp,int left,int right) {if (left >= right)return;int mid = (left + right) / 2;int begin1 = left, end1 = mid, begin2 = mid + 1, end2 = right,i=left;_Mergesort(arr, tmp, begin1, end1);_Mergesort(arr, tmp, begin2, end2);while (begin1 <= end1 && begin2 <= end2) {if (arr[begin1] < arr[begin2]) {tmp[i++] = arr[begin1];begin1++;}else {tmp[i++] = arr[begin2];begin2++;}}while (begin1 <= end1) {tmp[i++] = arr[begin1];begin1++;}while (begin2 <= end2) {tmp[i++] = arr[begin2];begin2++;}memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
}
归并排序(非递归)
我们要用到希尔排序时创建的一个变量:gap
gap为一个数组拆分后单个小数组的元素个数
最小为一
当gap小于总数时
按照gap为一组,两组为一大组的顺序从左到右进行排序
当右侧起始位置超出时,直接退出,因为左侧小数组本身就是有序的
右侧终止位置超出时修正即可
单次遍历结束后将辅助数组元素拷贝回原数组即可
代码
void MergesortNonR(int* arr, int n) {int gap = 1;//gap为每小组元素个数,两个小组为一大组进行比较int* tmp = (int*)malloc(sizeof(int) * n),i;while (gap < n) {for (i = 0; i < n; i+=2*gap) {int begin1 = i, end1 = begin1 + gap - 1;int begin2 = end1 + 1, end2 = begin2 + gap - 1, j = i;if (begin2 >= n)break;if (end2 >= n)end2 = n - 1;while (begin1 <= end1 && begin2 <= end2) {if (arr[begin1] > arr[begin2])tmp[j++] = arr[begin2++];elsetmp[j++] = arr[begin1++];}while (begin1 <= end1)tmp[j++] = arr[begin1++];while (begin2 <= end2)tmp[j++] = arr[begin2++];memcpy(arr + i, tmp + i, sizeof(int) * gap * 2);}gap *= 2;}free(tmp);tmp = NULL;
}