数据结构 --- [关于递归的理解,使用递归的方式删除链表的元素]
Posted 小智RE0
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构 --- [关于递归的理解,使用递归的方式删除链表的元素]相关的知识,希望对你有一定的参考价值。
递归
使用的方法在自己的方法体内调用自己,
从本质上,就是把原来的问题转化为更小的同一问题。
比如说,要执行方法A,但是方法A中又调用了方法B,方法B中调用了方法C,
在递归的思想中,是方法直接或者间接调用自身.
例如说计算1+2+3+4+5…+100的和;
sum(1) = 1
sum(2) = 2 + sum(1) = 3
sum(3) = 3 + sum(2) = 6
sum(4) = 4 + sum(3) = 10
........
sum(100)= 100 +sum(99)=?
即
sum (n) = n + sum(n-1)
对于递归,要先确定一个递归到底的情况;(一般用if语句先去判断).
比如说,这个整数相加时,递归结束点就是 加到 1 时;
确定了结束点手,再去写递归的方法(表达式),
//整数相加;
public static int sum(int n) {
//递归结束点;;
if(n == 1){
return 1;
}
//递归函数 sum(n-1) + n
return sum(n-1) + n;
}
猴子吃桃问题递归求解
一猴子在吃桃子, 每天吃掉一半 桃子后,又偷偷地 多吃 一个;
结果第6天的时候,就剩下1个桃子了;
那么;
第 4 天桃子总数 ==> 1 个桃子;
第 3 天桃子总数 ==> (第四天的桃子 + 1) X 2 ==> 4
第 2 天桃子总数 ==> (第三天的桃子 + 1) X 2 ==> 10
第 1 天桃子总数 ==> (第二天的桃子 + 1) X 2 ==> 22
......
第 n天 ==> (第 (n-1) 天 + 1 ) ) X2
//吃桃问题;求出第一天的桃子数量;
public static int peach(int day){
//递归到底结束点为第四天;
if(day == 4){
return 1 ;
}
//递归表达式;
return (peach(day+1)+1)*2;
}
这样的方式,如果说要改变吃桃子的天数,还需在递归函数内部去更改递归结束点的判断条件.
若采用反向的方式,将递归结束条件变为倒数第一天时,就剩下一个桃子;
public static int peach2(int day){
//终结点;
if(day==1){
return 1;
}
return (peach2(day-1)+1)*2;
}
斐波那契数递归求解
该数列从第3项开始,每一项都等于前两项之和。
public static int test3(int i){
//终结点;
if(i==0){
return 0;
}
if(i==1||i==2){
return 1;
}
return test3(i-1)+test3(i-2);
}
而对于链表的删除指定内容,也能使用递归的方式实现;
之前创建的自定义链表==>MyLink
现在给它添加一个使用递归,删除指定的数据元素的方法removeValDg
public class MyLink<T> {
/**
* 创建节点内部类
*/
class Node {
//val 数据域;
private T val;
//next 指向下个结点的引用;默认指向空;
private Node next;
//初始化结点;
public Node(T val) {
this.val = val;
this.next = null;
}
//结点数据,输出方法;
@Override
public String toString() {
return this.val.toString();
}
}
//定义链表头;
private Node head;
//链表的实际结点个数;
private int size;
//初始化链表;
public MyLink() {
this.head = null;
this.size = 0;
}
/**
* 判断链表是否为空;
*/
public boolean isEmpty() {
return this.size == 0;
}
/**
* 获取链表的结点个数;
*/
public int getSize() {
return this.size;
}
/**
* 输出链表;
*/
@Override
public String toString() {
StringBuilder sbl = new StringBuilder();
Node cur = head;
//排除头结点不为空的情况下,遍历得到所有结点;
while (cur != null) {
sbl.append(cur + "==>");
cur = cur.next;
}
sbl.append("null");
return sbl.toString();
}
//==========================================================>
//提供给外部访问的递归删除方法;
//(注意,仅可删除首次出现的指定元素)
public Node removeValDg(T val) {
//先判断链表为空的情况;
if (this.isEmpty()) {
return null;
}
//调用内部定义的私有方法处理;
return head = removeValDg(head,val);
}
//递归删除的底层;
private Node removeValDg(Node head, T val) {
//提供终结条件;
if(head==null){
return null;
}
//表达式;
//先把每次要用的头结点脱离链表,存到要操作的结点中;
Node operNode=head;
//将当前头结点的下一位存为新的头结点;
Node newHead=head.next;
//每次让当前操作结点进行比对,若符合,就删除,返回后面的剩余结点;
if(operNode.val==val){
return newHead;
}else{
//若当前头结点不符合,则将预备的新头节点,再次传入调用;最终删除后留下的链表 要接到操作结点的后面;一步步回调;
operNode.next=removeValDg(newHead,val);
return operNode;
}
}
注意终止的条件就是head==null
;那么也就是传入的参数为null时触发;
由于 operNode (当前操作结点)
11 不符合删除的值,则把newHead ()剩余链表的头结点 12)
传参,调用删除方法;
需要注意的是, 以 12
为头结点的链表调用删除方法后 得到的返回链表是连接在之前的操作结点 11 的下一位;
也就是说,
即使刚才脱离链表 11
不符合, 那么也得让他连接回去; 所以返回的是 return operNode;
那么,看看 以 12
为操作结点的链表情况, 此时 12作为operNode (当前操作结点)
需要脱离这段剩余的链表;需要把operNode (当前操作结点) 12
单独拿出来和 4
比较;那么(剩余链表的头结点) newHead
就是13
了;由于operNode (当前操作结点) 12
不符合删除的值; 那么,就把newHead ()剩余链表的头结点 13)
传参,调用删除方法;同样地,以 13
为头结点的链表调用删除方法后 得到的返回链表是连接在之前的操作结点12后面
;而上一次又是连接在11
后面;
以此类推, 以 13
为操作结点的链表情况,… 以 4
为操作结点的链表情况,…;
实际上,这样保证了最终删除元素后,剩余的元素还是保持着连接;
经过测试,这种方式仅仅只能删除首次出现的指定元素;
debug调试发现,该方法在匹配到12作为删除元素后就结束了.
来看看这个删除链表所有指定元素的方式;
直接上方法;
//(提供给外部访问)删除链表的所有指定元素;
public Node removeAllValDg(T val) {
//先判断链表为空的情况;
if (this.isEmpty()) {
return null;
}
//调用内部定义的私有方法处理;
return head = removeAllValDg(head,val);
}
//递归删除所有指定元素方法的底层;
private Node removeAllValDg(Node head, T val) {
//终结方式;
if(head==null){
return null;
}
Node result = removeAllValDg(head.next,val);
//每次让当前操作结点进行比对,若符合,就删除;
if(head.val == val){
return result;
}else{
//否则就让当前操作的结点的下一位调用删除方法;处理的结果链接到当前操作结点后;
head.next=result;
return head;
}
}
在使用debug调试时,注意到由于进入方法后就会执行;
Node result = removeAllValDg(head.next,val);
于是,它就一次一次第进入方法,直到末尾的null处;然后在从14倒着开始和12进行比较;
然后又返回到13;此时13作为链表的头结点;后面连接的是14,14连接的是null;
依次执行;直到最终到达11;
以上是关于数据结构 --- [关于递归的理解,使用递归的方式删除链表的元素]的主要内容,如果未能解决你的问题,请参考以下文章