Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在链表中插入节点_C_Algorithm_Struct_Linked List_Doubly Linked List - Fatal编程技术网

C 在链表中插入节点

C 在链表中插入节点,c,algorithm,struct,linked-list,doubly-linked-list,C,Algorithm,Struct,Linked List,Doubly Linked List,我试图在两个索引之间动态插入一个节点,这两个索引包含node类型的结构。数组中的第一个元素是head指针,第二个元素是tail 我试图在数组的两个索引之间动态地增长双链接列表。以下是我迄今为止尝试过的代码 我也可以动态地创建head和tail作为节点,但根据需求,我必须这样做 保证要插入的节点data值位于qllentry[0]的值之间。data和qllentry[1]。data #include <stdio.h> #include <stdlib.h> #includ

我试图在两个索引之间动态插入一个节点,这两个索引包含node类型的结构。数组中的第一个元素是head指针,第二个元素是tail

我试图在数组的两个索引之间动态地增长双链接列表。以下是我迄今为止尝试过的代码

我也可以动态地创建head和tail作为节点,但根据需求,我必须这样做

保证要插入的节点
data
值位于
qllentry[0]的值之间。data
qllentry[1]。data

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

struct Node {
    int data;
    struct Node *qprev;
    struct Node *qnext;
}Node;

struct Node qllentry[2];


int main()
{

struct Node head, tail;
    head.data = INT_MAX;
    tail.data = INT_MIN;

    head.qnext = &tail;
    tail.qprev = &head;
    head.qprev = NULL;
    tail.qnext = NULL;


    qllentry[0] = head;
    qllentry[1] = tail;
    int key = 20;
    struct Node *curr ;
    struct Node *prev;
    curr= &qllentry[0];

    while(curr->qnext != NULL && curr->data >= key) {
                curr = curr->qnext;
        }
    prev = curr->qprev;

    struct Node *new_node = (struct Node*)malloc(sizeof(struct Node));
        new_node->data = key;
        new_node->qnext = prev->qnext;
        prev->qnext = new_node;
        new_node->qprev = prev;
        if (new_node->qnext != NULL)
            new_node->qnext->qprev = new_node;


    return 0;
}
#包括
#包括
#包括
结构节点{
int数据;
结构节点*qprev;
结构节点*qnext;
}节点;
结构节点qllentry[2];
int main()
{
结构节点头、尾;
head.data=INT_MAX;
tail.data=INT_MIN;
head.qnext=&tail;
tail.qprev=&head;
head.qprev=NULL;
tail.qnext=NULL;
qllentry[0]=头;
qllentry[1]=尾部;
int键=20;
结构节点*curr;
结构节点*prev;
curr=&qllentry[0];
while(curr->qnext!=NULL&&curr->data>=key){
curr=curr->qnext;
}
prev=当前->qprev;
结构节点*新节点=(结构节点*)malloc(sizeof(结构节点));
新建_节点->数据=键;
新建节点->下一步=上一步->下一步;
prev->qnext=新建_节点;
新建节点->qprev=prev;
if(新建节点->下一步!=NULL)
新建_节点->qnext->qprev=新建_节点;
返回0;
}
新节点的插入未按预期在头部和尾部索引之间进行。我添加了一些用于调试的打印语句


感谢您的帮助

以下是根据问题中的代码进行了一些修改的代码,我猜它会按预期打印结果:

dlink.c:

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

struct Node {
    int data;
    struct Node *qprev;
    struct Node *qnext;
} Snode;

