最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 如何设计一个基于对象的链表?

    正文概述 掘金(时樾同学)   2021-01-05   359

    前言

    链表

    单向链表是最普通的链表结构了,它是由多个节点组成类似链装的数据结构,样子大概如下:

    如何设计一个基于对象的链表?

    链表会有一个特殊的节点叫“head”,它存放第一个节点。每个节点会包含一个元素和一个指向下一个元素的“指针(next)”;最后一个节点的next会指向“空(null,undefind)”。

    在js中,虽然有“链表”概念,但是它却没有提供内置创建“链表”的构造函数,不像一些后端语言有内置的构造函数。那么在js中,想要用“链表”存储数据,只能自己手动实现一些构造函数和方法。

    设计一个链表它应该包含以下这些东西:

    • 链表构造函数

    • 节点构造函数

    • push方法(添加一个节点到链表最后)

    • insert方法 (添加一个元素到指定的位置)

    • removeAt方法 (删除一个指定位置的节点)

    • removeItem方法(删除一个指定元素的节点)

    • getElementAt方法 (获取一个指定位置的节点)

    • indexOf方法(获取一个元素的节点位置)

    • show方法 (展示所有链表数据)

    • size方法 (链表节点个数)

    • getHead方法 (获取头节点)

    • isEmpty方法 (判断列表是否为空)

    • 可能还有其他的,暂时没想到

    需求弄明白了,接下来就一步一步的实现一个链表结构。(为了方便理解,不会对代码进行封装,虽然有比较多类似代码)

    节点构造函数

    一个普通的节点,只需要一个元素(element)和 一个指针(next)就行,无需其他多余的东西。

    class Node {
      constructor(elememt){
        this.elememt = elememt
        this.next = undefined
      }
    }
    

    链表构造函数

    链表构造函数需要一个头节点(head)和保存节点个数的count上面的那些方法

    
    class LinkedList {
      constructor(){
        this.count = 0
        this.head = new Node('head')
      }
    }
    
    

    创建好结构后,就可以实现操作链表的方法了,现在链表的样子如下:

    如何设计一个基于对象的链表?

    push方法

    实现该方法前,先通过一张图了解一下它的添加逻辑。

    如何设计一个基于对象的链表?

    push方法是在链表最后添加一个节点,假设,我们要添加一个“张三”,那么就要通过Node构造函数创建一个叫“张三”的节点,然后,找到该链表的最后一个节点,断开它next指向undefined的链接,并将它指向新节点(如上图)。

    逻辑清楚,那么实现起来就不费力了。

    
    push(ele){
      // 创建新节点
      let newEle = new Node(ele)
      let current = this.head
      // 找到最后的那个节点
      while(current.next !== undefined){
        current = current.next
      }
      // 改变最后一个节点的指针指向
      current.next = newEle
      // 节点个数加1
      this.count++
    }
    
    

    insert方法

    如何设计一个基于对象的链表?

    假设,我们要在第一个(index=0)的位置添加一个叫"李四"的节点,那么我们就要找index的前一个节点,那么如上图,index的前一个节点就是head,我们要找到它并将它的next指针指向新节点,还要将新元素的指针指向index节点

    
    insert(ele, index){
    	// 越标处理
        if(index>=0 && index <= this.count){
          // 创建新元素
          let node = new Node(ele)
          let current=this.head , pre
          
          for (let i = 0; i <= index; i++) {
          	// 保存 index 的前一个节点
            pre = current
            // index的目标节点
            current =current.next
          }
          // index 的前一个节点的指针指向新节点
          pre.next = node
          // 新节点指针指向index的目标节点
          node.next = current
          // 节点加1
          this.count++
        }else{
          console.error('越标')
        }
      }
    
    

    removeAt方法

    如何设计一个基于对象的链表?

    假设,我们要删除第一项(index === 0),那么就要找到它(index=0)的前一个节点,并将它的指针指向index=0下一个节点,也就是它的next,最后将删除的节点指针重置为undefined

    
     removeAt(index){
     	// 越标处理
        if(index >= 0 && index < this.count){
          let current=this.head , pre
          for (let i = 0; i <= index; i++) {
          	// index前一项
            pre = current
            // index项
            current =current.next
          }
          // 改变index前一项指针指向,让它跳过index项,指向到index下一项
          pre.next = current.next
          current.next = undefined
          // 节点减一
          this.count--
        }else{
          console.error('删除失败,越标')
        }
      }
    
    

    removeItem方法

    这方法是通过元素删除,逻辑跟上面差不多,就不上图了。

    
    removeItem(ele){
      let current = this.head,pre
      try {
        while(current.elememt !== ele){
          pre = current
          current = current.next
        }
      } catch (error) {
        console.error('删除失败,没有该元素')
      }
      pre.next = current.next
      this.count--
    }
    
    

    getElementAt方法

    该方法主要是通过index找到对应的节点,找到就返回该节点,没找到就返回undefined

    
     getElement(index){
        if(index >= 0 && index < this.count){
          let node = this.head
          for (let i = 0; i <= index; i++) {
            node = node.next        
          }
          return node
        }
        return undefined
      }
    
    

    indexOf方法

    该方法主要是通过元素找到下标,找到就返回下标,没找到就返回-1

    
    indexOf(ele){
      let current = this.head
      for (let i = 0; i < this.count; i++) {
        if(ele === current.elememt){
          return i
        }
        current = current.next
      }
      return -1
    }
    
    

    size、getHead、isEmpty、show方法

    size方法获取节点的个数,getHead方法获取链表的头节点,isEmpty方法判断链表是否为空,show方法展示链表元素。

    
     size(){
        return this.count
      }
    
      getHead(){
        return this.head
      }
    
      isEmpty(){
        return this.count === 0
      }
    
      show(){
        if(this.count > 0){
          let current = this.head
          while(current.next !== undefined){
          	// 这里只是做了打印展示
            console.log(current.next.elememt)
            current = current.next
          }
        }
      }
    
    

    测试

    
      let personLink = new LinkedList()
      
      personLink.push('张三')
      
      personLink.push('李四')
      
      personLink.insert('王五', 1)
      
      personLink.removeAt(1)
      
      console.log(personLink.getHead())
      
      personLink.show()
      
      personLink.removeAt(1)
      
      console.log(personLink.indexOf('王五'))
    
    

    完整代码

    
    class Node {
      constructor(elememt){
        this.elememt = elememt
        this.next = undefined
      }
    }
    
    class LinkedList {
      constructor(){
        this.count = 0
        this.head = new Node('head')
      }
    
      push(ele){
        let newEle = new Node(ele)
        let current = this.head
        while(current.next !== undefined){
          current = current.next
        }
        current.next = newEle
        this.count++
      }
     
      size(){
        return this.count
      }
    
      getHead(){
        return this.head
      }
    
      isEmpty(){
        return this.count === 0
      }
    
      show(){
        if(this.count > 0){
          let current = this.head
          while(current.next !== undefined){
            console.log(current.next.elememt)
            current = current.next
          }
        }
      }
    
      removeAt(index){
        if(index >= 0 && index < this.count){
          let current=this.head , pre
          for (let i = 0; i <= index; i++) {
            pre = current
            current =current.next
          }
          pre.next = current.next
          current.next = undefined
          this.count--
        }else{
          console.error('删除失败,越标')
        }
      }
    
      removeItem(ele){
        let current = this.head,pre
        try {
          while(current.elememt !== ele){
            pre = current
            current = current.next
          }
        } catch (error) {
          console.error('删除失败,没有该元素')
        }
        pre.next = current.next
        this.count--
      }
    
      getElement(index){
        if(index >= 0 && index < this.count){
          let node = this.head
          for (let i = 0; i <= index; i++) {
            node = node.next        
          }
          return node
        }
        return undefined
      }
    
      insert(ele, index){
        if(index>=0 && index <= this.count){
          let node = new Node(ele)
          let current=this.head , pre
          for (let i = 0; i <= index; i++) {
            pre = current
            current =current.next
          }
          pre.next = node
          node.next = current
          this.count++
        }else{
          console.error('越标')
        }
      }
    
      indexOf(ele){
        let current = this.head
        for (let i = 0; i < this.count; i++) {
          if(ele === current.elememt){
            return i
          }
          current = current.next
        }
        return -1
      }
    
    }
    
    let personLink = new LinkedList()
    personLink.push('张三')
    personLink.push('李四')
    personLink.insert('王五', 1)
    personLink.removeAt(1)
    console.log(personLink.getHead())
    personLink.show()
    personLink.removeAt(1)
    console.log(personLink.indexOf('王五'))
    
    

    起源地下载网 » 如何设计一个基于对象的链表?

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元