利用单向链表 进行递归的实践

本文探讨了递归的基本原理,并通过修改经典故事进行生动解释。接着,通过汉诺塔问题展示了递归的应用,解析了递归解决复杂问题的思路。随后,文章转向了单向链表,讲解如何利用递归实现链表的增、删、查、显示等操作,代码注释详细阐述了实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

利用单向链表 进行递归的实践

更多干货见博主个人网站:https://blog.zhenglin.work

原理阐述

首先阐述一下什么叫递归呢,就是方法不断的自身调用,直至不满足条件,跳出这个递归循环;举个栗子:从前有座山,山里有座庙,庙里有个小和尚、小和尚让老和尚给他讲故事,然后老和尚开始讲故事:“从前有座山,山里有座庙,庙里有个小和尚、小和尚让老和尚给他讲故事,然后老和尚开始讲故事……” 这就是个递归,而且这是个死循环递归。
那正常的递归是什么样的呢,还是这个故事,稍作改动一下就可以了:从前有座山,山里有座庙,庙里有个5岁的小和尚、小和尚让老和尚给他讲故事,然后老和尚开始讲故事:“从前有座山,山里有座庙,庙里有个4岁的小和尚、小和尚让老和尚给他讲故事,然后老和尚开始讲故事……” 这个直至小和尚到1岁(因为0岁的小和尚还未出生),结束递归。

牛刀小试

public class Hannio {

   private void hanTest(int n,char from,char mid,char to) {
      if(n<1) {
         System.out.println("输入有误");
      }else if(n==1) {
         System.out.println("把第1个箱子从"+from+"移到"+to);
      }else {
         //把n-1个箱子 移动到mid上,to作为过渡
         hanTest(n-1, from, to, mid);
         //把第n个箱子移动到to上
         System.out.println("把第"+n+"个箱子从"+from+"移动到"+to);
         //把n-1个箱子从mid 移动到to上,from作为过渡;
         hanTest(n-1, mid, from, to);
      }
   }
  • 上面代码是简单实现一个汉诺塔程序,汉诺塔可以看作是一个比较典型的递归现象;

首先总结规律,不管多少个箱子移动,只有两种情况:第一种 只有一个箱子,从第一根柱子直接移动到第三根柱子上。 第二种 有两个箱子,先把第一个箱子移动到中间的柱子,第二个箱子移动到第三根柱子上,最后第一个箱子移动到第三根柱子上,完成任务。 那如果有很多箱子呢,比如有n个箱子呢,这个可以把n-1个箱子看成第一个箱子,n是第二个箱子;这样就很好移动了;先用递归方法让n-1个箱子移动到第二根柱子上,然后第n个箱子移动到第三根柱子上。最后再用递归实现剩下的n-1个箱子从第二根柱子上移动到第三根柱子上。

通过上面例子,基本理解了递归的本质了,接下来用递归实现单向链表,实现增、删、查、显示功能。

单向链表的实现

package com.zhengling.work;

//可以吧ListDemo 理解为链表类,初始化只有一个head 节点,其值为null;
public class ListDemo {
    //定义一个内部类,包含存放值的value 和存放下一个元素内存地址的next,可以理解为实现节点特性的类
    class Entry{
        int value;
        Entry next;

        //添加一个可以存放值的构造器
        public Entry(int value) {
            this.value = value;
        }
        //添加节点,如果当前节点的next为空,把节点增加到后面;如果不为空 使用递归,直至找到next为空的位置,加到此处。
        public  void add(Entry entry){
            if(this.next == null){
                this.next = entry;
            }else {
                this.next.add(entry);
            }
        }
        //打印节点中的值,如果当前节点的next不为空,递归打印 直至节点的next为空。
        public void show(){
            System.out.print(value+"------>");
            if(this.next != null){
                this.next.show();
            }
        }

        //查找值 如果当前节点的值和查找的值 相等 返回true
        //如果当前节点没有查找到,当前节点next不为空 采用递归一直往下查找
        //如果递归查询完了 还是没找到 则返回false;
        public boolean search(int i){
            if(this.value == i){
                return true;
            }else{
                if(this.next != null){
                    return this.next.search(i);
                }else {
                    return  false;
                }
            }
        }

        //如果当前节点的下一个节点 里面有要删除的值  进行判断
        //如果下一个节点的下一个节点 不为空 ,下一个节点=下下一个节点;
        //下下一个节点为空的话,自己让下一个节点=null;
        public  void delete(int i){
            if(this.next.value ==i){
                if(this.next.next != null){
                    this.next=this.next.next;
                }else {
                    this.next=null;
                }
            }else{
                this.next.delete(i);
            }
        }

    }

    //初始化一个起始节点。
    Entry head;
    //如果起始节点为空,则把这个节点放到起始节点中。如果起始节点不为空 在head后面调用添加节点的方法;
    public void addValue(int i){
        Entry entry = new Entry(i);
        if(this.head == null){
            this.head = entry;
        }else {
            this.head.add(entry);
        }
    }

    //如果起始节点不为空 就打印节点,起始节点为空了 代表链表是空的 没有打印的必要。
    public void showValue(){
        if(this.head != null){
            this.head.show();
        }
    }

