C链表:将数字放在列表前面,并使所有数字移位

C链表:将数字放在列表前面,并使所有数字移位,c,linked-list,C,Linked List,我正在试着让这个方法开始工作。我想在列表中插入一个数字,使最后一个数字消失。如果这是列表p1->2->3->4->5,那么在shiftInsert8之后,列表需要看起来像p8->1->2->3->4。正如你所见,最后一个数字需要消失。我如何实现这一点 #include <stdio.h> #include <stdlib.h> struct elem { int value; struct elem *next; }; typedef struct e

我正在试着让这个方法开始工作。我想在列表中插入一个数字,使最后一个数字消失。如果这是列表p1->2->3->4->5,那么在shiftInsert8之后,列表需要看起来像p8->1->2->3->4。正如你所见,最后一个数字需要消失。我如何实现这一点

#include <stdio.h>
#include <stdlib.h>

struct elem {
    int value;
    struct elem *next;
};

typedef struct elem Node;

Node *root;

Node * addElem(Node *p, int value) {
    p->next = malloc(sizeof *p);
    p = p->next;
    p->value = value;
    p->next = NULL;
    return p;
}

void shiftInsert(Node *n, int v) {
    int tmp;

    while (n != NULL) {
        Node * new_node;
        new_node = malloc(sizeof (new_node));
        n = n->next;
    }
}

void printList() {
    Node *p = root;

    while (p != NULL) {
        printf("%2d -> ", p->value);
        p = p->next;
    }

    printf("NULL\n");
}

int main(int argc, char **argv) {
    Node *p;
    int i = 0;

    root = p = malloc(sizeof (Node));
    p->value = 1;

    for (i = 2; i <= 10; i++) {
        p = addElem(p, i);
    }

    printList();
    shiftInsert(root, 88);
    printList();
    shiftInsert(root->next->next->next, 33);
    printList();

    return 0;
} 

根据您的示例,您希望插入第一个位置并删除最后一个位置。因此,基本上您希望创建一个新根,然后找到最后一个元素,并将其next设置为NULL

首先是delete函数:

void deleteLast()
{
    int i, before_last = 0;
    Node *temp;

    /* Find last element to remove it*/
    temp = root;

    for(i = 0; temp->next != NULL; i++) { // "i" will be the index of the last element
        temp = temp->next;
    }

    before_last = i - 1; // the one before "i" will be the new last element
    temp = root;

    for(i = 0; i < before_last; i++) { // find the one before last and set its "next" NULL
        temp = temp->next;
    }

    free(temp->next);
    temp->next = NULL;
}
根据main,要在某个元素之后插入,必须首先找到它。然后创建一个新元素,并将其下一个设置为原始元素的下一个,这样就不会丢失列表的其余部分。最后,将原始元素的下一个元素设置为新元素

void shiftInsertAnywhere(Node *position, int v) {
    int i;
    Node *temp;

    temp = root;

    for(i = 0; temp->value != position->value; i++) {

        temp = temp->next;
    }

    if (temp != NULL) {
        Node * new_root;
        /* Create new root */
        new_root = malloc(sizeof (new_root));
        new_root->next = temp->next; // save the rest of the list
        new_root->value = v;         // set new value
        position->next = new_root;   // insert the new element after "position" element

        deleteLast();
    }
}
这将在位置后插入

例如:

printList();
shiftInsertRoot(88);
printList();
shiftInsertRoot(33);
printList();
shiftInsertAnywhere(root->next->next, 99);
printList();
shiftInsertAnywhere(root, 17171);
printList();
输出:


根据您的示例,您希望插入第一个位置并删除最后一个位置。因此,基本上您希望创建一个新根,然后找到最后一个元素,并将其next设置为NULL

首先是delete函数:

void deleteLast()
{
    int i, before_last = 0;
    Node *temp;

    /* Find last element to remove it*/
    temp = root;

    for(i = 0; temp->next != NULL; i++) { // "i" will be the index of the last element
        temp = temp->next;
    }

    before_last = i - 1; // the one before "i" will be the new last element
    temp = root;

    for(i = 0; i < before_last; i++) { // find the one before last and set its "next" NULL
        temp = temp->next;
    }

    free(temp->next);
    temp->next = NULL;
}
根据main,要在某个元素之后插入,必须首先找到它。然后创建一个新元素,并将其下一个设置为原始元素的下一个,这样就不会丢失列表的其余部分。最后,将原始元素的下一个元素设置为新元素

void shiftInsertAnywhere(Node *position, int v) {
    int i;
    Node *temp;

    temp = root;

    for(i = 0; temp->value != position->value; i++) {

        temp = temp->next;
    }

    if (temp != NULL) {
        Node * new_root;
        /* Create new root */
        new_root = malloc(sizeof (new_root));
        new_root->next = temp->next; // save the rest of the list
        new_root->value = v;         // set new value
        position->next = new_root;   // insert the new element after "position" element

        deleteLast();
    }
}
这将在位置后插入

例如:

