将元素插入双向链表的末尾

时间:2013-01-19 17:06:20

标签: c list

我正在编写一个程序,可以将元素插入到列表的末尾,然后显示其中一个。它插入正确,但我可以显示指定的一个。

typedef struct Node
{
        int data;
        struct Node *next;
        struct Node *prev;
} node;

void insert(node *head, int data)
{
        node *newNode = (node*) malloc(sizeof(node));
        newNode->data = data;
        newNode->next = NULL;

        if(head == NULL)
        {
            head = newNode;
        }
        else
        {
            while(head != NULL)
                head = head->next;

            head->next = newNode;
            (head->next)->prev = head;
        }
}

void print(node *head, int element)
{
    node *temp = head;
    int count = 0, i = 1;
    while(i < element)
    {
        temp = temp->next;
        i++;
    }
    printf("%d", temp->data);
}

int main()
{
        node *start = (node*) malloc(sizeof(node));
        start = NULL;

        int data1 = 4, data2 = 5;
        insert(start,data1);
        insert(start,data2);

        print(start, 1);
}

为什么不起作用?另外,你能否告诉我我是否正确地做到了这一点?

3 个答案:

答案 0 :(得分:1)

这是因为您按值传递了start指针。这意味着一旦函数返回,insert函数内的任何更改都将丢失。

您可以通过引用传递指针:

void insert(node **head, int data)
{
    /* ... */
    if (*head == NULL)
        *head = newNode;
    else
    {
        /* ... */
    }
}

int main(void)
{
    node *start = NULL;
    insert(&start, 1);
    /* ... */
}

或者从函数返回指针:

node *insert(node *head, int data)
{
    /* ... */
    return head;
}

int main(void)
{
    node *start = NULL;
    start = insert(start, 1);
    insert(start, 2);  /* Do not get the returned pointer, as the returned pointer no longer points to the start of the list */
    /* ... */
}

这两种解决方案的问题在于,如果head不是NULL,则更改为insert,指向最后一个节点之前的节点。在NULL内的循环中,您应该使用临时指针。


作为安全预防措施,您应该检查print功能中的循环中是否没有{{1}}节点。想想如果传递的数字大于列表中的节点数,会发生什么。

答案 1 :(得分:0)

编辑:我跳了几行。

请参阅我的修订评论内联main()的代码段:

node *start = (node*) malloc(sizeof(node));//You allocate memory here. Good.
start = NULL;//Memory leak. 

//Instead of the above two lines use this
node* start=NULL;

int data1 = 4, data2 = 5;
start=insert(start,data1);//If you want to do it statically, why not write insert(start,4)?
insert(start,data2);
....

我建议在print()函数中添加NULL检查。

void print(node *head, int element)
{
    //Null check for the start pointer.
    //If you would have had this here, you'd have never faced such problem.
    if(head == NULL)
    {
      //Handle null
    }
    node *temp = head;
    int count = 0, i = 1;
  ....
}

加起来insert()我会建议:

node* insert(node *head, int data)
{
        node *newNode = (node*) malloc(sizeof(node));
        newNode->data = data;
        newNode->next = NULL;

        if(head == NULL)
        {
            head = newNode;
            return head;
        }
        else
        {
            while(head != NULL)
                head = head->next;

            head->next = newNode;
            (head->next)->prev = head;
            return NULL;
        }
}

希望它有所帮助。

答案 2 :(得分:0)

有一个技巧可以让事情变得更容易,也可以提高你的代码效率!

技巧是使用循环列表,并使“head”节点成为sentinel值。空列表由指向自身的prevnext的单个节点表示。你永远不需要NULL,这种风格大大减少了你需要的特殊外壳。它还允许O(1)访问列表的头部和尾部。从不使用头部的data字段。它在Knuth的“计算机编程艺术”中有所描述。

在这种风格中,你会得到这样的结论:[未经测试]

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

typedef struct Node {
   int data;
   struct Node *next, *prev;
} node;

void insert_list(node *head, int data) {
  node d = {data, head, head->prev};
  node *new_node = malloc(sizeof(node));
  /* TODO: handle malloc failure */
  *new_node = d;
  head->prev->next = new_node;
  head->prev = new_node;
}

node *get_list(node *head, int n) {
  node *node = head;
  int i;
  for (i = 0; i <= n; i++) {
    node = node->next;
    if (node == head) {
      /* TODO: handle out-of-bounds index */
    }
  }
  return node;
}

void print_list(node *head, int i) {
   printf("%d\n", get_list(head, i)->data);
}

node *new_list(void) {
  node *head = malloc(sizeof(node));
  /* TODO: handle malloc failure */
  head->next = head->prev = head;
  return head;
}

int main(int argc, char**argv) {
  node *list = new_list();
  insert_list(list, 10);
  insert_list(list, 20);
  print_list(list, 0);
  print_list(list, 1);
  return 0;
}