链表的递归实现

来源:5-7 更多和链表相关的问题

SsssZzzz

2018-05-14

在课程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回答

慕少2174631

2018-06-09

//刚写完的递归实现链表的增删改查
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
0

慕少2174631

2018-06-09

我发现你这样写有些问题,我在用实现增这个功能查看递归内部调用的顺序时发现会出现空指针异常,我试着在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
2
慕少2174631
又尴尬了,以后我理清楚再说。。。明明是有虚拟头节点实现
2018-06-09
共2条回复

liuyubobobo

2018-05-14

赞!感谢分享:)

0
0

玩转数据结构

动态数组/栈/队列/链表/BST/堆/线段树/Trie/并查集/AVL/红黑树…

6221 学习 · 1704 问题

查看课程