简体   繁体   English

在恒定时间内将节点插入链表?

[英]Inserting a node into a linked list in constant-time?

I'm working on an assignment that is telling me to assume that I have a singly linked list with a header and tail nodes.我正在做一项作业,它告诉我假设我有一个带有 header 和尾节点的单向链表。 It wants me to insert an item y before position p.它要我在 position p 之前插入一个项目 y。 Can anybody please look over my code and tell me if I'm on the right track?任何人都可以查看我的代码并告诉我我是否在正确的轨道上? If not, can you provide me with any tips or pointers (no pun intended)?如果没有,您能否为我提供任何提示或指示(无双关语)?

tmp = new Node();
tmp.element = p.element;
tmp.next = p.next;
p.element = y;
p.next = tmp;

I think I may be wrong because I do not utilize the header and tail nodes at all even though they are specifically mentioned in the description of the problem.我想我可能是错的,因为我根本没有使用 header 和尾节点,即使在问题描述中特别提到了它们。 I was thinking of writing a while loop to traverse the list until it found p and tackle the problem that way but that wouldn't be constant-time, would it?我正在考虑编写一个 while 循环来遍历列表,直到它找到 p 并以这种方式解决问题,但这不会是恒定时间,对吗?

Just write it down if you get stuck with an algorithm: 如果遇到算法问题,只需写下来:

// First we have a pointer to a node containing element (elm) 
// with possible a next element.
// Graphically drawn as:
// p -> [elm] -> ???

tmp = new Node();
// A new node is created. Variable tmp points to the new node which 
// currently has no value.
// p   -> [elm] -> ???
// tmp -> [?]

tmp.element = p.element;

// The new node now has the same element as the original.
// p   -> [elm] -> ???
// tmp -> [elm]

tmp.next = p.next;

// The new node now has the same next node as the original.
// p   -> [elm] -> ???
// tmp -> [elm] -> ???

p.element = y;

// The original node now contains the element y.
// p   -> [y] -> ???
// tmp -> [elm] -> ???

p.next = tmp;

// The new node is now the next node from the following.
// p   -> [y] -> [elm] -> ???
// tmp -> [elm] -> ???

You have the required effect, but it can be more efficient and I bet you can now find out yourself. 您已达到要求的效果,但是它可以提高效率,我敢打赌,您现在就可以了解自己。

It is more clear to write something like: 写这样的东西更清晰:

tmp = new Node();
tmp.element = y;
tmp.next = p;
p = tmp;

Which of course does not work if p is not mutable. 如果p不可变,那当然不起作用。 But your algorithm fails if p == NULL. 但是,如果p == NULL,则您的算法将失败。

But what I meant to say, is, if you have problems with an algorithm, just write the effects out. 但是我要说的是,如果您对算法有疑问,只需写下效果即可。 Especially with trees and linked lists, you need to be sure all pointers are pointing to the righ direction, else you get a big mess. 尤其是对于树和链表,您需要确保所有指针都指向严格的方向,否则您会陷入困境。

Hint : insertion into a linked list is only constant when position n = 0, or the head of the list. 提示 :仅当位置n = 0或列表的开头时,插入到链表中才是常数。 Otherwise, the worst-case complexity is O(n) . 否则,最坏情况下的复杂度是O(n) That's not to say that you cannot create a reasonably efficient algorithm, but it will always have at least linear complexity. 这并不是说您不能创建一个合理有效的算法,但是它将始终至少具有线性复杂性。

The reason why the header and tail node is given in the question is to the update the header and tail reference if the the replacement node that your creating happens to become the header or tail. 问题中给出标题和尾部节点的原因是,如果您创建的替换节点碰巧变为标题或尾部,则更新标题和尾部引用。 In other is words, the given previous node is either a header or tail. 换句话说,给定的先前节点是标头或尾部。

In a singly LinkedList only adding a Node to the beginning of the list or creating a List with only one Node would take O(1). 在单个LinkedList中,仅将Node添加到列表的开头或仅使用一个Node创建List都将花费O(1)。 OR as they have provided the TailNode also Inserting the Node at End of list would take O(1). 或者,因为他们已经提供了TailNode,并且还在列表末尾插入Node将花费O(1)。

every other inserting operation will take O(n). 其他所有插入操作将取O(n)。

create a node ptr
ptr->info = item //item is the element to be inserted...
ptr->next = NULL
if (start == NULL) //insertion at the end...
    start = ptr
else
    temp = ptr
    while (temp->next != NULL)
        temp = temp->next
    end while 
end if
if (start == NULL) //insertion at the beginning...
    start = ptr
else
    temp = start
    ptr->info = item
    ptr->next = start
    start = ptr
end if
temp = start //insertion at specified location...
for (i = 1; i < pos-1; i++)
    if (start == NULL)
        start = ptr
    else
        t = temp
        temp = temp->next
    end if
end for
t->next = ptr->next
t->next = ptr

What you are not doing is linking the element that was before p prior to insertion of y to y. 您不做的是将y插入y之前将p之前的元素链接起来。 So while y is inserted before p, no one is pointing to y now (at-least not in the code snipped you showed). 因此,当在p之前插入y时,现在没有人指向y(至少不在您显示的代码片段中)。

You can only insert in constant time if you know the positions of the elements between which you have to insert y. 如果您知道必须在其间插入y的元素的位置,则只能以固定时间插入。 If you have to search for that position, then you can never have a constant time insertion in a single link list. 如果必须搜索该位置,则永远不能在单个链接列表中插入固定时间。