printList();
shiftInsertRoot(88);
printList();
shiftInsertRoot(33);
printList();
shiftInsertAnywhere(root->next->next, 99);
printList();
shiftInsertAnywhere(root, 17171);
printList();
输出:


在不增加列表的情况下,不需要为插入节点分配新空间。下面是一个函数,它在列表的开头插入一个节点,并删除最后一个节点:

Node * shiftInsert(Node *n, int v) {
    Node *tail = n;

    if (n == NULL){
        return n;
    } else if (n->next == NULL) {
        n->value = v;
        return n;
    }
    while (tail->next->next != NULL)
        tail = tail->next;
    tail->next->value = v;
    tail->next->next = n;
    n = tail->next;
    tail->next = NULL;

    return n;
}
Node * shiftInsertAny(Node *root, Node *n, int v) {
    Node *tail = n;
    Node *insert = root;

    if (root == NULL){
        return root;

    } else if (root->next == NULL) {
        root->value = v;
        return root;

    }
    while (n != root && insert->next != n)
        insert = insert->next;
    if (insert->next->next == NULL) {
        insert->next->value = v;
        return root;
    }
    while (tail->next->next != NULL)
        tail = tail->next;
    tail->next->value = v;
    tail->next->next = n;
    if (insert == root)
        root = tail->next;
    else
        insert->next = tail->next;
    tail->next = NULL;

    return root;
}
注意,这个版本的shiftInsert返回一个指向列表头部的指针

下面是第二个函数,它允许您在列表中的任何位置插入节点,并删除最后一个节点:

Node * shiftInsert(Node *n, int v) {
    Node *tail = n;

    if (n == NULL){
        return n;
    } else if (n->next == NULL) {
        n->value = v;
        return n;
    }
    while (tail->next->next != NULL)
        tail = tail->next;
    tail->next->value = v;
    tail->next->next = n;
    n = tail->next;
    tail->next = NULL;

    return n;
}
Node * shiftInsertAny(Node *root, Node *n, int v) {
    Node *tail = n;
    Node *insert = root;

    if (root == NULL){
        return root;

    } else if (root->next == NULL) {
        root->value = v;
        return root;

    }
    while (n != root && insert->next != n)
        insert = insert->next;
    if (insert->next->next == NULL) {
        insert->next->value = v;
        return root;
    }
    while (tail->next->next != NULL)
        tail = tail->next;
    tail->next->value = v;
    tail->next->next = n;
    if (insert == root)
        root = tail->next;
    else
        insert->next = tail->next;
    tail->next = NULL;

    return root;
}
此函数还返回指向列表头的指针,并将指向列表头的指针和指向插入点的指针作为参数。新节点插入到由指针n指示的节点前面

如果在代码中这样调用这些函数:

printList();
root = shiftInsert(root, 88);
printList();
root = shiftInsertAny(root, root->next->next->next, 33);
printList();
这是输出:

1 ->  2 ->  3 ->  4 ->  5 ->  6 ->  7 ->  8 ->  9 -> 10 -> NULL
88 ->  1 ->  2 ->  3 ->  4 ->  5 ->  6 ->  7 ->  8 ->  9 -> NULL
88 ->  1 ->  2 -> 33 ->  3 ->  4 ->  5 ->  6 ->  7 ->  8 -> NULL
我更新了shiftInsertAny函数的上述代码段。我做了一个更改,允许它在列表的开头插入一个节点,但是我忘记了在前面编辑代码段。使用此函数,可以插入到第一个节点或最后一个节点中。例如,使用5元素列表,可以执行以下操作:

printList();
root = shiftInsertAny(root, root, 88);
printList();
root = shiftInsertAny(root, root->next->next->next->next, 33);
printList();
其输出:

1 ->  2 ->  3 ->  4 ->  5 -> NULL
88 ->  1 ->  2 ->  3 ->  4 -> NULL
88 ->  1 ->  2 ->  3 -> 33 -> NULL

在不增加列表的情况下,不需要为插入节点分配新空间。下面是一个函数,它在列表的开头插入一个节点,并删除最后一个节点:

Node * shiftInsert(Node *n, int v) {
    Node *tail = n;

    if (n == NULL){
        return n;
    } else if (n->next == NULL) {
        n->value = v;
        return n;
    }
    while (tail->next->next != NULL)
        tail = tail->next;
    tail->next->value = v;
    tail->next->next = n;
    n = tail->next;
    tail->next = NULL;

    return n;
}
Node * shiftInsertAny(Node *root, Node *n, int v) {
    Node *tail = n;
    Node *insert = root;

    if (root == NULL){
        return root;

    } else if (root->next == NULL) {
        root->value = v;
        return root;

    }
    while (n != root && insert->next != n)
        insert = insert->next;
    if (insert->next->next == NULL) {
        insert->next->value = v;
        return root;
    }
    while (tail->next->next != NULL)
        tail = tail->next;
    tail->next->value = v;
    tail->next->next = n;
    if (insert == root)
        root = tail->next;
    else
        insert->next = tail->next;
    tail->next = NULL;

    return root;
}
注意,这个版本的shiftInsert返回一个指向列表头部的指针

