快速排序霍尔算法
void QuickSort(int* arr, int begin,int end) {
if (begin >= end)
return;
int keyi = begin;
int right = end;
int left = begin;
while (right > left) {
//此时不能先走左边,应为先走左边会是右边找到的不一定是小值,即两指针相遇在一个大于keyi值的地方
//先走右边即一定能确保相遇的地方一定是小于keyi值的地方
while (right > left && arr[keyi] <= arr[right]) {
right--;
}
while (right > left && arr[keyi]>=arr[left]) {
left++;
}
swap(arr + left, arr + right);
}
swap(arr + left, arr+keyi);
QuickSort(arr, begin, left - 1);
QuickSort(arr, left+1,end);
}
右边指针一定要先走,才能确保最后被交换过去的是比a[left]小的值
while (right > left && arr[keyi] <= arr[right]) {
right--;
}
这段代码前面语句一定要注意,防止在找的过程中两个指针交叉。
后面语句一定要注意等号,防止指针一直停在那里发生死循环。
快速排序挖坑法
// 快速排序挖坑法
void QuickSort2(int* a, int left, int right) {
if (left >= right)
return;
int begin = left;
int end = right;
int key = a[left];
int holei = left;
while (right > left) {
while (right > left && a[right] >= key) {
right--;
}
a[holei] = a[right];
holei = right;
while (right > left && a[left] <= key) {
left++;
}
a[holei] = a[left];
holei = left;
}
a[left] = key;
QuickSort2(a,begin,left-1);
QuickSort2(a, left + 1, end);
}
将要排序的第一个元素设为key,且将第一个元素下标设为坑
右边找比key值小的数,找到之后将a[right]填入坑中,在将right设为坑
最后两个指针相遇,将key值填入坑中,即完成左右两端的排序
快速排序两指针法
// 快速排序前后指针法
void QuickSort(int* a, int left, int right) {
if (right <= left)
return;
int begin = left;
int end = right;
int keyi = left;
int prev = left, cur = left + 1;
while (cur <= right) {
while (a[cur] >= a[keyi] && cur <= right) {
cur++;
}
if (cur <= right) {
prev++;
int temp;
temp = a[prev];
a[prev] = a[cur];
a[cur] = temp;
}
cur++;
}
int temp;
temp = a[prev];
a[prev] = a[keyi];
a[keyi] = temp;
QuickSort(a, begin, prev - 1);
QuickSort(a, prev + 1, end);
}
保存left为keyi,a[left]设为prev,a[left+1]设为cur,cur找比keyi元素值小的数字,找到后prev++
然后交换a[prev]和a[cur],cur再++,加 if (cur <= right) 是因为cur在上面循环已经越界了,后面的a[prev]被赋值了,就造成了越界最后再将prev停的值与keyi的值交换,保证了prev前面均是小于a[keyi]的值
快速排序非递归实现
// 快速排序 非递归实现
void QuickSortNonR(int* a, int left, int right) {
Stack st;
StackInit(&st);
StackPush(&st, left);
StackPush(&st, right);
while (isStackEmpty(&st)) {
int end = StackTop(&st);
StackPop(&st);
int begin = StackTop(&st);
StackPop(&st);
int keyi = begin;
int prev = begin, cur = begin + 1;
while (cur <= right) {
while (a[cur] >= a[keyi] && cur <= right) {
cur++;
}
if (cur <= right) {
prev++;
int temp;
temp = a[prev];
a[prev] = a[cur];
a[cur] = temp;
}
cur++;
}
int temp;
temp = a[prev];
a[prev] = a[keyi];
a[keyi] = temp;
if (end > prev + 1) {
StackPush(&st, prev + 1);
StackPush(&st, end);
}
if (prev - 1 > begin) {
StackPush(&st, begin);
StackPush(&st, prev - 1);
}
}
}
先创建一个栈,将两个区间入栈,将栈顶元素赋值给left,right,注意赋值一个出一个。
while循环判断为空就结束。
只要区间还>=1就继续入栈。
归并排序递归
void _MergeSort(int* a, int* temp, int left, int right) {
if (right <= left)
return;
int mid = (right + left) / 2;
_MergeSort(a, temp, left, mid);
_MergeSort(a, temp, mid + 1, right);
int begin1 = left, end1 = mid;
int begin2 = mid + 1, end2 = right;
int index = left;
while (begin1 <= end1 && begin2 <= end2) {
if (a[begin1] <= a[begin2]) {
temp[index++] = a[begin1++];
}
else {
temp[index++] = a[begin2++];
}
}
while (begin1 <= end1)
temp[index++] = a[begin1++];
while (begin2 <= end2)
temp[index++] = a[begin2++];
memcpy(a + left, temp + left, sizeof(int) * (right - left + 1));
}
// 归并排序递归实现
void MergeSort(int* a, int n) {
int* temp = (int*)malloc(sizeof(int) * n);
assert(temp);
_MergeSort(a, temp, 0, n - 1);
/*for (int i = 0; i < n; i++) {
a[i] = temp[i];
}*/
free(temp);
}
类似与二叉树前序遍历,两个数为一个区间等价与一个节点。
归并排序非递归
// 归并排序非递归实现
void MergeSortNonR(int* a, int n) {
int* temp = (int*)malloc(sizeof(int) * n);
assert(temp);
int gap = 1;
while (gap < n) {
for (int i = 0; i < n; i += 2 * gap) {
int begin1 = i, end1 = i + gap - 1;
int begin2 = i + gap, end2 = i + 2 * gap - 1;
int index = i;
if (end1 >= n)
break;
if (end2 >= n)
end2 = n - 1;
while (begin1 <= end1 && begin2 <= end2) {
if (a[begin1] <= a[begin2]) {
temp[index++] = a[begin1++];
}
else {
temp[index++] = a[begin2++];
}
}
while (begin1 <= end1)
temp[index++] = a[begin1++];
while (begin2 <= end2)
temp[index++] = a[begin2++];
memcpy(a + i, temp + i, sizeof(int) * (gap - i) * 2);
}
gap = gap * 2;
}
free(temp);
}
最外层while控制排序最小区间大小,fro循环控制将区间大小一个等级的排序
如果begin2越界了,则不需要排序,直接拷贝回去。如果end2越界则修改end2到数组最后一个值