【数据结构与算法】JavaScript实现单向链表

news2024/11/15 4:51:43

文章目录

      • 一、单向链表简介
      • 二、封装单向链表类
        • 2.0.创建单向链表类
        • 2.1.append(element)
        • 2.2.toString()
        • 2.3.insert(position,element)
        • 2.4.get(position)
        • 2.5.indexOf(element)
        • 2.6.update(position,element)
        • 2.7.removeAt(position)
        • 2.8.其他方法
        • 2.9.完整实现

一、单向链表简介

链表和数组一样,可以用于存储一系列的元素,但是链表和数组的实现机制完全不同。链表的每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(有的语言称为指针或连接)组成。类似于火车头,一节车厢载着乘客(数据),通过节点连接另一节车厢。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • head属性指向链表的第一个节点;
  • 链表中的最后一个节点指向null;
  • 当链表中一个节点也没有的时候,head直接指向null;

数组存在的缺点:

  • 数组的创建通常需要申请一段连续的内存空间(一整块内存),并且大小是固定的。所以当原数组不能满足容量需求时,需要扩容(一般情况下是申请一个更大的数组,比如2倍,然后将原数组中的元素复制过去)。
  • 在数组的开头或中间位置插入数据的成本很高,需要进行大量元素的位移。

链表的优势:

  • 链表中的元素在内存中不必是连续的空间,可以充分利用计算机的内存,实现灵活的内存动态管理
  • 链表不必在创建时就确定大小,并且大小可以无限地延伸下去。
  • 链表在插入和删除数据时,时间复杂度可以达到O(1),相对数组效率高很多。

链表的缺点:

  • 链表访问任何一个位置的元素时,都需要从头开始访问(无法跳过第一个元素访问任何一个元素)。
  • 无法通过下标值直接访问元素,需要从头开始一个个访问,直到找到对应的元素。
  • 虽然可以轻松地到达下一个节点,但是回到前一个节点是很难的。

链表中的常见操作:

  • append(element):向链表尾部添加一个新的项;
  • insert(position,element):向链表的特定位置插入一个新的项;
  • get(position):获取对应位置的元素;
  • indexOf(element):返回元素在链表中的索引。如果链表中没有该元素就返回-1;
  • update(position,element):修改某个位置的元素;
  • removeAt(position):从链表的特定位置移除一项;
  • remove(element):从链表中移除一项;
  • isEmpty():如果链表中不包含任何元素,返回trun,如果链表长度大于0则返回false;
  • size():返回链表包含的元素个数,与数组的length属性类似;
  • toString():由于链表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值;

首先需要弄清楚:下文中的position指的是两个节点之间,并且与index的关系如下图所示:

在这里插入图片描述

position的值一般表示position所指位置的下一个节点。当position的值与index的值相等时,比如position = index = 1,那么它们都表示Node2。

二、封装单向链表类

2.0.创建单向链表类

先创建单向链表类Linklist,并添加基本属性,再实现单向链表的常用方法:

    // 封装单向链表类
    function LinkList(){
      // 封装一个内部类:节点类
      function Node(data){
        this.data = data;
        this.next = null;
      }

      // 属性
      // 属性head指向链表的第一个节点
      this.head = null;
      this.length = 0;
      }
2.1.append(element)

代码实现:

      // 一.实现append方法
      LinkList.prototype.append = data => {
        //1.创建新节点
        let newNode = new Node(data)

        //2.添加新节点
        //情况1:只有一个节点时候
        if(this.length == 0){
          this.head = newNode
        //情况2:节点数大于1,在链表的最后添加新节点  
        }else {              
          //让变量current指向第一个节点
          let current = this.head
          //当current.next(下一个节点不为空)不为空时,一直循环,直到current指向最后一个节点
          while (current.next){
            current = current.next
          }
          // 最后节点的next指向新的节点
          current.next = newNode
        }
        //3.添加完新结点之后length+1
        this.length += 1
      }

过程详解:

  • 首先让current指向第一个节点:

在这里插入图片描述

  • 通过while循环使current指向最后一个节点,最后通过current.next = newNode,让最后一个节点指向新节点newNode:

在这里插入图片描述

测试代码:

    //测试代码
    //1.创建LinkList
    let list = new LinkList()
    
    //2.测试append方法
    list.append('aaa')
    list.append('bbb')
    list.append('ccc')
    console.log(list);  

测试结果:

在这里插入图片描述

2.2.toString()

