在链表

时间:2015-09-17 08:40:08

标签: java recursion data-structures recursive-datastructures

对于这类问题,有一个简单的迭代解决方案。

Node Insert(Node head,int data) {
    Node newNode = new Node();
    newNode.data = data;
    if (head == null) {
        return newNode;
    }
    Node current = head; 
    while (current.next != null) {
        current = current.next;
    }
    current.next = newNode;
    return head;
}

它完美无缺。但我想学习递归并用这种观点看待事物。因此我提出了以下解决方案,看起来很优雅,但我不得不承认它只是直觉并且给定的代码有效。我想开发一个用于递归的心理模型,或者至少某种方式来验证我的代码是否正常工作。如何从理论上验证以下解决方案是否有效。

递归版

Node Insert(Node head,int data) {
    // Base case.
    if (head == null) {
        Node newNode = new Node();
        newNode.data = data;
        return newNode;
    }
    // Smaller problem instance.
    head.next = Insert(head.next, data);
    return head;
}

3 个答案:

答案 0 :(得分:2)

递归解决方案通常必须遵守这些规则:

  1. 必须区分通用案例和 base 案例。然后,它必须包含某种类型的代码分叉(通常是一个if)到两个代码块:基本块和通用块。
  2. 基本块必须返回立即响应(不是递归)。
  3. 一般块必须重新调用相同的函数(递归),但不能使用相同的参数值(这将产生无限递归),但是向前发送到基数的值情况下。
  4. 对于corse,这是一个简单的递归模型,实际上可能更复杂(多个基本情况,两个函数之间的递归等)。

    如果我们根据这些规则在理论上分析您的提案,我们可以看到它符合所有规则。

答案 1 :(得分:1)

我会稍微采用代码并删除多个退出点。这允许您推断列表上的效果和返回的节点mut。

Node appendRecursive(Node head, int data) {
    // By default return the same list we were given.
    Node list = head;
    if (list == null) {
        // At end of list or list is empty.
        list = new Node();
        list.data = data;
    } else {
        // Recurse.
        head.next = appendRecursive(head.next, data);
    }
    return list;
}

就推理而言,你通常需要使用归纳法。

  • 如果列表为空(list == null),则创建一个新节点,该节点将成为您的列表。
  • 如果列表不为空,则新列表必须是附加新数据的列表。

鉴于上述情况,可以推断在所有情况下,这将正常运作,因为列表为空或不是。

在列表上使用递归通常被认为是低效且笨重的,因为迭代算法更适合线性结构。更好的练习是编写自己的Tree结构,因为树很适合递归算法。您会发现在树上递归执行所需的函数通常会更容易和更优雅。

static class Tree {

    Node head = null;

    class Node {

        Node left;
        Node right;
        int data;

        private Node(int data) {
            this.data = data;
        }
    }

    void insert(int data) {
        head = insert(head, data);
    }

    private Node insert(Node node, int data) {
        if (node == null) {
            // Empty tree becomes just the node.
            return new Node(data);
        } else {
            // Pick the correct branch to add this data to.
            if (data < node.data) {
                node.left = insert(node.left, data);
            } else {
                node.right = insert(node.right, data);
            }
        }
        return node;
    }

    private CharSequence toString(Node n) {
        StringBuilder s = new StringBuilder();
        if (n != null) {
            // First print the tree on the left.
            if (n.left != null) {
                s.append(toString(n.left)).append(",");
            }
            // Then the data in this node.
            s.append(n.data);
            // Then the tree on the right.
            if (n.right != null) {
                s.append(",").append(toString(n.right));
            }
        }
        return s;
    }

    @Override
    public String toString() {
        // Even toString is recursive.
        StringBuilder s = new StringBuilder("{");
        s.append(toString(head));
        return s.append("}").toString();
    }
}

public void test() {
    Tree tree = new Tree();
    for (int i : new int[]{6, 5, 4, 3, 2, 1}) {
        tree.insert(i);
    }
    System.out.println(tree);
}

请注意在toString方法中判断添加“,”的位置是多么简单 - 在打印列表时这是一个众所周知的笨重问题。

答案 2 :(得分:0)

Node Insert(Node head,int data) {
    if (head == null) {
        head  = new Node();
        head.data = data;
    }
    else{
    head.next = Insert(head.next, data);
    }
    return head;
}

假设您有5,3,2,1并且您想添加4然后: - insert(node(5),int 4)

if( node(5) == null )head.next = node(5).next node(3)并致电Insert(node(3),4)

if( node(3) == null )head.next = node(3).next node(2)并致电Insert(node(2),4)

if( node(2) == null )head.next = node(2).next node(1)并致电Insert(node(1),4)

if( node(1) == null )不是head.next = node(1).next null因为 node(1)之后没有元素”并且调用Insert(node(1).next,4) < / p>

(node(1).next) == null是,然后设置head = new node ();并在结束返回头设置数据head = new node ();