    //查找:如果起始节点中的value 就等于查找的值,返回true;
    //否则 就判断起始节点是否还有下一个节点,如果有,就让head调用查找查找此值的方法;
    //如果没有查找到此值 就返回false;
    public  boolean searchValue(int i){
        if(this.head.value == i){
            return  true;
        }else{
            if(this.head.next != null){
                return  this.head.search(i);
            }else {
                return  false;
            }
        }
    }


    //首先判断 这个链表有没有这个类,如果有再进行删除操作
    //如果起始节点中有这个值,然后起始节点有下一个节点  让起始节点的值等于其next,否则起始节点=null
    //如果起始节点没有这个值,让起始节点调用查找值的方法。
    public void deleteValue(int i){
        if(this.searchValue(i)){
            if(this.head.value == i){
                if(this.head.next != null){
                    this.head =this.head.next;
                }else{
                    this.head = null;
                }
            }else{
                this.head.delete(i);
            }
        }
    }

}
//测试类
class ListDemoTest{
    public static void main(String[] args) {
        ListDemo  ld  = new ListDemo();
        ld.addValue(1);
        ld.addValue(3);
        ld.showValue();
        System.out.println();
        ld.addValue(4);
        ld.showValue();
        System.out.println();
        System.out.println(ld.searchValue(3));
        System.out.println(ld.searchValue(5));
        ld.deleteValue(3);
        ld.showValue();
    }
}

具体实现过程和思路已在代码中 注释。

<think>好的,我现在需要回答用户关于PyTorch是否支持同时安装CPUGPU版本的问题。首先,我应该回顾一下PyTorch的安装机制。根据用户提供的引用资料,安装GPU版本的PyTorch通常需要特定的CUDA版本,并且用户可能需要通过不同的渠道获取对应的whl文件,比如从官网或镜像源下载[^2][^3][^5]。 接下来,我需要理解CPUGPU版本的区别。CPU版本是运行在处理器上的,而GPU版本需要NVIDIA的CUDA支持,利用显卡加速计算。两者在安装包上有不同的依赖项库文件,例如GPU版本会包含CUDA相关的库,而CPU版本则没有这些。 然后,我考虑是否可以在同一个环境中同时安装两个版本。根据经验,Python的包管理通常不允许同一个包的不同版本共存,因为包名称相同(如torch)会导致冲突。用户提供的引用中提到,如果强行安装不同版本的torch,可能会覆盖现有安装,导致不可预期的问题[^4][^5]。例如,如果先安装CPU版本,再安装GPU版本,后者会覆盖前者,反之亦然。 此外,用户可能需要同时使用两种环境的情况,比如在没有GPU的机器上运行CPU代码,而在有GPU的机器上运行加速代码。这时,使用虚拟环境(如conda或venv)分别创建独立的环境可能更合适。每个环境可以安装对应的PyTorch版本,避免冲突[^1][^3]。 还有一个考虑点是PyTorch的设计是否支持同时加载两个版本的库。通常,在运行时,PyTorch会检测可用的CUDA设备,并自动使用GPU版本。如果安装了GPU版本,即使代码中没有显式调用CUDA函数,PyTorch也会优先使用GPU资源。因此,同时安装两个版本不仅技术上不可行,也没有实际必要,因为GPU版本已经包含CPU功能。 最后,我需要总结这些信息,给出清晰的回答,并建议用户使用虚拟环境来管理不同版本的PyTorch,确保项目的兼容性稳定性。</think>PyTorch无法在同一个Python环境中同时安装CPUGPU版本。以下是具体分析及解决方案: ### 一、版本冲突机制 PyTorch的CPUGPU版本通过包名`torch`进行统一管理。安装时会根据后缀(如`cuXXX`表示CUDA版本)决定具体类型: - CPU版本:例如`torch-1.10.0-cp37-cp37m-win_amd64.whl` - GPU版本:例如`torch-1.10.0+cu113-cp37-cp37m-win_amd64.whl` 由于包名相同,后安装的版本会直接覆盖前一个版本[^4]。例如: ```bash # 先安装CPU版本 pip install torch==1.10.0 # 再安装GPU版本会导致覆盖 pip install torch==1.10.0+cu113 ``` ### 二、推荐解决方案 使用虚拟环境隔离不同需求: 1. **Conda环境管理**(推荐): ```bash # 创建GPU环境 conda create -n pytorch_gpu python=3.8 conda activate pytorch_gpu pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cu113 # 创建CPU环境 conda create -n pytorch_cpu python=3.8 conda activate pytorch_cpu pip install torch torchvision ``` 通过`conda activate`切换环境即可[^3] 2. **Docker容器方案**: ```dockerfile # GPU容器 FROM pytorch/pytorch:1.10.0-cuda11.3-cudnn8-runtime # CPU容器 FROM pytorch/pytorch:1.10.0-cpu ``` ### 三、版本兼容性验证 安装后可通过以下代码检测当前环境版本: ```python import torch print(torch.__version__) # 输出如1.10.0+cpu或1.10.0+cu113 print(torch.cuda.is_available()) # GPU版本返回True ``` ### 四、特殊需求处理 若需在GPU版本中使用CPU模式,可直接通过代码指定设备: ```python device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") tensor = torch.randn(3,3).to(device) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值