代码实现:

      // 实现toString方法
      LinkList.prototype.toString = () => {
        // 1.定义变量
        let current = this.head
        let listString = ""

        // 2.循环获取一个个的节点
        while(current){ 
          listString += current.data + " "
          current = current.next//千万不要忘了拼接完一个节点数据之后,让current指向下一个节点
        }
        return  listString
      }

测试代码:

    //测试代码
    //1.创建LinkList
    let list = new LinkList()
    
    //2.插入数据
    list.append('aaa')
    list.append('bbb')
    list.append('ccc')
    
    //3.测试toString方法
    console.log(list.toString());

测试结果:

在这里插入图片描述

2.3.insert(position,element)

代码实现:

      // 实现insert方法
      LinkList.prototype.insert = (position, data) => {
      //理解positon的含义:position=0表示新界点插入后要成为第1个节点,position=2表示新界点插入后要成为第3个节点
        //1.对position进行越界判断:要求传入的position不能是负数且不能超过LinkList的length
        if(position < 0 || position > this.length){
          return false
        }
        //2.根据data创建newNode
        let newNode = new Node(data)

        //3.插入新节点
        //情况1:插入位置position=0
        if(position == 0){
          // 让新节点指向第一个节点
          newNode.next = this.head
          // 让head指向新节点
          this.head = newNode
        //情况2:插入位置position>0(该情况包含position=length)
        } else{
          let index = 0
          let previous = null
          let current = this.head
          //步骤1:通过while循环使变量current指向position位置的后一个节点(注意while循环的写法)
          while(index++ < position){
          //步骤2:在current指向下一个节点之前,让previous指向current当前指向的节点
            previous = current
            current = current.next
          }
          // 步骤3:通过变量current(此时current已经指向position位置的后一个节点),使newNode指向position位置的后一个节点
          newNode.next = current
          //步骤4:通过变量previous,使position位置的前一个节点指向newNode
          previous.next = newNode
          /*
            启示:
            1.我们无法直接操作链表中的节点,但是可以通过变量指向这些节点,以此间接地操作节点(替身使者);
            比如current指向节点3,想要节点3指向节点4只需要:current.next = 4即可。
            2.两个节点间是双向的,想要节点2的前一个节点为节点1,可以通过:1.next=2,来实现;
          */
        }
        //4.新节点插入后要length+1
        this.length += 1;

        return true
      }

过程详解:

inset方法实现的过程:根据插入节点位置的不同可分为多种情况:

  • 情况1:position = 0

通过: newNode.next = this.head,建立连接1;

通过: this.head = newNode,建立连接2;(不能先建立连接2,否则this.head不再指向Node1)

在这里插入图片描述

  • 情况2:position > 0

首先定义两个变量previous和curent分别指向需要插入位置pos = X的前一个节点和后一个节点;

然后,通过:newNode.next = current,改变指向3;

最后,通过:previous.next = newNode,改变指向4;

在这里插入图片描述

  • 情况2的特殊情形:position = length

情况2也包含了pos = length的情况,该情况下current和newNode.next都指向null;建立连接3和连接4的方式与情况2相同。

在这里插入图片描述

测试代码:

    //测试代码
    //1.创建LinkList
    let list = new LinkList()
    
    //2.插入数据
    list.append('aaa')
    list.append('bbb')
    list.append('ccc')
    
    //3.测试insert方法
    list.insert(0, '在链表最前面插入节点');
    list.insert(2, '在链表中第二个节点后插入节点');
    list.insert(5, '在链表最后插入节点');
    alert(list);
    console.log(list);

测试结果:
在这里插入图片描述

在这里插入图片描述

2.4.get(position)

代码实现:

      //实现get方法
      LinkList.prototype.get = (position) => {
        //1.越界判断
        // 当position = length时,取到的是null所以0 =< position < length
        if(position < 0 || position >= this.length){
          return null
        }
        //2.获取指定的positon位置的后一个节点的data
        //同样使用一个变量间接操作节点
        let current = this.head
        let index = 0
        while(index++ < position){
          current = current.next
        }
        return current.data
      }

过程详解:

get方法的实现过程:以获取position = 2为例,如下图所示:

  • 首先使current指向第一个节点,此时index=0;

在这里插入图片描述

  • 通过while循环使current循环指向下一个节点,注意循环终止的条件index++ < position,即当index=position时停止循环,此时循环了1次,current指向第二个节点(Node2),最后通过current.data返回Node2节点的数据;

在这里插入图片描述

