链表常见操作:逆置(反转)
来源:互联网 发布:注册会计师软件哪个好 编辑:程序博客网 时间:2024/06/05 22:56
链表中的一个很常见的操作是:链表的逆置,也叫链表的反转。
如:1->3->5->7->9 反转后是 9->7->5->3->1
方法一:使用指针
红色的箭头是新的变换,明白了操作原理就很好写代码了。
使用了三个指针:pre(前驱) cur(当前) rear(后继),经过以上的四步变换,目地是,使cur指向的节点成功逆置(反转)指向pre所指向的节点。后面的节点的逆置,是同样的。
关键代码是:
void reverse(Node *&head){if (head == NULL || head->next==NULL) //空或者只有一个元素不用逆置return;Node *pre, *cur, *rear;pre = head;cur = head->next;while (cur){rear = cur->next;cur->next = pre;pre = cur;cur = rear;}//以下两步,很重要head->next = NULL; //这一步会使新的尾节点的链域置空head = pre; //head指针指向新的一头}
写一个完整的测试用例
#include<stdio.h> #include<stdlib.h>typedef struct node //节点类型定义 {int data;struct node *next;}Node;void printlist(Node *head) //打印链表 {Node *p = head;while (p->next){printf("%-4d->", p->data);p = p->next;}printf("%-4d\n", p->data);}void reverse(Node *&head) //逆置 {if (head == NULL || head->next == NULL) //空或者只有一个元素不用逆置 return;Node *pre, *cur, *rear;pre = head;cur = head->next;while (cur){rear = cur->next;cur->next = pre;pre = cur;cur = rear;}//以下两步,很重要 head->next = NULL;head = pre;}int main(){Node p9{ 9, NULL };Node p7{ 7, &p9 };Node p5{ 5, &p7 };Node p3{ 3, &p5 };Node p1{ 1, &p3 };Node *head = &p1;printf("原表是\n");printlist(head);printf("逆置\n");reverse(head);printlist(head);system("pause");return 0;}
运行:
思考:我们知道链表一般是带有头节点的,而这里我们没有使用头节点。那么,我们如何对一个带有头节点的链表进行逆置呢?逆置后的链表也是要带有头节点的哦。大家可以动手试试,不妨把代码写在评论里,互相参考下,看有什么细节的不同。(楼主的一个写法,在一楼,欢迎不吝赐教,thanks)
方法二:在递归中逆置(反转)
思路:在对当前节点逆置时,先递归地逆置其后继节点,然后将后继节点指向当前节点。
直接给一个测试用例:
#include<stdio.h>#include<stdlib.h>typedef struct node{int data;struct node *next;}Node;void printlist(Node *head){Node *p = head;while (p->next){printf("%-4d->", p->data);p = p->next;}printf("%-4d\n", p->data);}void reverseWithRecursion(Node *&head, Node *cur) //递归逆置{if (cur->next == NULL) //最后一个元素是递归终止条件{head = cur;return;}Node *rear = cur->next;reverseWithRecursion(head, rear);rear->next = cur;//cur->next = NULL; //句一,这一句可以注释掉}void reverse(Node *&head){if (head == NULL || head->next == NULL) //为空或只有一个元素就结束 return;Node *cur=head;reverseWithRecursion(head, cur);cur->next = NULL; //句二,这一句可以注释掉,不过句一和句二必须保留一句}int main(){Node *head = NULL;Node p8{ 8, NULL };Node p6{ 6, &p8 };Node p4{ 4, &p6 };Node p2{ 2, &p4 };Node p0{ 0, &p2 };head = &p0;printf("原链表\n");printlist(head);printf("逆置\n");reverse(head);printlist(head);system("pause");return 0;}
运行:
对递归逆置函数的理解是最重要的,也是最难理解的。难点有:
- 句一的作用。这个初看很难让人明白,甚至误解。我们知道原链表的第一个节点的链域在最后要置空,但这里每次递归都置空,是否会出问题?画个图后,发现不会。我们对递归的过程要理解,并且得明白上一次的递归函数中的rear指向的正是这一次的cur,(它俩指向同一节点)。所以即使被置空了,当递归返回上一层时,该链域依然会被修改。当然,除了原链表的第一个节点(想想为什么?),这也是这句话的真实目地:让原链表的第一个节点的链域在最后被置空。
- 由上一点的分析,我们可以想到:为何不直接修改原链表第一个节点的链域呢?何必费心一路递归修改,这样会造成很多的操作是没必要的。事实上的确可以,这就是句二的作用,那就是说不用句一,只用句二就可以了。但它俩至少要有一个,从效率上看,推荐只使用句二。
- 第一个参数被设计成引用类型,它的意义:在递归到原链表的尾节点时,把head指向该曾经的尾节点(也就是新链表的第一个节点)。
专栏目录:
- 数据结构与算法目录
- c指针
2 0
- 链表常见操作:逆置(反转)
- 链表常见操作:逆置(反转) .
- 链表常见操作java实现二:反转链表,从尾到头倒序遍历
- 算法-链表反转操作
- 面试常见算法之---反转链表
- 链表操作之链表反转
- 链表操作:反转链表
- 链表操作 部分反转链表
- 链表操作:创建,插入,排序,反转
- 链表操作:创建,插入,排序,反转
- 链表基本操作及其反转
- 链表、反转链表操作,Java实现
- 面试中常见链表问题12:单链表反转(递归)
- 链表常见操作
- 常见链表操作
- 链表常见操作
- 链表常见操作练习
- 链表的常见操作
- QC部分浏览器不支持、不能加载组件
- 图像边缘检测--OpenCV之cvCanny函数
- 使用FlashPaper 实现JSP在线阅读
- Java类加载机制
- QC(ALM11)不支持IE 9、10等浏览器的问题
- 链表常见操作:逆置(反转)
- 写了一个对自己很实用的安卓软件
- mapreduce 作业优化
- 颜色代码大全
- linux进程高cpu问题分析
- HDU4565 2013长沙赛区邀请赛A题。。。
- java学习篇——clone方法
- dentry
- position:absolute 含义