我试图在两个索引之间动态插入一个节点,这两个索引包含Node类型的结构 . 数组中的第一个元素是头指针,第二个元素是尾 .
我正在尝试动态增长数组的两个索引之间的双链表 . 以下是我到目前为止尝试过的代码 .
我可以动态地创建头部和尾部作为节点,但是根据我要求我这样做 .
保证在 qllentry[0].data
和 qllentry[1].data
的值之间插入 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;
}
正如预期的那样,新节点的插入不会发生在头部和尾部索引之间 . 我添加了一些用于调试的print语句
任何帮助表示赞赏 .
2 回答
虽然保持指向列表头部和尾部的数组(或者指针)是没有错的,但如果使用数组,则在分配地址 keep your array references out of your list operations 之后 . 将
&array[x]
与列表操作混合使用只会引起混淆 . 使用列表时,将其视为列表并忘记数组 .您的主要问题是迭代一个节点到远处寻找插入
new_node
的位置,导致您在停止之前迭代到tail
. 在 node before 上插入new_node
停止迭代 . 你通过测试来做到这一点:( note: 使用
prev = curr->qprev;
旁边的变量进行间接屏蔽级别的隐藏级别只是隐藏细节 - 这可能会在以后增加混乱 . 这是完全合法的,但可以谨慎使用......)现在,您可以集中精力在
&head
和&tail
之间插入new_node
.在任何列表插入中,只需 re-wiring 指向当前节点的指针 - >下一个指向
new_node
,指向下一个节点的指针 - > prev指向new_node
. 要完成插入,new_node->qprev
指向curr
和new_node->qnext
指向curr->next
,例如( note: 解决这个问题的简单方法是拉一张纸和一支2号铅笔,为
new_node
绘制一个块 tail ,然后为 tail 绘制一个块,然后为prev / next指针绘制线条没有new_node
并且带有它的列表 . 然后,在逻辑笔直的情况下,坐下来键盘并将其啄出来 . )此外,您必须 always validate 您的分配,例如
在您编写的任何动态分配内存的代码中,您对分配的任何内存块都有2个职责:(1)始终保留指向内存块起始地址的指针,因此,(2)当它为no时可以释放它需要更久 . 因此,如果您分配它,请在完成后跟踪指向块的指针和
free
. 例如,当完成输出列表值(或在专用循环中)时,您可以释放您分配的内存,类似于:完全放在一起,您可以执行以下操作:
Example Use/Output
Memory Use/Error Check
您必须使用内存错误检查程序,以确保您不会尝试访问内存或写入超出/超出已分配块的范围,尝试读取或基于未初始化值的条件跳转,最后,确认你释放了你分配的所有内存 .
对于Linux
valgrind
是正常的选择 . 每个平台都有类似的记忆检查器 . 它们都很简单易用,只需通过它运行程序即可 .始终确认已释放已分配的所有内存且没有内存错误 .
Simple Pointer Dump/Check
最后,除了使用调试器逐步调试地址之外,您还可以编写一个简短的调试路由,以帮助您选择是否以及在哪里,您的指针处理有任何问题 . (你根本不需要输出任何内容,如果你愿意的话,你可以用相等的方法检查地址)这可以让你一次查看所有指针 . 只需输出节点指针的简单路由通常很有帮助 . 你所需要的只是,例如,
这将提供类似于以下的输出:
我总是觉得从头到尾可视地遍历地址是有帮助的 . 如果节点的任何prev或next不是作为前一行(或下一行)上该节点的地址输出的内容,则您知道问题所在 .
仔细看看,如果您有其他问题,请告诉我 .
以下是基于代码的一些修改代码问题,它按预期打印结果我猜:
dlink.c:
The running result:
Suggestions
唐't mix struct (head, tail) & struct pointer (new_node), it'令人困惑,容易犯错误 .
单个链表可能就足以进行这样的插入,在单个链表中插入元素有一种棘手的方法 .
为了获得良好的性能,您可以分配一个大缓存,然后从缓存中创建新节点 .
编译c代码时,添加
-Wall
选项,这将为您提供更多警告 .