每天三道冲刺工作--用一种算法来颠倒一个链接表的顺序。现在在不用递归式的情况下做一遍。
2015-05-06 10:42
495 查看
定义一个方法(函数),实现输入一个链表的头结点,然后可以反转这个链表的方向,并输出反转之后的链表的头结点。
typedefstruct Node{
int data;
Node *next;
} Node, *List;
链表类的问题,涉及到了很多指针的操作,需要严谨的分析,全面的分析问题之后,在开始写代码,磨刀不误砍柴工!反转链表,直接的想法,就是把链表中指针的方向反转就可以了,如图所示:
假设 i 结点之前,我们把所有的结点的指针都已经反转了,那么自然 i 和以后的结点链接发生了断裂!如下图;
这样的话,无法继续遍历 i 以后的结点了,那么自然想到,在断链之前,提前保存之前的状态。那么自然想到定义三个指针,分别指向当前结点 i,i 的后继 j,i 的前驱 h 结点。保存断链之前的三个结点的连接状态。然后,假设没问题了,那么继续反转完毕,最后链表的尾结点就是反正链表的头结点了,也就是 next 为 null 的结点,是原始链表的尾结点。
#include <iostream>
using namespace std;
typedef struct Node{
int data;
Node *next;
} Node, *List;
Node * reverseList(List head){
//定义三个指针,保存原来的连接的状态
//当前结点指针
Node *pnow = head;
//当前结点的前驱指针,初始化是 NULL
Node *pre = NULL;
//当前结点的后继指针,初始化也是 null
Node *pnext = NULL;
//定义尾指针
Node *tail = NULL;
//开始遍历链表
while(pnow != NULL){
//如果当前结点不是 null,那么初始化 pnext 指针指向当前结点的下一个结点
pnext = pnow->next;
//如果找到了尾结点,初始化 tail 指针
if(NULL == pnext){
tail = pnow;
}
//进行链表的反转,当前结点的 next 指针指向前一个结点,实现链表方向的反转,此时发生了断链
pnow->next = pre;
//勿忘断链的情形,需要使用 pre 指针保存状态,pre 等价于是后移一个结点
pre = pnow;
//pnow 后移一个结点
pnow = pnext;
}
return tail;
}
定义的这个三个指针,目的就是防止断链之后无法继续遍历链表以后的结点,实现全部的反转。当 pnow 的 next 指向 pnow 的前驱pre(初始化是 null)的时候,已经实现了 pnow 和前驱pre的方向反转,但是 pnow 此时就和后继pnext断链了,那么使用 pre 后移的方式,指向 pnow,同时 pnow 也后移,指向 pnext,而 pnext 继续指向更新之后的 pnow 的 next 结点即可。从而实现了状态的保存,继续遍历全部结点,实现链表反转。
注意关于链表问题的常见注意点的思考:
1、如果输入的头结点是 NULL,或者整个链表只有一个结点的时候
2、链表断裂的考虑
下面看看递归的实现方式
递归的方法其实是非常巧的,它利用递归走到链表的末端,然后再更新每一个node的next 值 ,实现链表的反转。而newhead 的值没有发生改变,为该链表的最后一个结点,所以,反转后,我们可以得到新链表的head。
//递归方式
Node * reverseList(List head)
{
//如果链表为空或者链表中只有一个元素
if(head == NULL || head->next == NULL)
{
return head;
}
else
{
//先反转后面的链表,走到链表的末端结点
Node *newhead = reverseList(head->next);
//再将当前节点设置为后面节点的后续节点
head->next->next = head;
head->next = NULL;
return newhead;
}
}
程序刚开始执行,if 语句失效,进入 else 语句,然后执行Node *newhead = reverseList(head->next);第二个结点的指针参数传入递归函数,一直到,最后一个结点的指针参数传入递归函数,if 语句有效head->next == NULL,返回当前的head 给 newhead 指针指向,如图:
其实在递归函数栈内,按照后进先出的顺序,执行一级级的递归函数,返回末位结点给 newhead 之后,执行递归栈里的第二个递归函数,发生如图
返回 newhead,也就是新的反转之后的链表(临时的),然后进入到递归工作栈里的第一个递归函数,如图:
返回 newhead,也就是反转之后的链表,此时递归工作栈的函数全部执行,返回的结点就是反转之后的链表的头结点(之前的尾结点)
本文链接:全面分析再动手的习惯:链表的反转问题(递归和非递归方式),转载请注明。
java版
问题:
给一个单向链表,把它从头到尾反转过来。比如: a -> b -> c ->d 反过来就是 d -> c -> b -> a 。
分析:
假设每一个node的结构是:
[java]
view plaincopy
class Node {
char value;
Node next;
}
因为在对链表进行反转的时候,需要更新每一个node的“next”值,但是,在更新 next 的值前,我们需要保存 next 的值,否则我们无法继续。所以,我们需要两个指针分别指向前一个节点和后一个节点,每次做完当前节点“next”值更新后,把两个节点往下移,直到到达最后节点。
第一种方法就是把每个Node按照顺序存入到一个stack里面,这样,最后面一个就在最上面了。然后,把每一个再取出来,这样顺序就换过来了。
[java]
view plaincopy
public static Node reverse(Node head) {
Stack<Node> stack = new Stack<Node>();
// put all the nodes into the stack
while (head != null) {
stack.add(head);
head = head.next();
}
//reverse the linked list
Node current = stack.pop();
head = current;
while (stack.empty() != true) {
Node next = stack.pop();
//set the pointer to null, so the last node will not point to the first node.
next.setNext(null);
current.setNext(next);
current = next;
}
return head;
}
第二种方法就是利用两个指针,分别指向前一个节点和当前节点,每次做完当前节点和下一个节点的反转后,把两个节点往下移,直到到达最后节点。
[java]
view plaincopy
public static Node reverse(Node head) {
Node previous = null;
while (head != null) {
Node nextNode = head.next();
head.setNext(previous);
previous = head;
head = nextNode;
}
return previous;
}
上面代码使用的是非递归方式,这个问题也可以通过递归的方式解决。代码如下:
[java]
view plaincopy
public Node reverse(Node current)
{
if (current == null || current.next == null) return current;
Node nextNode = current.next;
current.next = null;
Node reverseRest = reverse(nextNode);
nextNode.next = current;
return reverseRest;
}
递归的方法其实是非常巧的,它利用递归走到链表的末端,然后再更新每一个node的next 值 (代码倒数第二句)。 在上面的代码中, reverseRest 的值没有改变,为该链表的最后一个node,所以,反转后,我们可以得到新链表的head。
参考:
http://stackoverflow.com/questions/354875/reversing-a-linked-list-in-java-recursively
http://blog.csdn.net/beiyeqingteng/article/details/7030020
转载请注明出处:http://blog.csdn.net/beiyetengqing
typedefstruct Node{
int data;
Node *next;
} Node, *List;
链表类的问题,涉及到了很多指针的操作,需要严谨的分析,全面的分析问题之后,在开始写代码,磨刀不误砍柴工!反转链表,直接的想法,就是把链表中指针的方向反转就可以了,如图所示:
假设 i 结点之前,我们把所有的结点的指针都已经反转了,那么自然 i 和以后的结点链接发生了断裂!如下图;
这样的话,无法继续遍历 i 以后的结点了,那么自然想到,在断链之前,提前保存之前的状态。那么自然想到定义三个指针,分别指向当前结点 i,i 的后继 j,i 的前驱 h 结点。保存断链之前的三个结点的连接状态。然后,假设没问题了,那么继续反转完毕,最后链表的尾结点就是反正链表的头结点了,也就是 next 为 null 的结点,是原始链表的尾结点。
#include <iostream>
using namespace std;
typedef struct Node{
int data;
Node *next;
} Node, *List;
Node * reverseList(List head){
//定义三个指针,保存原来的连接的状态
//当前结点指针
Node *pnow = head;
//当前结点的前驱指针,初始化是 NULL
Node *pre = NULL;
//当前结点的后继指针,初始化也是 null
Node *pnext = NULL;
//定义尾指针
Node *tail = NULL;
//开始遍历链表
while(pnow != NULL){
//如果当前结点不是 null,那么初始化 pnext 指针指向当前结点的下一个结点
pnext = pnow->next;
//如果找到了尾结点,初始化 tail 指针
if(NULL == pnext){
tail = pnow;
}
//进行链表的反转,当前结点的 next 指针指向前一个结点,实现链表方向的反转,此时发生了断链
pnow->next = pre;
//勿忘断链的情形,需要使用 pre 指针保存状态,pre 等价于是后移一个结点
pre = pnow;
//pnow 后移一个结点
pnow = pnext;
}
return tail;
}
定义的这个三个指针,目的就是防止断链之后无法继续遍历链表以后的结点,实现全部的反转。当 pnow 的 next 指向 pnow 的前驱pre(初始化是 null)的时候,已经实现了 pnow 和前驱pre的方向反转,但是 pnow 此时就和后继pnext断链了,那么使用 pre 后移的方式,指向 pnow,同时 pnow 也后移,指向 pnext,而 pnext 继续指向更新之后的 pnow 的 next 结点即可。从而实现了状态的保存,继续遍历全部结点,实现链表反转。
注意关于链表问题的常见注意点的思考:
1、如果输入的头结点是 NULL,或者整个链表只有一个结点的时候
2、链表断裂的考虑
下面看看递归的实现方式
递归的方法其实是非常巧的,它利用递归走到链表的末端,然后再更新每一个node的next 值 ,实现链表的反转。而newhead 的值没有发生改变,为该链表的最后一个结点,所以,反转后,我们可以得到新链表的head。
//递归方式
Node * reverseList(List head)
{
//如果链表为空或者链表中只有一个元素
if(head == NULL || head->next == NULL)
{
return head;
}
else
{
//先反转后面的链表,走到链表的末端结点
Node *newhead = reverseList(head->next);
//再将当前节点设置为后面节点的后续节点
head->next->next = head;
head->next = NULL;
return newhead;
}
}
程序刚开始执行,if 语句失效,进入 else 语句,然后执行Node *newhead = reverseList(head->next);第二个结点的指针参数传入递归函数,一直到,最后一个结点的指针参数传入递归函数,if 语句有效head->next == NULL,返回当前的head 给 newhead 指针指向,如图:
其实在递归函数栈内,按照后进先出的顺序,执行一级级的递归函数,返回末位结点给 newhead 之后,执行递归栈里的第二个递归函数,发生如图
返回 newhead,也就是新的反转之后的链表(临时的),然后进入到递归工作栈里的第一个递归函数,如图:
返回 newhead,也就是反转之后的链表,此时递归工作栈的函数全部执行,返回的结点就是反转之后的链表的头结点(之前的尾结点)
本文链接:全面分析再动手的习惯:链表的反转问题(递归和非递归方式),转载请注明。
java版
问题:
给一个单向链表,把它从头到尾反转过来。比如: a -> b -> c ->d 反过来就是 d -> c -> b -> a 。
分析:
假设每一个node的结构是:
[java]
view plaincopy
class Node {
char value;
Node next;
}
因为在对链表进行反转的时候,需要更新每一个node的“next”值,但是,在更新 next 的值前,我们需要保存 next 的值,否则我们无法继续。所以,我们需要两个指针分别指向前一个节点和后一个节点,每次做完当前节点“next”值更新后,把两个节点往下移,直到到达最后节点。
第一种方法就是把每个Node按照顺序存入到一个stack里面,这样,最后面一个就在最上面了。然后,把每一个再取出来,这样顺序就换过来了。
[java]
view plaincopy
public static Node reverse(Node head) {
Stack<Node> stack = new Stack<Node>();
// put all the nodes into the stack
while (head != null) {
stack.add(head);
head = head.next();
}
//reverse the linked list
Node current = stack.pop();
head = current;
while (stack.empty() != true) {
Node next = stack.pop();
//set the pointer to null, so the last node will not point to the first node.
next.setNext(null);
current.setNext(next);
current = next;
}
return head;
}
第二种方法就是利用两个指针,分别指向前一个节点和当前节点,每次做完当前节点和下一个节点的反转后,把两个节点往下移,直到到达最后节点。
[java]
view plaincopy
public static Node reverse(Node head) {
Node previous = null;
while (head != null) {
Node nextNode = head.next();
head.setNext(previous);
previous = head;
head = nextNode;
}
return previous;
}
上面代码使用的是非递归方式,这个问题也可以通过递归的方式解决。代码如下:
[java]
view plaincopy
public Node reverse(Node current)
{
if (current == null || current.next == null) return current;
Node nextNode = current.next;
current.next = null;
Node reverseRest = reverse(nextNode);
nextNode.next = current;
return reverseRest;
}
递归的方法其实是非常巧的,它利用递归走到链表的末端,然后再更新每一个node的next 值 (代码倒数第二句)。 在上面的代码中, reverseRest 的值没有改变,为该链表的最后一个node,所以,反转后,我们可以得到新链表的head。
参考:
http://stackoverflow.com/questions/354875/reversing-a-linked-list-in-java-recursively
http://blog.csdn.net/beiyeqingteng/article/details/7030020
转载请注明出处:http://blog.csdn.net/beiyetengqing
相关文章推荐
- 每天三道冲刺工作--颠倒一个句子中的词的顺序,比如将“我叫克丽丝”转换为“克丽丝叫我”,
- 用一种算法来颠倒一个链接表的顺序
- 每天三道冲刺工作--如何用递归算法判断一个数组是否是递增
- 每天三道冲刺工作--假设你有一个用1001个整数组成的数组
- eclipse转换工作空间的时候需要配置maven等各种配置 现在有一种简单的方法可以不用复杂配置 只配置一次就行
- To_10_r_100_8_4---用一种算法在一个循环的链接表里插入一个节点,但不得穿越链接表
- 每天三道冲刺工作--输入n个整数,输出其中最小的k个。
- 每天三道冲刺工作--比较两个字符串,用 O(n)时间和恒量空间。
- 每天三道冲刺工作--判断俩个链表是否相交。
- 每天三道冲刺工作
- 每天三道冲刺工作--有两个房间,一间房里有三盏灯,另一间房有控制着三盏灯的三个开关
- 百度笔试题:一个已经排序好的很大的数组,现在给它划分成m段,每段长度不定,段长最长为k,然后段内打乱顺序,请设计一个算法对其进行重新排序
- 每天三道冲刺工作--在二元树中找出和为某一值的所有路径
- 每天学习一算法系列(27)(输入两个整数序列。其中一个序列表示栈的push 顺序,判断另一个序列有没有可能是对应的pop 顺序)
- 每天三道冲刺工作--编写反转字符串的程序,要求优化速度、优化空间。
- flag1本人技术小白,自学了数据结构,现在自学算法,给自己立一个flag争取每天学会一个算法,欢迎大家监督打脸!!!!
- 每天三道冲刺工作--根据上排给出十个数,在其下排填出对应的十个数
- To_10_r_100_8_3---颠倒一个链接表的顺序(递归以及非递归方式)
- 每天三道冲刺工作--在排序好的数组中查找和为给定值的两个数字
- 设计一种算法,产生一个不在某文件中的整数