递归实现链表的冒泡排序。
2014-09-28 02:02
197 查看
我们经常通过链表方式处理问题。链表的 创建、插删、合并、逆置、等等我们都通过非递归方法和递归方法实现过了,但是 冒泡排序 一直是用非递归的循环方法进行处理,这两天突发奇想,为啥不用递归试一试呢?O(∩_∩)O~~然后好好想了一下,恕在下愚钝,最终代码写成这个样子已是极限,。
下面是我的思路。
思考:如何用递归实现冒泡排序?我觉得排序的代码应该是一样的,都是用中间变量t_num来交换数据,而不是通过改变节点地址关系。(如果这个方法真的可以实现的话,那肯定是很厉害的算法⊙o⊙!)既然交换方式是相同的,那么需要解决的就是如何将链表进行n次完整的递归,(在我的定义中n为全部节点个数,一次完整的递归是从当前调用点递归到最后一个节点,然后层层返回到这个调用点的上一个调用点)。
我想了下,如果一个函数中只有一条递归语句,应该很难实现这个过程,因为一次递归的话,跑到最后一个节点就得返回了,只能将链表中的最值排到链表尾部,而整体目标尚未达成。所以在我的sort函数中,有两条递归语句。
既然有两条递归语句,那么一定得为这两条语句设定严格的停止条件,否则函数将无法停止。(这也是所有递归算法都应该有的东西),所以我设定了tag值。
在我的设想中:
第一条递归语句放在sort函数首部。在sort函数被激活之后,应该先通过递归一直调到链表尾部,(第一条递归语句的作用就是递归到链表尾部,并且这条语句只能被执行n-2次,因为最后一个节点没有后继结点。即从第一次开始处理数据之后,这条递归语句就再也不能被执行了)然后每次返回之前都比较当前节点的num与后继结点的num,然后进行交换处理。这样可以保证,链表的处理次序过程是从后向前倒序进行的,但排序过程还是从前向后的!)这样倒着返回、正着处理的好处是,保证当前处理节点之后的所有节点的信息都是已经排好序的!!
第二条递归语句放在sort函数尾部。每一次当前节点(为说明方便,设此节点为king)数据处理完毕后,都会再次递归(若到达倒数第二个节点则不用继续递归),将下一个节点的地址传给sort函数,然后层层递进并且处理数据,(此时第一条递归语句已经被屏蔽不能在执行,tag为0),直到递归到达倒数第二个节点,因为在倒数第二个节点,所以第二条递归语句也不执行。然后层层返回,最终返回到king的前驱结点。接着在处理king前驱结点的数据,然后激活第二条递归语句,将king的地址传给sort函数继续调用,然后边处理数据边递归直到倒数第二个节点,这样就将king前驱节点及其之后所有节点的信息都排序好了,然后层层返回到king前驱的前驱,继续进行这样的重复操作。。。
最终返回到头结点,然后处理头结点的数据(此时头结点之后的数据已经全部排好序了),在层层递归调用,将头结点里的数据放到它应该在的位置上,随后层层返回到主函数。由于没有改变节点的链接关系,所以头结点仍为head,sort函数类型为void。
限于我表达能力有限,说了这么多,也不知道到底有没有成功将我的思路表达而出,下面贴上源代码,作为程序猿的我们,自己理解的效果肯定还是比听别人说的要高得多。总之还望路过的英雄多多指点。
最后,虽然代码运行成功,但我仍有很多地方还是不清楚。比如代码的时间复杂度是多少,递归次数=(n-2)+1+2+3+······+(n-3)+(n-2)=n*(n-2),但由于用的是递归,所以我不知道到底该怎么算。。
还有代码的优化,其实不用每次都跑到倒数第二个节点的,但是我暂时也没想到该怎么修改。以及其他好多问题。
况且这还只算是最初等的算法了吧,之后有那么多的内容还可以去学习!
所以,路漫修远~
顺便膜拜路过的大神,真诚的求指导与修改,不胜感激!
下面是我的思路。
思考:如何用递归实现冒泡排序?我觉得排序的代码应该是一样的,都是用中间变量t_num来交换数据,而不是通过改变节点地址关系。(如果这个方法真的可以实现的话,那肯定是很厉害的算法⊙o⊙!)既然交换方式是相同的,那么需要解决的就是如何将链表进行n次完整的递归,(在我的定义中n为全部节点个数,一次完整的递归是从当前调用点递归到最后一个节点,然后层层返回到这个调用点的上一个调用点)。
我想了下,如果一个函数中只有一条递归语句,应该很难实现这个过程,因为一次递归的话,跑到最后一个节点就得返回了,只能将链表中的最值排到链表尾部,而整体目标尚未达成。所以在我的sort函数中,有两条递归语句。
既然有两条递归语句,那么一定得为这两条语句设定严格的停止条件,否则函数将无法停止。(这也是所有递归算法都应该有的东西),所以我设定了tag值。
在我的设想中:
第一条递归语句放在sort函数首部。在sort函数被激活之后,应该先通过递归一直调到链表尾部,(第一条递归语句的作用就是递归到链表尾部,并且这条语句只能被执行n-2次,因为最后一个节点没有后继结点。即从第一次开始处理数据之后,这条递归语句就再也不能被执行了)然后每次返回之前都比较当前节点的num与后继结点的num,然后进行交换处理。这样可以保证,链表的处理次序过程是从后向前倒序进行的,但排序过程还是从前向后的!)这样倒着返回、正着处理的好处是,保证当前处理节点之后的所有节点的信息都是已经排好序的!!
第二条递归语句放在sort函数尾部。每一次当前节点(为说明方便,设此节点为king)数据处理完毕后,都会再次递归(若到达倒数第二个节点则不用继续递归),将下一个节点的地址传给sort函数,然后层层递进并且处理数据,(此时第一条递归语句已经被屏蔽不能在执行,tag为0),直到递归到达倒数第二个节点,因为在倒数第二个节点,所以第二条递归语句也不执行。然后层层返回,最终返回到king的前驱结点。接着在处理king前驱结点的数据,然后激活第二条递归语句,将king的地址传给sort函数继续调用,然后边处理数据边递归直到倒数第二个节点,这样就将king前驱节点及其之后所有节点的信息都排序好了,然后层层返回到king前驱的前驱,继续进行这样的重复操作。。。
最终返回到头结点,然后处理头结点的数据(此时头结点之后的数据已经全部排好序了),在层层递归调用,将头结点里的数据放到它应该在的位置上,随后层层返回到主函数。由于没有改变节点的链接关系,所以头结点仍为head,sort函数类型为void。
限于我表达能力有限,说了这么多,也不知道到底有没有成功将我的思路表达而出,下面贴上源代码,作为程序猿的我们,自己理解的效果肯定还是比听别人说的要高得多。总之还望路过的英雄多多指点。
#include<stdio.h> /*利用递归实现:创建链表 、冒泡排序 */ #include<stdlib.h> #define NULL 0 int tag=1; //tag初始化为1 typedef struct node{ int num; struct node * next; }ElemSN; ElemSN * creatlink(int n); void out(ElemSN * head); void sort(ElemSN *p); int main (void){ ElemSN * head; printf("请输入十个数据:\n"); head=creatlink(10); //创建了十个节点 printf("\n原链表为:\t\t"); out(head); sort(head); printf("\n冒泡排序后的链表为:\t"); out(head); printf("\n\n"); return 0; } void sort(ElemSN *p){ int t; if(p->next->next&&tag){ //当跑到倒数第二个节点后,tag=0,之后就再也不执行这条语句了*/ sort(p->next); //第一条递归语句 } else tag=0; if(p->num<p->next->num){ //处理节点数据 t=p->num; p->num=p->next->num; p->next->num=t; } if(p->next->next) sort(p->next); //第二条递归语句 } ElemSN * creatlink(int n) { ElemSN * head = NULL; if(n){ head=(ElemSN *)malloc(sizeof(ElemSN)); scanf("%d", &head->num); head->next = creatlink(n-1); } return head; } void out(ElemSN * head){ ElemSN *p; for(p=head;p!=NULL;p=p->next) printf(" %d",p->num); }
最后,虽然代码运行成功,但我仍有很多地方还是不清楚。比如代码的时间复杂度是多少,递归次数=(n-2)+1+2+3+······+(n-3)+(n-2)=n*(n-2),但由于用的是递归,所以我不知道到底该怎么算。。
还有代码的优化,其实不用每次都跑到倒数第二个节点的,但是我暂时也没想到该怎么修改。以及其他好多问题。
况且这还只算是最初等的算法了吧,之后有那么多的内容还可以去学习!
所以,路漫修远~
顺便膜拜路过的大神,真诚的求指导与修改,不胜感激!
相关文章推荐
- 带头节点链表的反转 循环和递归 C#实现
- 递归实现两个链表合并
- 冒泡排序(链表实现)
- 经典排序——归并、快排递归与非递归实现与冒泡排序
- 递归求集合子集(两种方法实现(数组,链表))
- C递归实现单向链表的反转
- 递归和非递归实现链表反转
- 链表实现冒泡排序
- 一些常用算法[数组全排列算法,单链表反转(递归实现),字符串反转,桶排序]
- 下标注意【算法】冒泡排序与选择排序的递归实现
- 合并两个链表递归和非递归实现
- C/C++面试程序题(一)——字符串反转、链表反转的递归、非递归实现
- C递归实现单向链表的反转
- 【100题】反转链表(递归实现)
- 用递归方法实现两个链表head1和head2各自有序,请把它们合并成一个链表仍然有序。(c/c++)
- 有序链表的合并(递归实现)
- 递归实现合并两个有序链表成一个链表依然有序
- 两个有序链表合并递归实现及非递归实现
- 程序员面试宝典之数据结构基础---⑤单链表逆序的递归与非递归实现
- 合并两个排序链表--迭代和递归分别实现