本文主要是介绍快排与归并的算法(非递归版),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一.快排
1.递归法(方法多样)
1>hoare版
注:该方法小编已经在上篇博客中介绍过了,就不在这里过多赘述了,如果有兴趣的小伙伴可以看看小编的上篇博客哦
2>挖坑法
1)方法介绍:定义最左边的数据为key,此时最左边的位置内可视为没有数据(即被挖了个坑),定义L,R两个下标,分别位于最左侧和最右侧,R向前走,若找到比key小的数据停下来,将该处数据放在坑位中,这时R指向的位置成为新坑;L开始向后走,若找到比key大的数据停下来,将该处数据放在坑位中,这时L指向的位置成为新坑;当R与L相遇时,将key放在相遇位置的坑中,此时完成依次排序,下面将数据分成[left,key-1],[key+1,right]两个区间进行下一轮的排序,直至排序完成
2)时间复杂度:O(N*logN)
空间复杂度:O(1)
3)代码实现
int qSortWay2(int* a, int left, int right)
{int key = a[left];int begin = left, end = right;while (begin < end){while (begin<end && a[end] > key){end--;}a[begin] = a[end];while (begin<end && a[begin] < key){begin++;}a[end] = a[begin];}a[begin] = key;return begin;
}
3>前后指针法
1)方法介绍:定义prev,cur两个下标,prev指向key所在位置,cur指向prev的下一个位置,cur向后走,如果找到比key小的数据,先将prev++,再将cur,prev所在位置的数据交换,cur继续向后找比key小的数据,直至cur越界访问数据,返回prev作为下次排序的分割点下标
2)时间复杂度:O(N*logN)
空间复杂度:O(1)
3)代码实现
int qSortWay3(int* a, int left, int right)
{int keyi = left;int prev = left;int cur = prev + 1;while (cur <= right){if (a[cur] < a[keyi] && ++prev != cur)Swap(&a[cur], &a[prev]);cur++;}Swap(&a[prev], &a[keyi]);return prev;
}
2.非递归法
1>方法介绍:利用栈将每个区间的左右下标分别入栈,待数据被细分到只有左下标>=右下标时,开始将左右下标出栈,进行排序
2>使用非递归法可以大大降低栈的消耗,但不一定能提高效率
1)利用栈模拟递归法实现非递归排序类似于二叉树的前序遍历
2)利用队列模拟递归法实现非递归排序类似于二叉树的层序遍历(利用队列可能无法实现排序,且空间消耗很大,不推荐使用)
3>代码实现
void QuickSortNonR(int* a, int left,int right)
{ST st;STInit(&st);STPush(&st, right);STPush(&st, left);while (!STEmpty(&st)){int begin = STTop(&st);STPop(&st);int end = STTop(&st);STPop(&st);int keyi = qSortWay3(a, begin, end);//[begin,keyi-1],keyi,[keyi+1,end]if (keyi+1 < end){STPush(&st, end);STPush(&st, keyi + 1);}if (begin < keyi - 1){STPush(&st, keyi - 1);STPush(&st, begin);}}STDestory(&st);
}
二.归并(非递归法)
1.方法介绍
1)利用gap对数据从小区间到大区间进行归并(类似于将归并的递归方法用循环的方式进行从底层到顶层的排序),同时对两组数据[begin,begin+gap-1],[begin+gap,begin+2*gap-1]归并
2)gap从1开始,实现11归并,再2倍增加
3)注意此时存在越界访问的分风险,此时可以采用如下方法进行避免越界
2.时间复杂度:O(N*logN)
空间复杂度:O(N)
3.代码实现
void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");return;}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 j = i;//前一组最后一个数据下标大于n-1,则后面一组数据全部越界if (end1 >= n){break;}//后一组最后一个数据下标大于n-1,则有部分数据越界,令尾巴等于n-1if (end2 >= n){end2 = n - 1;}while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}while (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));}gap = gap * 2;}free(tmp);tmp = NULL;
}
这篇关于快排与归并的算法(非递归版)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!