int main() {
    struct Node *head = (struct Node*)malloc(sizeof(struct Node));
    struct Node *tail = (struct Node*)malloc(sizeof(struct Node));

    // init head,
    head->data = INT_MAX;
    head->qnext = tail;
    head->qprev = NULL;

    // init tail,
    tail->data = INT_MIN;
    tail->qprev = head;
    tail->qnext = NULL;

    int key = 20;
    struct Node *curr = head;
    struct Node *prev;

    //get the pointer of the process which has less priority than the current process
    while(curr->data >= key && curr->qnext != NULL) {
        curr = curr->qnext;
    }
    prev = curr->qprev;

    printf("head %p, data is %d, next is %p, prev is %p\n", head, head->data, (void *)head->qnext, (void *)head->qprev);
    printf("tail %p, data is %d, next is %p, prev is %p\n", tail, tail->data, (void *)tail->qnext, (void *)tail->qprev);
    printf("prev of new node %p, data is %d, next is %p, prev is %p\n", prev, prev->data, (void *)prev->qnext, (void *) prev->qprev);
    printf("--------------------\n\n");

    struct Node *new_node = (struct Node*)malloc(sizeof(struct Node));
    new_node->data = key;
    new_node->qnext = prev->qnext;
    prev->qnext = new_node;
    new_node->qprev = prev;

    if (new_node->qnext != NULL)
        new_node->qnext->qprev = new_node;
    else
        tail = new_node;

    printf("head %p, data is %d, next is %p, prev is %p\n", head, head->data, (void *)head->qnext, (void *)head->qprev);
    printf("new_node %p, data is %d, next is %p, prev is %p\n", new_node, new_node->data, (void *)new_node->qnext, (void *)new_node->qprev);
    printf("tail %p, data is %d, next is %p, prev is %p\n", tail, tail->data, (void *)tail->qnext, (void *)tail->qprev);

    return 0;
}
head 0x2380010, data is 2147483647, next is 0x2380030, prev is (nil)
tail 0x2380030, data is -2147483648, next is (nil), prev is 0x2380010
prev of new node 0x2380010, data is 2147483647, next is 0x2380030, prev is (nil) // this is same as head,
--------------------

head 0x2380010, data is 2147483647, next is 0x2380460, prev is (nil)
new_node 0x2380460, data is 20, next is 0x2380030, prev is 0x2380010
tail 0x2380030, data is -2147483648, next is (nil), prev is 0x2380460
建议

  • 不要将struct(head,tail)和struct指针(new_节点)混用,这很容易混淆,并且容易出错
  • 一个单链表就足以进行这样的插入,在单链表中插入元素有一种很复杂的方法
  • 为了获得良好的性能,您可以分配一个大型缓存,然后从缓存中创建新节点
  • 编译c代码时,添加
    -Wall
    选项,这将给您提供更多警告

虽然保留一个指向列表开头和结尾的数组(或指针)没有错,但如果使用数组,则在分配地址后将数组引用排除在列表操作之外。将
&array[x]
与列表操作混合使用只会导致混淆。使用列表时,请将其视为列表,而忽略数组

您的主要问题是迭代一个节点到远端,寻找插入新节点的位置,从而在停止之前迭代到
tail
。在插入
新节点之前,在节点上停止迭代。您可以通过测试以下各项来实现:

    /* test curr->qnext->data > key to stop before tail */
    while (curr->qnext && curr->qnext->data > key)
                curr = curr->qnext;
注意:使用变量屏蔽间接层次,就像您接下来使用
prev=curr->qprev;
只是隐藏细节——这可能会在以后增加混乱。这是完全合法的,但需要谨慎使用…)

现在,您可以集中精力在
之间插入
新节点

在任何列表插入中,只需重新连接当前节点的指针->下一个以指向
新\u节点
,以及下一个节点的指针->上一个以指向
新\u节点
。要完成插入,您的
new\u节点->qprev
指向
curr
new\u节点->qnext
指向
curr->next
,例如

    new_node->qprev = curr;         /* rewire pointers */
    new_node->qnext = curr->qnext;
    curr->qnext->qprev = new_node;
    curr->qnext = new_node;
注意:解决这个问题的简单方法是,用一张纸和一支2号铅笔画一个块,用于curr一个块,一个块用于
新节点
和一个块用于,然后为上一个/下一个指针画线(对于没有
新节点
的列表和带有它的列表).然后,理直气壮地坐到键盘前,把它啄出来。)

此外,您必须始终验证您的分配,例如

    /* allocate and VALIDATE! */
    if (!(new_node = malloc (sizeof *new_node))) {
        perror ("malloc - new_node");
        exit (EXIT_FAILURE);
    }