测试代码:

	//测试代码
    //1.创建LinkList
    let list = new LinkList()
    
    //2.插入数据
    list.append('aaa')
    list.append('bbb')
    list.append('ccc')	

	//3.测试get方法
    console.log(list.get(0));
    console.log(list.get(1));

测试结果:

在这里插入图片描述

2.5.indexOf(element)

代码实现:

      //实现indexOf方法
      LinkList.prototype.indexOf = data => {
        //1.定义变量
        let current = this.head
        let index = 0

        //2.开始查找:只要current不指向null就一直循环
        while(current){
          if(current.data == data){
            return index
          }
          current = current.next
          index += 1
        } 

        //3.遍历完链表没有找到,返回-1
        return -1
      }

过程详解:

indexOf方法的实现过程:

  • 使用变量current记录当前指向的节点,使用变量index记录当前节点的索引值(注意index = node数-1):

在这里插入图片描述

测试代码:

	//测试代码
    //1.创建LinkList
    let list = new LinkList()
    
    //2.插入数据
    list.append('aaa')
    list.append('bbb')
    list.append('ccc')	
    
    //3.测试indexOf方法
    console.log(list.indexOf('aaa'));
    console.log(list.indexOf('ccc'));

测试结果:

在这里插入图片描述

2.6.update(position,element)

代码实现:

      //实现update方法
      LinkList.prototype.update = (position, newData) => {
        //1.越界判断
        //因为被修改的节点不能为null,所以position不能等于length
        if(position < 0 || position >= this.length){
          return false
        }
        //2.查找正确的节点
        let current = this.head
        let index = 0
        while(index++ < position){
          current = current.next
        }
        //3.将position位置的后一个节点的data修改成newData
        current.data = newData
        //返回true表示修改成功
        return true
      }

测试代码:

	//测试代码
    //1.创建LinkList
    let list = new LinkList()
    
    //2.插入数据
    list.append('aaa')
    list.append('bbb')
    list.append('ccc')	
    
    //3.测试update方法
    list.update(0, '修改第一个节点')
    list.update(1, '修改第二个节点')
    console.log(list);
    console.log(list.update(3, '能修改么'));

测试结果:

在这里插入图片描述

2.7.removeAt(position)

代码实现:

      //实现removeAt方法
      LinkList.prototype.removeAt = position => {
        //1.越界判断
        if (position < 0 || position >= this.length) {//position不能为length
          return null
        }
        //2.删除元素
        //情况1:position = 0时(删除第一个节点)
        let current = this.head
        if (position ==0 ) {
        //情况2:position > 0时
          this.head = this.head.next
        }else{
          let index = 0
          let previous = null
          while (index++ < position) {
            previous = current
            current = current.next
          }
          //循环结束后,current指向position后一个节点,previous指向current前一个节点
          //再使前一个节点的next指向current的next即可
          previous.next = current.next
        }
        //3,length-1
        this.length -= 1

        //返回被删除节点的data,为此current定义在最上面
        return current.data
      }

过程详解:

removeAt方法的实现过程:删除节点时存在多种情况:

  • 情况1:position = 0,即移除第一个节点(Node1)。

通过:this.head = this.head.next,改变指向1即可;

虽然Node1的next仍指向Node2,但是没有引用指向Node1,则Node1会被垃圾回收器自动回收,所以不用处理Node1指向Node2的引用next。

在这里插入图片描述

  • 情况2:positon > 0,比如pos = 2即移除第三个节点(Node3)。

**注意:**position = length时position后一个节点为null不能删除,因此position != length;

首先,定义两个变量previous和curent分别指向需要删除位置pos = x的前一个节点和后一个节点;

然后,通过:previous.next = current.next,改变指向1即可;

随后,没有引用指向Node3,Node3就会被自动回收,至此成功删除Node3 。

在这里插入图片描述

测试代码:

    //测试代码
    //1.创建LinkList
    let list = new LinkList()
    
    //2.插入数据
    list.append('aaa')
    list.append('bbb')
    list.append('ccc')
  
  //3.测试removeAt方法
    console.log(list.removeAt(0));
    console.log(list.removeAt(0));
    console.log(list);

测试结果:

在这里插入图片描述

2.8.其他方法

其他方法包括:remove(element)、isEmpty()、size()

代码实现:

/*-------------其他方法的实现--------------*/
      //一.实现remove方法
      LinkList.prototype.remove = (data) => {
        //1.获取data在列表中的位置
        let position = this.indexOf(data)
        //2.根据位置信息,删除结点
        return this.removeAt(position)
      }

      //二.实现isEmpty方法
      LinkList.prototype.isEmpty = () => {
        return this.length == 0
      }

      //三.实现size方法
      LinkList.prototype.size = () => {
        return this.length
      }

