门户网站意思网站建设规划书 简版
web/
2025/10/2 22:38:38/
文章来源:
门户网站意思,网站建设规划书 简版,wordpress文章评论数量,wordpress底部浮动窗口欢迎来到博主的专栏——C语言数据结构 博主ID#xff1a;代码小豪 文章目录 冒泡排序冒泡排序的代码及原理快速排序快速排序的代码和原理快速排序的其他排序方法非递归的快速排序 冒泡排序
相信冒泡排序是绝大多数计科学子接触的第一个排序算法。作为最简单、最容易理解的排序…欢迎来到博主的专栏——C语言数据结构 博主ID代码小豪 文章目录 冒泡排序冒泡排序的代码及原理快速排序快速排序的代码和原理快速排序的其他排序方法非递归的快速排序 冒泡排序
相信冒泡排序是绝大多数计科学子接触的第一个排序算法。作为最简单、最容易理解的排序算法冒泡排序虽然效率不高但是冒泡排序的思路给了其他排序算法一些启发。
冒泡排序的思路如下 1从第一个数据开始向后继元素比较大小、若满足条件大于或小于则交换数据的位置然后从后一个位置开始继续比较。 2当N-1与N进行数据比较后、完成一趟冒牌排序然后从头开始继续进行冒牌排序 3完成N-1趟排序后、冒牌排序结束。 可以发现、在第一趟冒泡排序结束后最大值7排到了最后一位而升序数组中的7也是排到最后一位。这一趟冒泡排序就确定了升序数组中的一位。
当第二趟冒泡排序开始时由于最后一位的数据已经确定了因此不再需要参与排序将end向前移动一位以此类推。
冒泡排序的代码及原理
void Swap(int* e1, int* e2)//交换函数
{int tmp *e1;*e1 *e2;*e2 tmp;
}
void BubbleSort(int* a, int n)
{for (int i 0; i n-1; i)//共计排n-1趟{int end n - i - 1;for (int begin 0;//每趟冒泡排序从0开始begin end;//当beginend时结束begin){if (a[begin] a[begin 1])//满足条件交换数据{Swap(a[begin], a[begin 1]);}}}
}冒牌排序的原理如下 每一趟冒泡排序都能使至少一个数据处于正确的升降序的位置。即每趟排序都能让当前范围的最大值位于最后一个位置好比水中的鱼吐出的泡泡从水底到水面渐渐变大。
快速排序
快速排序和冒泡排序都有一个相似之处或者是一种排序的思路即一趟排序完成单个或多个数据的定位将数据排在最终确定的位置上多次排序后将所有数据都完成定位最终完成排序操作。
冒泡排序的思路是每次确定最后一位因此每趟排序都需要将整个数组遍历一遍导致时间复杂度非常高。快速排序作为最著名昭著的排序算法以高效率深受程序员喜爱这里讲讲快排的优化之处。
先来了解一下快速排序的步骤 1选取数组中的任意一个数据作为关键数据key 2让key左边的数据小于大于key右边的数据大于小于key 3将整体分割为两部分一部分是key左边另一部分是key右边以这些部分作为一个整体重复123操作直到所以数据不可分割为止。
这个思路单凭讲述时很难理解其中奥义的。我们先拆分步骤逐渐讲解。 1选取key可以选择区间中的任意数据选取方法通常有三种取队首、取队尾、随机值取中间数通常来说结合三数取中即在队首、队尾、随机之间选择中间数作为key是最合理的。但这里为了方便讲解选择取队首作为key
2中让key左边的数据小于key右边的数据大于key有多种方法总体而言对效率影响不大我们先来了解快排发明者霍尔的方法。
首先将待排序的区间选出队首第一个值为key值。区间最左边设置一个left最右边设置一个right。如图
让right往左边遍历若遍历的数据小于key则right停留在该数据处。
当right找到比key小的数后让left向右遍历找到比key大的数。找到比key大的数后停留在该数据处。 当left和right都停留时交换left和right 交换结束后重复上述步骤让right向左遍历。 此时left继续向右遍历left与right重合此时将key与重合位置的数据交换。 以key为分割线将这段区间分为两个区间。 再对这两个区间进行快排。以此类推。 当某个区间的left和right重合数据不可再分割不再需要排序。
快速排序的代码和原理
快速排序的原理如下 和冒泡排序有个类似的点每一趟冒泡排序都有一个数据被定位快速排序也是如此key位置的左边小于key右边大于key那么key这个位置就是符合排序要求的位置的。那么快速排序比冒泡排序有效率的点在哪呢
冒泡排序每趟排序都需要将整个数组遍历一遍。快速排序使用了一种分治的方法将区间分割成多个小区间进行排序减少了需要遍历的元素个数。 此时快速排序就不再需要遍历整个数组了而是遍历小区间遍历区间1只用遍历4个数据定位一个区间2只需遍历2个数据定位1当数据数量变得很多时快速排序的优势更加明显效率更快。
代码如下
void QuickSort(int* a, int begin, int end)
{int left begin;int right end-1;if (left right)//区间不可再分割结束递归{return;}int key left;//队首取keywhile (left right)//遍历条件{while (left right a[key] a[right])//right向左寻找比key小的值{right--;}while (left righta[key]a[left])//left向右寻找比key大的值{left;}Swap(a[left], a[right]);//找到之后交换}Swap(a[key], a[left]);//left与right相等与key交换。key left;QuickSort(a, begin, key);//分割QuickSort(a, key 1, end);//分割
}快速排序的其他排序方法
这里介绍另外一种排序方式——前后指针法。霍尔使用left和right的找寻方法非常巧妙但是代码较复杂。这里讲一种较为简洁的找寻方法对效率影响不大。
定义一个prev和cur指向队首与队首的后一个元素key值仍取队首。
步骤如下 1判断cur的值是否大于prev 若大于cur往前移动一位prev不变。 若小于prev往前移动一位与cur交换数据cur再往前移动一位。若prev指针与cur相遇不交换。 2当cur超出区间后让key与prev交换数据。 剩下也是将key分割两个区间继续分治只是找寻方法改变了。
为什么这种方法能完成key的左边比key小右边比key大呢? 首先我们可以发现cur与prev之间的元素都是比key大的。我们重新回顾一下步骤。 1最初开始时prev与cur之间不存在任何数据因为他们相邻。 2cur与prev最初是挨着的当cur遍历到比key大的树据才会有所距离此时距离之间的数据都是比key大到数。 3为了保持cur与key之间的数都是大于key值需要将prev后一位的数据一定大于key与小于key值的cur进行交换 4最后prev的值一定是小于key的因为此时prev的值是从小于key的cur值里交换而来的。所以prev一定小于key。 如果prev和cur中间的数据保持比key大那么当cur超出范围时key左边一定小于key右边一定大于key
代码如下
void QuickSort(int* a, int begin, int end)
{if (begin end)//区间不可分割时停止递归{return;}int prev begin;int cur begin 1;int key begin;while (cur end)//cur没超出区间{if (a[cur] a[key])//当cur小于key的值时{prev;if (prev ! cur){Swap(a[prev], a[cur]);}}cur;//不管是大于key还是小于keycur最后都要}Swap(a[prev], a[key]);key prev;QuickSort(a, begin, key);QuickSort(a, key1, end);
}非递归的快速排序
前面讲了快排的递归形式但是递归就说明需要大量的调用堆栈一旦递归深度过高就会导致栈溢出因此有人想出了快速排序的非递归方法。
想要替代递归的作用就得先找到为什么使用递归以及递归是为了实现什么。
快速排序中的递归起的作用是为了记录分割的区间的起始点与结束点
QuickSort(a, begin, key);
QuickSort(a, key1, end);如果我们有办法将每趟快速排序的分割区间记录下来。就能取代递归的作用。
我们可以创建一个栈用来记录快速排序的区间。这样子就不再需要递归了。
记录的步骤如下 1将左区间和右区间压入栈中 2将左区间和右区间弹出。将弹出的数据作为一个区间进行一趟快速排序 3完成快速排序后将新分割好的节点压入栈中 4若取出的左右区间不构成新区间不执行这个操作。 循环往复直到栈变成空栈。
代码如下
void QuickSort(int* a, int begin, int end)
{stack s1;StackInit(s1);//初始化栈StackPush(s1,begin);//压入左区间StackPush(s1,end);//压入右区间while (!StackEmpty(s1)){int right StackTopData(s1);//出栈StackPop(s1);int left StackTopData(s1);//出栈StackPop(s1);int cur left1;int prev left;int key left;while (cur right){if (a[cur] a[key]){prev;if (prev ! cur){Swap(a[cur], a[prev]);}}cur;}Swap(a[prev], a[key]);key prev;//[left,key],[key1,right]if (left key){StackPush(s1, left);//压入分割后的左区间StackPush(s1, key);//压入分割后的右区间}if (key 1 right){StackPush(s1, key 1);//压入分割后的左区间StackPush(s1, right);//压入分割后的右区间}}StackDestory(s1);
}栈的实现函数
void StackInit(stack* ps)//栈的初始化
{ps-data NULL;ps-capacity 0;ps-top 0;
}void StackPush(stack* ps, datatype n)//压栈
{assert(ps);if (ps-top ps-capacity){int newcapacity ps-capacity 0 ? 4 : 2 * ps-capacity;datatype* tmp (datatype*)realloc(ps-data, sizeof(stack) * newcapacity);assert(tmp);ps-data tmp;ps-capacity newcapacity;}ps-data[ps-top] n;ps-top;
}void StackPop(stack* ps)//出栈
{if (StackEmpty(ps)){perror(Stack is empty\n);return;}ps-top--;
}bool StackEmpty(stack* ps)//判断是否空栈
{return ps-top 0;
}datatype StackTopData(stack* ps)//取栈顶
{if (StackEmpty(ps)){perror(Stack is empty\n);exit(1);}return ps-data[ps-top - 1];
}void StackDestory(stack* ps)//销毁栈
{assert(ps);free(ps-data);ps-data NULL;ps-top 0;ps-capacity 0;
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/85863.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!