【问题标题】:Correct way to delete a node in doubly circular linked list删除双循环链表中节点的正确方法
【发布时间】:2018-10-16 11:55:48
【问题描述】:

此代码的目的是管理插入和删除以及可视化。我只想知道我是否正确地做所有事情,让我知道是否有更多可能的方法来做到这一点。这是我的第一次尝试,我没有遵循任何教程。

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



typedef struct Node {
  int n;
  struct Node *next;
  struct Node *prev;

}TNode;
typedef TNode* Node;



void NewNode(Node *pp, int n)
{
  Node temp, last;

  temp = (Node)malloc(sizeof(struct Node));

  temp->n = n;
  temp->next = temp;
  temp->prev = temp;

  if(*pp != NULL)
    {
      last = (*pp)->prev;
      temp->next = (*pp);
      temp->prev = last;
      last->next = (*pp)->prev = temp;
    }

  *pp = temp;

}

void ViewList(Node head)
{
  if(head == NULL)
  {
    return;
  }
  Node node = head->prev;
 do
  {
    printf("Curr: %d\n", node->n);
    node = node->prev;
  }while(node != head->prev);
}

void ReadData(Node * head, int * n)
{
  printf("\nInsert a number:");
  scanf("%d", n);
  NewNode(head, *n);
}

Node SearchNode(Node head)
{
  int d;
  printf("\nElement to Delete:");
  scanf("%d", &d);

  while(head != NULL)
    {
      if(head->n == d)
        {
          return head;
        }
      head = head->next;
    }
  printf("\nNo Element [%d] Found", d);
  return NULL;
}

void Delete(Node * head)
{
  Node del = SearchNode(*head);

       if(*head == NULL || del == NULL)
        {
          return;
        }
      if(*head == del && del->next == *head)
      {
        *head = NULL;
        free(del);
        return;
      }
      if(*head == del)
      {
        *head = del->next;
        del->prev->next = *head;
        (*head)->prev = del->prev;
        free(del);
        return;
      }
      if((*head)->prev == del)
        {
          (*head)->prev = del->prev;
          del->prev->next = *head;
          free(del);
          return;
        }
        del->next->prev = del->prev;
        del->prev->next = del->next;
        free(del);
}

int Menu()
{
  int c;

  printf("\n*** M E N U ***\n"
     "1 - New Node\n"
     "2 - View List\n"
     "3 - Delete\n"
     "0 - Exit\n"
     "\n>> ");
  scanf(" %d", &c);

  return c;
}

int main()
{
  int c,n;
  Node head = NULL;

  do {
    c = Menu();

    switch (c)
    {
      case 1: ReadData(&head, &n); break;
      case 2: ViewList(head); break;
      case 3: Delete(&head); break;
      default: c = 0;
    }

  } while (c != 0);

  return 0;
}

我如何测试这是否是一个真正的循环双向链表而不是一个简单的双向链表?

【问题讨论】:

  • 对于删除一个节点,你不需要知道它是否是一个循环列表,只要在你取消引用它们之前确保所有指针都是非空的(并记住要 initialize 所有指向 null 的指针)。
  • 我不知道这是否是您要求的,但我发现有人似乎已经在 github 中完成了此算法。也许这也可以帮助您比较Circular Double Linked List in C
  • 至于移除本身,我建议你先在纸上做:画一些正方形(代表节点)和它们之间的箭头(代表链接)。在尝试使用代码之前,请尝试找出一种在纸上“取消链接”的方法。当您开始编码时,请分小步进行,在每个步骤之间进行测试和调试。
  • 您的问题是:“删除双循环链表中节点的正确方法是什么?” 还是 “我如何测试这是否是一个真正的循环双向链表而不是一个简单的双向链表?” 这是两个非常不同的问题。顺便说一句,删除一个你不需要知道它是否是循环列表的节点。
  • 顺便说一句:你隐藏的指针类型和 typedefs 只会增加混乱。我会把它们放在一起。

标签: c nodes doubly-linked-list circular-list


【解决方案1】:

您的程序运行良好,我检测到的唯一真正的错误是在SearchNode:如果列表中不存在该元素,您将进入无限循环。您的列表显然是一个循环列表,因此您需要检查您是否已经回到函数中的头部,这意味着您要搜索的元素不在列表中:

修正版:

Node SearchNode(Node head)
{
  int d;
  printf("\nElement to Delete:");
  scanf("%d", &d);

  Node start = head;     // remember where we started

  while (head != NULL)
  {
    if (head->n == d)
    {
      return head;
    }
    head = head->next;

    if (head == start)   // if we are back to where we started
      break;             // the element hasn't been found and we stop the loop
  }

  printf("\nNo Element [%d] Found", d);
  return NULL;
}

还有一些设计缺陷,并不妨碍程序正常工作:

其中之一是:n 变量不在ReadData 之外使用,因此在main 中声明它并将其指针传递给ReadData 是没有意义的。

修正版:

void ReadData(Node * head)
{
  int n;  // declare n locally
  printf("\nInsert a number:");
  scanf("%d", &n);
  NewNode(head, n);
}

这样称呼它:ReadData(&amp;head) 并从main 中删除int n;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多