How about using code that is already there? 如何使用已经存在的代码? LinkedHashMap, LinkedList, LinkedHashSet. LinkedHashMap,LinkedList,LinkedHashSet。 You can also check out the code and learn from it. 您还可以签出代码并从中学习。

The whole explanation and the 2 codes are in Java... but its easy to translate it to any other language of your choice.整个解释和 2 个代码在 Java 中......但很容易将其翻译成您选择的任何其他语言。 I do want to help you however I am a beginner myself... Still I have used the logic, sharing it from the queues implementation... I have pasted two codes one is in O(N) the other contains a method called append which is in O(1) Now, the explanation我确实想帮助你,但我自己是初学者......我仍然使用逻辑,从队列实现中分享它......我粘贴了两个代码,一个在 O(N) 中,另一个包含一个名为 append 的方法这是在 O(1) 现在,解释

  1. declare the tail node with head node in the class在 class 中用头节点声明尾节点

  2. now in the method append class in the 2nd code below just look at the tail pointer现在在方法 append class 下面的第二个代码中只看尾指针

  3. CASE 1: when LL empty usually people check if (head == null) if true then they point the head to the new Node and return案例 1:当 LL 为空时,通常人们会检查 if (head == null) if if true 然后他们将 head 指向新节点并返回

    whereas what I have done is I checked if (tail == null) and if it was true then tail = head = newnode meaning that the tail and head both now point to the new Node to be added.而我所做的是检查 if (tail == null) 并且如果它是 true 那么 tail = head = newnode 意味着 tail 和 head 现在都指向要添加的新节点。

  4. CASE 2: when LL is not empty wait, haha, hear me out first, I know you might be thinking that what if the LL has just 1 node currently, then what? CASE 2:当 LL 不为空时等等,哈哈,先听我说完,我知道你可能会想如果 LL 目前只有 1 个节点怎么办? well... for that...嗯……为此……

    this case 2 handles it automatically, in case 1 it sets the head and tail equal to the newnode right, so it now just changes and modifies the tail node keeping the head node intact.这种情况 2 会自动处理它,在情况 1 中它会将头和尾设置为等于新节点的权利,因此它现在只更改和修改尾节点,保持头节点不变。

    this way, the head keeps pointing to the first node and the tail keeps updating and pointing to the newnodes created with each append function call.这样,头部一直指向第一个节点,尾部不断更新并指向每次 append function 调用创建的新节点。

Hope this explanation helps...希望这个解释有帮助...

PS.附言。 check from line 24 for O(N) and 102 for O(1) and every time a newnode is added to the LL by the append method call, the tail will point to the new node to be added.检查第 24 行的 O(N) 和第 102 行的 O(1),每次通过 append 方法调用将新节点添加到 LL 时,尾部将指向要添加的新节点。

import java.io.*;
import java.util.*;

public class Solution {
    
    // class Solution is what should be called as the LINKEDLIST class but its ok
    
    Node head;  // declaring a head for the LL
    
    class Node {    // Node class
    
        int data;   // the .data variable
        Node ref;   // .ref aka .next 

        Node(int data) {    // constructor for initializing the values
        
            this.data = data;
            this.ref = null;
            
        }
    }
    
    public void append(int data) {  // i call 'to join at the end' as append
        // O(N)
    
        Node newnode = new Node(data);  // new node creation
        
        if (head == null) {     // checking is head is null aka None in Py
            head = newnode;
            return;
        }
        
        Node curr = head;   // assigning head to a curr node ready for traversal
        
        while (curr.ref != null) {  // traversal begins
            curr = curr.ref;
        }                           // traversal ends
        
        curr.ref = newnode; // this is the last node where the join happens
        
    }
    
    public void p() {   // i name printing function as p()
    
        if (head == null) { // if head is null then print empty
            System.out.println("Empty");
            return;
        }
        
        Node curr = head;   // same thing - traversal begins here
        
        while (curr != null) {
            System.out.println(curr.data);
            curr = curr.ref;
        }   // by now all data values have been printed out already
        
    }

    public static void main(String[] args) {
        
        Scanner sc = new Scanner(System.in);    // scanner class for input
        
        Solution l = new Solution();    // object creating for LL as Solution class name
        
        int numberOfNodes = sc.nextInt();   // input for number of NODEs in LL
        
        for (int i = 0; i < numberOfNodes; i++) {   // loop for .data values
        
            int data = sc.nextInt();    
            l.append(data); // function append call for each (i)
            
        }
        
        l.p();  // finally print func call to display output LL
        
    }
}


class PractGG {
    Node head;
    Node tail;

    class Node {
        int data;
        Node ref;
        Node(int data) {
            this.data = data;
            this.ref = null;
        }
    }
    public void push(int data) {
        Node newnode = new Node(data);
        if (head == null) {
            tail = head = newnode;
            return;
        }
        newnode.ref = head;
        head = newnode;
    }
    public void append(int data) {
        // O(1)
        Node newnode = new Node(data);
        if (tail == null) {
            tail = head = newnode;
            return;
        }
        tail.ref = newnode;
        tail = newnode;
    }
    
    public void p() {
        if (head == null) {
            System.out.println("Empty");
        }
        Node curr = head;
        while (curr!=null) {
            System.out.print(curr.data + "==>");
            curr = curr.ref;
        }
        System.out.println();
    }
    public static void main(String[] args) {
        PractGG l = new PractGG();
        l.append(1);
        l.append(2);
        l.append(3);
        l.p();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM