使用malloc创建链接列表

时间:2013-11-18 20:58:59

标签: malloc

我使用malloc来分配列表中的新节点,但是我遇到了代码中某一部分的错误; 以下解决方案仅适用于删除和插入

#include <stdio.h>
#include <malloc.h>

struct Node{
    int value;
    struct Node * Next;
    struct Node * Previous;


};
typedef struct Node Node;
struct List{
    int Count;
    int Total;
    Node * First;
    Node * Last;
};
typedef struct List List;
List Create();
void Add(List a,int value);
void Remove(List a,Node * b);
List Create()
{
    List a;
    a.Count=0;
    return a;

}

void Add(List a,int value)
{
    Node * b = (Node *)malloc(sizeof(Node));
    if(b==NULL)
        printf("Memory allocation error \n");
    b->value=value;
    if(a.Count==0)
    {
        b->Next=NULL;
        b->Previous=NULL;
        a.First=b;

    }
    else
    {
        b->Next=NULL;
        b->Previous=a.Last;
        a.Last->Next=b;

    }
    ++a.Count;
    a.Total+=value;
    a.Last=b;
    }
void Remove(List a,Node * b)
{
    if(a.Count>1)
    {
        if(a.Last==b)
        {
            b->Previous->Next=NULL;
        }
        else
        {
            b->Previous->Next=b->Next;
            b->Next->Previous=b->Previous;
        }

        }
    free(b);
    }

在删除功能中,在最后一个条件下,我不确定是否使用b-&gt; Next-&gt;上一个是可以的,并且可以使用;当使用 - &gt;运算符,我是关于节点指针还是它的值?

1 个答案:

答案 0 :(得分:0)

简短回答:是的,b->Next->Previous很好 - 它是struct Node*,就像右侧b->Previous一样。

我认为您的错误在于Count的处理:它增加Add(),但Remove()不会减少它。事实上,由于列表本身只需知道它是否为空,您可以将其删除,而不是查看a.First == NULL。 (您的a.Count == 1测试同样可以替换为a.First != NULL && a.First->Next == NULL测试。)

如果您在API中承诺Count,则可以在列表本身正常工作时将其添加回来。相同的“删除然后添加”可能对Total有用。把它们都想象成缓存。

更好的解决方案是实现循环列表:

struct List
{
    Node Anchor;
    //...
};

List Create()
{
    List l;
    l.Anchor.Next = l.Anchor.Previous = &l;
    return l;
}

bool IsEmpty(List const* l)
{
    // Both or neither point at 'l'.
    assert((l->Anchor.Next == l) == (l->Anchor.Previous == l));
    return l->Anchor.Next == l;
}

// Add a node 'n' to some list after 'ln'.
void AddAfter(Node* n, Node* ln)
{
    n->Previous = ln;
    n->Next = ln->Next;
    n->Next->Previous = n->Previous->Next = n;
}

Node* Remove(Node* n)
{
   n->Previous->Next = n->Next;
   n->Next->Previous = n->Previous;
   n->Next = n->Previous = n;  // nice and proper
   return x;
}

现在您需要特殊情况下的空列表。我让Remove()返回节点本身,以便在列表之间移动节点(AddAfter(Remove(somenode), &otherlist.Anchor))或删除和删除注释(free(Remove(somenode)))。

这里的一个瑕疵是我的Anchor节点现在浪费空间用于永远不会被使用的数据 - 但这很容易解决。