下面是第二个函数,它允许您在列表中的任何位置插入节点,并删除最后一个节点:

Node * shiftInsert(Node *n, int v) {
    Node *tail = n;

    if (n == NULL){
        return n;
    } else if (n->next == NULL) {
        n->value = v;
        return n;
    }
    while (tail->next->next != NULL)
        tail = tail->next;
    tail->next->value = v;
    tail->next->next = n;
    n = tail->next;
    tail->next = NULL;

    return n;
}
Node * shiftInsertAny(Node *root, Node *n, int v) {
    Node *tail = n;
    Node *insert = root;

    if (root == NULL){
        return root;

    } else if (root->next == NULL) {
        root->value = v;
        return root;

    }
    while (n != root && insert->next != n)
        insert = insert->next;
    if (insert->next->next == NULL) {
        insert->next->value = v;
        return root;
    }
    while (tail->next->next != NULL)
        tail = tail->next;
    tail->next->value = v;
    tail->next->next = n;
    if (insert == root)
        root = tail->next;
    else
        insert->next = tail->next;
    tail->next = NULL;

    return root;
}
此函数还返回指向列表头的指针,并将指向列表头的指针和指向插入点的指针作为参数。新节点插入到由指针n指示的节点前面

如果在代码中这样调用这些函数:

printList();
root = shiftInsert(root, 88);
printList();
root = shiftInsertAny(root, root->next->next->next, 33);
printList();
这是输出:

1 ->  2 ->  3 ->  4 ->  5 ->  6 ->  7 ->  8 ->  9 -> 10 -> NULL
88 ->  1 ->  2 ->  3 ->  4 ->  5 ->  6 ->  7 ->  8 ->  9 -> NULL
88 ->  1 ->  2 -> 33 ->  3 ->  4 ->  5 ->  6 ->  7 ->  8 -> NULL
我更新了shiftInsertAny函数的上述代码段。我做了一个更改,允许它在列表的开头插入一个节点,但是我忘记了在前面编辑代码段。使用此函数,可以插入到第一个节点或最后一个节点中。例如,使用5元素列表,可以执行以下操作:

printList();
root = shiftInsertAny(root, root, 88);
printList();
root = shiftInsertAny(root, root->next->next->next->next, 33);
printList();
其输出:

1 ->  2 ->  3 ->  4 ->  5 -> NULL
88 ->  1 ->  2 ->  3 ->  4 -> NULL
88 ->  1 ->  2 ->  3 -> 33 -> NULL

所以你的问题是。。。我如何实现这一点?你必须更具体一点。你只想插入第一个位置?为什么不更新下一个到最后一个节点中的下一个指针,使其指向NULL,使最后一个节点成为新的头,更新其值并更新指向旧头的下一个指针。您提问的方式表明您需要一个函数,该函数只接受一个值作为输入,并将该值插入列表的头,从而删除最后一个节点。但是您的代码表明您希望能够将节点插入列表中的任何位置。你的问题应该更具体一些。@BenceKaulics是的,我想在列表的开头插入最后一个数字,这样你的问题是。。。我如何实现这一点?你必须更具体一点。你只想插入第一个位置?为什么不更新下一个到最后一个节点中的下一个指针,使其指向NULL,使最后一个节点成为新的头,更新其值并更新指向旧头的下一个指针。您提问的方式表明您需要一个函数,该函数只接受一个值作为输入,并将该值插入列表的头,从而删除最后一个节点。但是您的代码表明您希望能够插入
节点在列表中的任意位置。你的问题应该更具体一些。@BenceKaulics是的,我想在列表的开头插入最后一个数字,让最后一个数字消失谢谢你的帮助!非常感谢:因为您将新节点插入给shiftInsertAnywhere函数的节点位置之后,所以此函数无法将新节点插入列表的开头位置。@DavidBowling有一个单独的函数用于此目的:void shiftinsertrotint v。我提到shiftInsertAnywhere将在position之后插入。我的观点是,您有三个函数,其中一个或两个函数(如果您真的想保留deleteLast函数)就可以了。@DavidBowling两个函数有两个不同的用途。第三个函数中的共享部分,该函数在以后的任何地方都可能有用。我认为这样读代码更容易,仅此而已。谢谢你的帮助!非常感谢:因为您将新节点插入给shiftInsertAnywhere函数的节点位置之后,所以此函数无法将新节点插入列表的开头位置。@DavidBowling有一个单独的函数用于此目的:void shiftinsertrotint v。我提到shiftInsertAnywhere将在position之后插入。我的观点是,您有三个函数,其中一个或两个函数(如果您真的想保留deleteLast函数)就可以了。@DavidBowling两个函数有两个不同的用途。第三个函数中的共享部分,该函数在以后的任何地方都可能有用。我认为这样读代码更容易,仅此而已。