一些算法题的总结:
1.链表的反转:
首先准备一个Node类实现链表功能:
class Node{
datatype data;
Node next;
public Node(datatype data,Node next){
this.data = data;
this.next = next;
}
}
(1).循环法:
class Solution{
public void reverseLinkList(Node head){
Node first = null;
Node pre = head.next;//pre指针开始指向第一个节点
Node curr = pre.next;
while(curr != null){
first = head.next;
head.next = curr;
pre.next = curr.next;
curr.next = first;
curr = pre.next;
}
}
}
1.使用
循环法
时我使用了三个指针进行操作:
first
指针:始终指向第一个元素,也就是新插进来的头结点。
pre
指针:pre指针会随着前面新结点的插入从而自动向前移动。
curr
指针:curr指针始终在pre指针的前一位,其表示当前循环待操作的元素。
2.反转链表的三个核心操作:
Ⅰ.由于新的头结点是当前正在操作的元素(即curr所指),所以让头指针指向当前结点。
Ⅱ.由于当前节点的移动缺失,所以让curr的前一个结点(即pre所指)指向原curr的下一个结点。
Ⅲ.由于当前结点curr称为新的头结点,所以其next指针域应指向原头结点(即first所指)。
以上操作完毕后,即反转了一个结点,当当前结点移动到原链表的最后一个结点的下一个结点时,反转操作完成,所以循环条件应采用curr != null
即可完成链表反转。
(2).递归法:
class Solution{
//该程序是主程序
public void reverseLinkList(Node head){
if(head==null||head.next==null){
return;
}
reverseNode(head.next,head);
}
//该程序是递归程序
public Node reverseNode(Node curr,Node head){
if(curr.next==null){
head.next = curr;
return curr;
}
Node newNode = reverseNode(curr.next,head);
newNode.next = curr;
curr.next = null;
return curr;
}
}
对于递归法而言,以上算法所用到的
回溯思想
值得学习。首先,对于一个递归而言,必不可少的就是一个结束递归的条件,否则会产生栈溢出异常。写所有递归操作的第一步一定需要书写结束条件。
本题的思路是,一个指针随着递归先遍历到最后一个结点,随后返回需要操作的那一个结点,并将其赋值给新的头结点。所以递归结束条件应该是当前待操作结点(curr)是链表最后一个结点时,即结束递归。对本题而言,最后一个结点同样需要被赋值给头结点,在结束条件中增添即可。
举个栗子:head->1->2->3->4->5->NULL
类比盗梦空间:
(第五层梦境):
&当curr指向5的时候,进入结束条件,结束条件中将curr赋值给新的头结点。并且返回给第四层梦境。
(第四层梦境):
&该层梦境中curr指向4所对应的结点,从第五层返回的5对应结点定义需要一个变量存储下来。而后将当前层数4所对应结点赋值给5的下一个结点。并将4所对应结点的后面断掉。最后返回当前层数的结点4即可。
(第三层梦境):
&该层梦境中curr指向3所对应结点,同将curr赋值给上一层返回下来的4所对应结点的下一个结点。清空3后面的结点,将curr返回给下一层梦境即可。
(第二层,第一层梦境同理)
递归法拥有的
回溯思想
是循环法所做不到的,当然,如果循环法想做到,需借助诸如栈数据结构的帮助。