测试代码:

    //测试代码
    //1.创建LinkList
    let list = new LinkList()
    
    //2.插入数据
    list.append('aaa')
    list.append('bbb')
    list.append('ccc')

/*---------------其他方法测试----------------*/
  	//remove方法
  	console.log(list.remove('aaa'));
  	console.log(list);
  	//isEmpty方法
  	console.log(list.isEmpty());
  	//size方法
  	console.log(list.size());

测试结果:

在这里插入图片描述

2.9.完整实现
    // 封装链表类
    function LinkList(){
      // 封装一个内部类:节点类
      function Node(data){
        this.data = data;
        this.next = null;
      }

      // 属性
      // 属性head指向链表的第一个节点
      this.head = null;
      this.length = 0;

      // 一.实现append方法
      LinkList.prototype.append = data => {
        //1.创建新节点
        let newNode = new Node(data)

        //2.添加新节点
        //情况1:只有一个节点时候
        if(this.length == 0){
          this.head = newNode
        //情况2:节点数大于1,在链表的最后添加新节点  
        }else {              
          //让变量current指向第一个节点
          let current = this.head
          //当current.next(下一个节点不为空)不为空时,一直循环,直到current指向最后一个节点
          while (current.next){
            current = current.next
          }
          // 最后节点的next指向新的节点
          current.next = newNode
        }
        //3.添加完新结点之后length+1
        this.length += 1
      }

      // 二.实现toString方法
      LinkList.prototype.toString = () => {
        // 1.定义变量
        let current = this.head
        let listString = ""

        // 2.循环获取一个个的节点
        while(current){ 
          listString += current.data + " "
          current = current.next//千万不要忘了拼接完一个节点数据之后,让current指向下一个节点
        }
        return  listString
      }

      // 三.实现insert方法
      LinkList.prototype.insert = (position, data) => {
      //理解positon的含义:position=0表示新界点插入后要成为第1个节点,position=2表示新界点插入后要成为第3个节点
        //1.对position进行越界判断:要求传入的position不能是负数且不能超过LinkList的length
        if(position < 0 || position > this.length){
          return false
        }
        //2.根据data创建newNode
        let newNode = new Node(data)

        //3.插入新节点
        //情况1:插入位置position=0
        if(position == 0){
          // 让新节点指向第一个节点
          newNode.next = this.head
          // 让head指向新节点
          this.head = newNode
        //情况2:插入位置position>0(该情况包含position=length)
        } else{
          let index = 0
          let previous = null
          let current = this.head
          //步骤1:通过while循环使变量current指向position位置的后一个节点(注意while循环的写法)
          while(index++ < position){
          //步骤2:在current指向下一个节点之前,让previous指向current当前指向的节点
            previous = current
            current = current.next
          }
          // 步骤3:通过变量current(此时current已经指向position位置的后一个节点),使newNode指向position位置的后一个节点
          newNode.next = current
          //步骤4:通过变量previous,使position位置的前一个节点指向newNode
          previous.next = newNode
          
		//我们无法直接操作链表中的节点,但是可以通过变量指向这些节点,以此间接地操作节点;
        }
        //4.新节点插入后要length+1
        this.length += 1;

        return true
      }

      //四.实现get方法
      LinkList.prototype.get = (position) => {
        //1.越界判断
        // 当position = length时,取到的是null所以0 =< position < length
        if(position < 0 || position >= this.length){
          return null
        }
        //2.获取指定的positon位置的后一个节点的data
        //同样使用一个变量间接操作节点
        let current = this.head
        let index = 0
        while(index++ < position){
          current = current.next
        }
        return current.data
      }

      //五.实现indexOf方法
      LinkList.prototype.indexOf = data => {
        //1.定义变量
        let current = this.head
        let index = 0

        //2.开始查找:只要current不指向null就一直循环
        while(current){
          if(current.data == data){
            return index
          }
          current = current.next
          index += 1
        } 

        //3.遍历完链表没有找到,返回-1
        return -1
      }

      //六.实现update方法
      LinkList.prototype.update = (position, newData) => {
        //1.越界判断
        //因为被修改的节点不能为null,所以position不能等于length
        if(position < 0 || position >= this.length){
          return false
        }
        //2.查找正确的节点
        let current = this.head
        let index = 0
        while(index++ < position){
          current = current.next
        }
        //3.将position位置的后一个节点的data修改成newData
        current.data = newData
        //返回true表示修改成功
        return true
      }

      //七.实现removeAt方法
      LinkList.prototype.removeAt = position => {
        //1.越界判断
        if (position < 0 || position >= this.length) {
          return null
        }
        //2.删除元素
        //情况1:position = 0时(删除第一个节点)
        let current = this.head
        if (position ==0 ) {
        //情况2:position > 0时
          this.head = this.head.next
        }else{
          let index = 0
          let previous = null
          while (index++ < position) {
            previous = current
            current = current.next
          }
          //循环结束后,current指向position后一个节点,previous指向current前一个节点
          //再使前一个节点的next指向current的next即可
          previous.next = current.next
        }
        //3,length-1
        this.length -= 1

        //返回被删除节点的data,为此current定义在最上面
        return current.data
      }

/*-------------其他方法的实现--------------*/
      //八.实现remove方法
      LinkList.prototype.remove = (data) => {
        //1.获取data在列表中的位置
        let position = this.indexOf(data)
        //2.根据位置信息,删除结点
        return this.removeAt(position)
      }

      //九.实现isEmpty方法
      LinkList.prototype.isEmpty = () => {
        return this.length == 0
      }

      //十.实现size方法
      LinkList.prototype.size = () => {
        return this.length
      }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1201585.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

租用服务器带宽类型应用

服务器带宽类型多样&#xff0c;以满足不同行业的需求。本文将介绍香港常见的服务器带宽类型及其应用领域。 1. 共享带宽 共享带宽是指多个用户共同使用同一台服务器的带宽资源。这种带宽类型适用于小型企业或个人网站&#xff0c;因为其成本较低。由于多个用户共享带宽资源&…

【C语言】解开指针|编址内存解引用指针产量|

&#x1f308;write in front :&#x1f50d;个人主页 &#xff1a; &#x1f60a;啊森要自信的主页 ✨ 作者寄语 &#x1f308;&#xff1a; 小菜鸟的力量不在于它的体型&#xff0c;而在于它内心的勇气和无限的潜能&#xff0c;只要你有决心&#xff0c;就没有什么事情是不可…

Linux操作系统使用及C高级编程-D3Linux shell命令(权限、输入输出)

Shell 是一种应用程序&#xff0c;用以完成用户与内核之间的交互 一个功能强大的编程语言&#xff08;C语言&#xff09; 一个解释执行的脚本语言&#xff0c;不需要编译&#xff0c;写完直接执行 目前Linux 乌班图的Shell默认是bash 查看当前提供的Shell&#xff1a;cat /…

Vue.js中的路由(router)和Vue Router的作用?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

2.8 CE修改器:寻找共享代码

本关我们将学习共享代码&#xff0c;在C语言中角色属性都是以结构体的方式进行存储的&#xff0c;而结构体所存储的信息都是连续性的&#xff0c;这一关我们将会解释如何处理游戏中的共用代码&#xff0c;这种代码是通用在除了自己以外的其他同类型对像上的常常你在修改游戏的时…

在Vue.js中,什么是mixins?它们的作用是什么?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

Linux基础环境开发工具的使用(三):gdb调试器

Linux基础环境开发工具的使用[三]:gdb调试器 一.调试命令的应用场景1.为什么要介绍调试命令的应用场景呢?2.调试命令的应用场景1.找到问题1.不借助调试2.调试 2.解决问题1.不借助调试2.借助调试 二.调试命令1.gdb使用的前置说明2.基础指令3.断点相关指令4.范围查找相关操作5.局…

通信原理板块——线性分组码之循环码

微信公众号上线&#xff0c;搜索公众号小灰灰的FPGA,关注可获取相关源码&#xff0c;定期更新有关FPGA的项目以及开源项目源码&#xff0c;包括但不限于各类检测芯片驱动、低速接口驱动、高速接口驱动、数据信号处理、图像处理以及AXI总线等 1、循环码原理 循环码(cycle code)…

C# Onnx LSTR 基于Transformer的端到端实时车道线检测

目录 效果 模型信息 项目 代码 下载 效果 模型信息 lstr_360x640.onnx Inputs ------------------------- name&#xff1a;input_rgb tensor&#xff1a;Float[1, 3, 360, 640] name&#xff1a;input_mask tensor&#xff1a;Float[1, 1, 360, 640] -----------------…

罕见!阿里云全系产品崩了。。

作者&#xff1a;苍何&#xff0c;前大厂高级 Java 工程师&#xff0c;阿里云专家博主&#xff0c;CSDN 2023 年 实力新星&#xff0c;土木转码&#xff0c;现任部门技术 leader&#xff0c;专注于互联网技术分享&#xff0c;职场经验分享。 &#x1f525;热门文章推荐&#xf…

安全认证框架Shrio学习,入门到深度学习,SpringBoot整合Shiro小案例,含代码

权限概述 什么是权限 什么是权限 权限管理&#xff0c;一般指根据系统设置的安全策略或者安全规则&#xff0c;用户可以访问而且只能访问自己被授权的资源&#xff0c;不多不少。权限管理几乎出现在任何系统里面&#xff0c;只要有用户和密码的系统。 权限管理再系统中一般分…

两个序列(数论)

两个序列 Problem:B Time Limit:1000ms Memory Limit:65535K Description Gugu 有两个长度无限长的序列A,BA0a^0/0!,A1a^1/1!,A2a^2/2!,A3a^3/3!…. B00, B1b^1/1!,B20,B3b^3/3!,B40, B5b^5/5! … Douge 看到这道这两个序列很觉得很麻烦&#xff0c;所以他想到一个好点子&…

【LeetCode刷题-二分查找】--704.二分查找

704.二分查找 class Solution {public int search(int[] nums, int target) {if(nums.length 0){return -1;}int left 0,right nums.length - 1;while(left < right){int mid (right - left) / 2 left;if(nums[mid] target){return mid;}else if(nums[mid] < targe…

模拟信号数字化--低通抽样与带通抽样

模拟信号数字化 本文主要涉及模拟信号数字化的基本概念&#xff0c;以及对低通抽样与带通抽样以及其公式推导的详细介绍。关于通信原理还有其他文章可参考&#xff1a; 1、信息量、码元、比特、码元速率、信息速率详细解析——实例分析 2、模拟系统的AM信号的调制与频域分析 3、…

HCIE-Rainbow迁移工具

Rainbow迁移工具 Rainbow迁移工具支持p2v&#xff08;物理机到虚拟机的迁移&#xff09; v2v&#xff08;虚拟机到虚拟机的迁移&#xff09; Rainbow业务上云迁移&#xff1a; Rainbow迁移到公有云&#xff08;利用公有云SMS服务&#xff0c;付费&#xff09; Rainbow迁移到公…

【python】sys-path和模块搜索路径

我们在导入一个模块的时候&#xff0c;比如说&#xff1a; import math它必然是有搜索路径的&#xff0c;那到底是在哪个目录下面找呢&#xff1f;Python解释器去哪里找这个文件呢&#xff1f;只有找到这个文件才能读取、装载运行该模块文件。 它一般按照如下路径寻找模块文件…

matlab simulink PSO算法优化simulink的PID参数

1、内容简介 略 13-可以交流、咨询、答疑 PSO算法优化simulink的PID参数 2、内容说明 标准的PSO算法优化simulink的PID参数 PSO、粒子群算法、simulink参数优化 3、仿真分析 4、参考论文 略 链接&#xff1a;https://pan.baidu.com/s/1yQ1yDfk-_Qnq7tGpa23L7g 提取码&…

企业知识库建设指南:实用经验分享

企业知识库建设是提升内部协作和客户支持效率的重要举措。一个完善的知识库可以帮助企业集中管理和传播知识&#xff0c;提供便捷的自助服务和丰富的编辑工具&#xff0c;从而提升用户体验和品牌好感度。接下来就分享一些经验&#xff0c;关于该如何构建一个高效的企业知识库。…

27 _ 递归树:如何借助树来求解递归算法的时间复杂度?

我们都知道,递归代码的时间复杂度分析起来很麻烦。有一个巧妙的方式是借助递归树来分析递归算法的时间复杂度。 递归树与时间复杂度分析 我们前面讲过,递归的思想就是,将大问题分解为小问题来求解,然后再将小问题分解为小小问题。这样一层一层地分解,直到问题的数据规模…

不可思议,才一周,阅读量就突破千万了

这段时间&#xff0c;我发布的文章阅读量看上去还算可以&#xff0c;但我知道&#xff0c;这并不是终点&#xff0c;而是起点。我深知&#xff0c;写作的道路永无止境&#xff0c;只有不断努力&#xff0c;才能在文字的海洋中游得更远。 在这条道路上&#xff0c;我始终坚持用心…