请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

链表的递归实现

在课程github里没找到链表的递归实现代码,所以自己实现了一遍。希望后面同学自己实现的时候可以参考。

如果代码有问题,欢迎评论指正。

package com.imooc.linkedlist;

public class LinkedListWithRecursion<E> {

  private class Node<E> {
    public E data;
    public Node next;

    public Node(E data, Node next) {
      this.data = data;
      this.next = next;
    }

    public Node(E data) {
      this(data, null);
    }

    public Node() {
      this(null, null);
    }

    @Override
    public String toString() {
      return data.toString();
    }
  }

  private Node dummyHead;

  private int size;

  public LinkedListWithRecursion() {
    dummyHead = new Node(null, null);
    size = 0;
  }

  /**
   * @return
   */
  public int getSize() {
    return size;
  }

  /**
   * @return
   */
  public boolean isEmpty() {
    return size == 0;
  }

  /**
   * 向索引指定位置添加元素
   *
   * @param e
   * @param index
   */
  public void add(E e, int index) {
    if (index < 0 || index > size) {
      throw new IllegalArgumentException("LinkedList.add failed, index is illegal!");
    }
    Node<E> previous = dummyHead;
    addWithRecursiton(e, previous, 0, index);
    size++;
  }

  /**
   * 
   * @param e  待添加的元素
   * @param previous 指定插入索引的前一节点
   * @param current 当前递归索引
   * @param index 指定添加索引
   */
  private void addWithRecursiton(E e, Node<E> previous, int current, int index){
    if (current == index){
      previous.next = new Node(e, previous.next);
      return;
    }
    addWithRecursiton(e, previous.next, current + 1, index);
  }

  /**
   * @param e
   */
  public void addFirst(E e) {
    add(e, 0);
  }

  /**
   * @param e
   */
  public void addLast(E e) {
    add(e, size);
  }

  /**
   * 查询索引指定位置的元素
   * @param index
   * @return
   */
  public E get(int index){
    if (index < 0 || index >= size) {
      throw new IllegalArgumentException("LinkedList.get failed, index is illegal!");
    }

    Node<E> current = dummyHead.next;
    return getWithRecursion(current, 0, index);
  }

  /**
   * 
   * @param node 当前节点
   * @param current 当前递归索引
   * @param index 指定索引
   * @return
   */
  private E getWithRecursion(Node<E> node, int current, int index){
    if (current != index){
      return (E)getWithRecursion(node.next, current + 1, index);
    }
    return node.data;
  }

  /**
   *
   * @return
   */
  public E getFirst(){
    return get(0);
  }

  /**
   *
   * @return
   */
  public E getLast(){
    return get(size - 1);
  }

  /**
   * 更新索引指定位置元素
   * @param e  新元素
   * @param index 待更新元素索引
   */
  public void set(E e, int index){
    if (index < 0 || index >= size) {
      throw new IllegalArgumentException("LinkedList.set failed, index is illegal!");
    }

    Node current = dummyHead.next;
    setWithRecursion(current, e, 0, index);
  }

  /**
   * 
   * @param node 当前节点
   * @param e  带更新元素
   * @param current  当前递归索引
   * @param index  指定索引
   */
  private void setWithRecursion(Node<E> node, E e, int current, int index){
    if (current == index){
      node.data = e;
      return;
    }
    setWithRecursion(node.next, e, current + 1, index);
  }

  /**
   * 删除索引指定位置元素
   * @param index
   * @return
   */
  public E remove(int index){
    if (index < 0 || index >= size) {
      throw new IllegalArgumentException("LinkedList.remove failed, index is illegal!");
    }

    Node previous = dummyHead;
    E res = (E)removeWithRecursion(previous, 0, index);
    size--;
    return res;
  }

  /**
   * 
   * @param previous 
   * @param current
   * @param index
   * @return
   */
  private E removeWithRecursion(Node<E> previous, int current, int index){
    if (current != index){
      return (E)removeWithRecursion(previous.next, current + 1, index);
    }
    Node<E> delNode = previous.next;
    previous.next = previous.next.next;
    delNode.next = null;
    return (E)previous.next.data;
  }

  /**
   *
   * @return
   */
  public E removeFirst(){
    return remove(0);
  }

  /**
   *
   * @return
   */
  public E removeLast(){
    return remove(size -1);
  }

  /**
   * 查找是否存在元素e
   * @param e
   * @return
   */
  public boolean contains(E e){
    Node current = dummyHead.next;
    return containsWithRecursion(current, e);
  }

  /**
   * 
   * @param node
   * @param e
   * @return
   */
  private boolean containsWithRecursion(Node<E> node, E e){
    if (node == null){
      return false;
    }
    return node.data == e ? true : containsWithRecursion(node.next, e);
  }

  @Override
  public String toString(){
    StringBuilder res = new StringBuilder();
    Node current = dummyHead.next;

    return toStringWithRecursion(current, res);
  }

  /**
   * 
   * @param node
   * @param res
   * @return
   */
  private String toStringWithRecursion(Node<E> node, StringBuilder res){
    if (node == null){
      return res.append("NULL").toString();
    }
    res.append(node.data + "->");
    return toStringWithRecursion(node.next, res);
  }

  public static void main(String[] args) {
    LinkedListWithRecursion linkedList = new LinkedListWithRecursion();
    for(int i = 0; i < 5; i ++){
      linkedList.addFirst(i);
      System.out.println(linkedList);
    }
    linkedList.add(66, 3);
    System.out.println(linkedList);

    System.out.println(linkedList.get(3));

    linkedList.set(77, 3);
    System.out.println(linkedList);

    System.out.println(linkedList.remove(3));
    System.out.println(linkedList);

    System.out.println(linkedList.contains(2));
  }
}


正在回答 回答被采纳积分+3

3回答

慕少2174631 2018-06-09 23:40:45
//刚写完的递归实现链表的增删改查
public class LinkedListDigui<E extends Comparable<E>> {

    private class Node{
        public E e;
        public Node next;

        public Node(E e,Node next){
            this.e = e;
            this.next = next;
        }

        public Node(E e){
            this(e, null);
        }

        public Node () {
            this(null,null);
        }

        @Override
        public String toString(){
            return e.toString();
        }

    }

    private Node dummyHead;
    int size;

    public LinkedListDigui(){
        dummyHead = new Node(null,null);
        size = 0;
    }

    //获取链表中的元素个数
    public int getSize(){
        return size;
    }

    //返回链表为空
    public boolean isEmpty(){
        return size == 0;
    }


    //向索引指定位置添加元素
    public void add(int index,E e){
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("LinkedList.add failed, index is illegal!");
        }
        Node prevoius = dummyHead;
        dummyHead = add(prevoius,e,0,index);
    }


    //prevoius待添加元素的头一个节点,current当前索引,index待添加元素的索引
    //返回添加元素后的链表
    private Node add(Node prevoius, E e, int current, int index) {
        if(current == index){
            size++;
            prevoius.next = new Node(e,prevoius.next);//实现插入的方式参考虚拟头节点插入元素,不用考虑特殊情况如头节点
            return prevoius;
        }
        prevoius.next = add(prevoius.next,e,current+1,index);
        return prevoius;
    }

    //在链表头添加新的元素e
    public void addFirst(E e){
        add(0, e);
    }

    //在链表末尾添加新的元素e
    public void addLast(E e){
        add(size, e);
    }

    //获得链表的第index(0-based)个位置的元素
    //在链表中不是一个常用的操作,练习
    public E get(int index){
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("get failed. Illegal index.");
        }
        Node prevoius = dummyHead;
        Node cur = get(prevoius,index,0);
        return cur.e;
    }

    //prevoius获得元素的前一个节点,index获得元素的下标,current当前索引
    //返回找到的节点
    private Node get(Node prevoius, int index,int current) {
        if (current == index) {
            return prevoius.next;
        }
        prevoius.next = get(prevoius.next,index,current+1);
        return prevoius.next;
    }

    //获得链表的第一个元素
    public E getFirst(){
        return get(0);
    }

    //获得链表的最后一个元素
    public E getLast(){
        return get(size-1);//传进去的是下标
    }

    //修改链表的第index(0-based)个位置的元素
    //在链表中不是一个常用的操作,练习
    public void set(int index, E e){
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("Add failed. Illegal index.");
        }

        Node prevoius = dummyHead;
        set(prevoius,e,index,0);
    }

    //prevoius修改元素的前一个节点,e待修改的值,index待修改元素的下标,current当前下标
    private void set(Node prevoius, E e, int index, int current) {
        if (current == index) {
            prevoius.next.e = e;
            return;//老是忘记递归的退出条件,导致代码总出错。
        }
        set(prevoius.next,e,index,current+1);
    }

    //查找链表中是否有元素e
    public boolean contain(E e){
        Node prevoius = dummyHead;
        return contain(prevoius,e);
    }

    //prevoius查找元素的前一个节点,index获得元素的下标
    //返回找到的节点
    private boolean contain(Node prevoius, E e) {
        if (prevoius.next.e.compareTo(e)==0){
            return true;
        }
        return contain(prevoius.next,e);
    }

    //从链表中删除index(0-based)个位置的元素
    //在链表中不是一个常用的操作,练习
    public E remove(int index){

        if (index < 0 || index > size) {
            throw new IllegalArgumentException("remove failed. Illegal index.");
        }

        Node prevoius = dummyHead;
        return remove(prevoius,index,0);
    }

    //prevoius待删除元素的前一个节点,index获得元素的下标,current当前元素的下标
    //返回删除指定位置的元素的值
    private E remove(Node prevoius, int index, int current) {
        if (index == current){
            Node delNode = prevoius.next;
            prevoius.next = delNode.next;
            delNode.next = null;
            return prevoius.next.e;
        }
        return remove(prevoius.next,index,current+1);
    }

    //从链表中删除第1个位置的元素,返回删除的元素
    public E removeFirst(){
        return remove(0);
    }

    //从链表中删除最后1个位置的元素,返回删除的元素
    public E removeLast(){
        return remove(size-1);
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        Node cur = dummyHead.next;
        while (cur != null){
            res.append(cur + "->");
            cur = cur.next;
        }
        /*for (Node cur = dummyHead.next; cur != null ; cur.next = cur) {
            res.append(cur + "->");
        }*/
        res.append("NULL");
        return res.toString();
    }
}


0 回复 有任何疑惑可以回复我~
慕少2174631 2018-06-09 19:05:18

我发现你这样写有些问题,我在用实现增这个功能查看递归内部调用的顺序时发现会出现空指针异常,我试着在main函数中调用add(i,i)来添加元素就会出错,所以我这样写,你看看如何?
//向索引指定位置添加元素
   public void add(int index,E e){
       if (index < 0 || index > size) {
           throw new IllegalArgumentException("LinkedList.add failed, index is illegal!");
       }
       Node prevoius = dummyHead;
       dummyHead = add(prevoius,e,0,index ,0);
   }

//prevoius待添加元素的头一个节点,current当前索引,index待添加元素的索引
//返回添加元素后的链表
private Node add(Node prevoius, E e, int current, int index,int depth) {
   String depthString = generateDepthString(depth);
   System.out.print(depthString);
   System.out.println("Call: add " + e + " in: " + prevoius.next );
   if(current == index){
       size++;
       prevoius.next = new Node(e,prevoius.next);
       System.out.print(depthString);
       System.out.println("Return:" + prevoius.next );
       return prevoius;
   }
   prevoius.next = add(prevoius.next,e,current+1,index,depth + 1);
   System.out.print(depthString);
   System.out.println("After add :" + prevoius.next );
   return prevoius;
}

private String generateDepthString(int depth){
   StringBuilder sb = new StringBuilder();
   for (int i = 0; i < depth; i++) {
       sb.append("==");
   }
   return sb.toString();
}

0 回复 有任何疑惑可以回复我~
  • 哦对了。。。在递归里面用的添加语句,我也不知道自己为啥这样写代码能跑通,所以我尝试自己去解析它。然后我才意识到这是用无虚拟头节点实现增加方法的语句,所以
    prevoius.next = new Node(e,prevoius.next);
    等价于
    Node node = new Node(e);
    node.next = prevoius.next;
    prevoius.next = node;
    回复 有任何疑惑可以回复我~ 2018-06-09 19:23:38
  • 又尴尬了,以后我理清楚再说。。。明明是有虚拟头节点实现
    回复 有任何疑惑可以回复我~ 2018-06-09 19:31:17
liuyubobobo 2018-05-14 19:13:11

赞!感谢分享:)

0 回复 有任何疑惑可以回复我~
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信