Java 在链表末尾插入节点
这类问题有一个简单的迭代解法Java 在链表末尾插入节点,java,recursion,data-structures,recursive-datastructures,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
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;
}
我会把代码再进一步,删除多个退出点。这允许您对列表的影响以及返回哪个节点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
- 如果列表不是空的,则新列表必须是附加了新数据的列表
树
结构,因为树非常适合递归算法。您将发现,在树上递归地执行所需的函数通常更容易、更优雅
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);
}
静态类树{
节点头=空;
类节点{
左淋巴结;
节点权;
int数据;
专用节点(int数据){
这个数据=数据;
}
}
无效插入(整型数据){
头部=插入(头部,数据);
}
专用节点插入(节点,int数据){
if(node==null){
//空树只会变成节点。
返回新节点(数据);
}否则{
//选择要将此数据添加到的正确分支。
if(数据<节点数据){
node.left=插入(node.left,数据);
}否则{
node.right=插入(node.right,数据);
}
}
返回节点;
}
私有字符序列到字符串(节点n){
StringBuilder s=新的StringBuilder();
如果(n!=null){
//首先打印左侧的树。
如果(n.left!=null){
s、 追加(toString(n.left))。追加(“,”);
}
//然后是该节点中的数据。
s、 附加(n.数据);
//然后是右边的那棵树。
如果(n.right!=null){
s、 追加(“,”)。追加(toString(n.right));
}
}
返回s;
}
@凌驾
公共字符串toString(){
//甚至toString也是递归的。
StringBuilder s=新的StringBuilder(“{”);
s、 追加(toString(head));
返回s.append(“}”).toString();
}
}
公开无效测试(){
树=新树();
for(inti:newint[]{6,5,4,3,2,1}){
树.插入(i);
}
System.out.println(树);
}
请注意,在toString
方法中判断在何处添加“,”是多么简单,这在打印列表时是一个出了名的笨拙问题
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(节点(5),int 4)
if(node(5)==null)
no然后head.next=node(5)。next
即node(3)
并调用Insert(node(3),4)
if(node(3)==null)
no然后head.next=node(3)。next
即node(2)
并调用Insert(node(2),4)
if(node(2)==null)
no然后head.next=node(2)。next
即node(1)
并调用Insert(node(1),4)
if(node(1)==null)
no然后head.next=node(1)。next
是null
“,因为节点(1)”之后没有元素,所以调用插入(node(1)。next,4)
(节点(1).下一步)==null
yes,然后设置head=new节点()
并设置数据head=new节点()代码>在返回端头递归解决方案通常必须遵守以下规则:
它必须区分一般情况和基本情况。然后,它必须包含某种类型的代码分支(通常是一个if
)到两个代码块:基本块和通用块
基块必须返回立即响应(不是递归响应)
通用块必须(递归地)重新调用相同的函数,但不能使用相同的参数值(这将产生无限递归),而是使用向前推进到基本情况的值
对于corse,这是一个简单的递归模型,实际上可能更复杂(不止一个基本情况,两个函数之间的递归,等等)
如果我们根据这些规则从理论上分析你的提案,我们可以看到它符合所有这些规则