在您编写的任何动态分配内存的代码中,对于所分配的任何内存块,您有两个责任:(1)始终保留指向内存块起始地址的指针,以便(2)在不再需要它时可以释放它。因此,如果分配它,请跟踪指向该块的指针,并在处理完该块后
free
。例如,输出列表值(或在专用循环中)后,可以释放分配的内存,类似于:

    curr = &head;                   /* output list */
    while (curr) {
        printf ("%d\n", curr->data);
        struct Node *victim = curr; /* self-explanatory */
        curr = curr->qnext;
        /* do not forget to free allocated memory */
        if (victim != &head && victim != &tail) {
            free (victim);
        }
    }
$ ./bin/llarray
list pointers:

prev:            (nil)    curr:   0x7ffd56371910    next:        0x1038010
prev:   0x7ffd56371910    curr:        0x1038010    next:   0x7ffd56371930
prev:        0x1038010    curr:   0x7ffd56371930    next:            (nil)
总而言之,您可以执行以下操作:

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

struct Node {
    int data;
    struct Node *qprev;
    struct Node *qnext;
} Node;

struct Node qllentry[2];


int main (void) {

    struct Node head = { .data = INT_MAX }, 
                tail = { .data = INT_MIN },
                *curr,
                *new_node;

    qllentry[0] = head;     /* keep your array and list operations separate */
    qllentry[1] = tail;

    head.qnext = &tail;     /* begin list operations */
    tail.qprev = &head;

    int key = 20;

    curr = &head;

    /* test curr->qnext->data > key to stop before tail */
    while (curr->qnext && curr->qnext->data > key)
                curr = curr->qnext;

    /* allocate and VALIDATE! */
    if (!(new_node = malloc (sizeof *new_node))) {
        perror ("malloc - new_node");
        exit (EXIT_FAILURE);
    }

    new_node->data = key;           /* assign value to new_node */

    new_node->qprev = curr;         /* rewire pointers */
    new_node->qnext = curr->qnext;
    curr->qnext->qprev = new_node;
    curr->qnext = new_node;

    curr = &head;                   /* output list */
    while (curr) {
        printf ("%d\n", curr->data);
        struct Node *victim = curr; /* self-explanatory */
        curr = curr->qnext;
        /* do not forget to free allocated memory */
        if (victim != &head && victim != &tail) {
            free (victim);
        }
    }

    return 0;
}
内存使用/错误检查

必须使用内存错误检查程序,以确保您不会试图访问内存或写入超出/超出分配的块的边界,尝试在未初始化的值上读取或建立条件跳转,最后确认释放所有已分配的内存

对于Linux,
valgrind
是正常的选择。每个平台都有类似的内存检查器。它们都很容易使用,只需运行程序即可

$ valgrind ./bin/llarray
==8665== Memcheck, a memory error detector
==8665== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==8665== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==8665== Command: ./bin/llarray
==8665==
2147483647
20
-2147483648
==8665==
==8665== HEAP SUMMARY:
==8665==     in use at exit: 0 bytes in 0 blocks
==8665==   total heap usage: 1 allocs, 1 frees, 24 bytes allocated
==8665==
==8665== All heap blocks were freed -- no leaks are possible
==8665==
==8665== For counts of detected and suppressed errors, rerun with: -v
==8665== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认已释放所有已分配的内存,并且没有内存错误

简单指针转储/检查

最后,除了使用调试器单步遍历地址外,您还可以编写一个简短的调试路由,以帮助您确定指针处理是否存在问题,以及在何处存在问题。(你根本不需要输出任何东西,如果你愿意的话,你可以用一个等式检查地址)这让你可以一次查看所有指针。只是一个简单的路由到ou
void debugptrs (struct Node *list)
{
    printf ("list pointers:\n\n");
    for (struct Node *iter = list; iter; iter = iter->qnext)
        printf ("prev: %16p    curr: %16p    next: %16p\n", 
                (void*)iter->qprev, (void*)iter, (void*)iter->qnext);
    putchar ('\n');
}
$ ./bin/llarray
list pointers:

prev:            (nil)    curr:   0x7ffd56371910    next:        0x1038010
prev:   0x7ffd56371910    curr:        0x1038010    next:   0x7ffd56371930
prev:        0x1038010    curr:   0x7ffd56371930    next:            (nil)