链接列表功能?

时间:2016-03-01 06:14:41

标签: c linked-list

所以我正在编写这个函数,使得最小的节点位于链表的末尾。除了最后一个元素之外,它还有效。如果链接列表创建为包含0~9项的节点,则此函数后面的列表为{1,2,3,4,5,6,7,8,0,9}且零不会出现在端。

任何想法为什么?

我的功能;

int connecting(linkk A)
{
    linkk L = A;
    for (int i = 0; i<sizeof(L);i++)
    {
        if (L->item < L->next->item)
        {
            int a = L->item;
            L->item = L->next->item;
            L->next->item = a;
            L = L->next;
        }
        else{L=L->next;}
    }
    return 0;
}

2 个答案:

答案 0 :(得分:1)

让我们从我认为你应该做的不同开始:

  1. 您的函数名称为connecting。鉴于您对该功能要做什么的描述,这是不是一个好名字。
  2. 我可以从使用中推断出linkk是一个typedef&#39; ed指针。在大多数情况下,以这种方式隐藏指针并不是一个好主意。
  3. 您的函数返回int。它总是0。为什么?这没有任何意义。
  4. 因为linkk可能是指向节点的指针,并且您通过值(即它的副本)将头指针传递给函数,所以您无法处理头部的情况你的清单是最低的。要么返回&#34;新&#34;头指针,或传递指向头指针的指针,以便能够修改头指针。
  5. 正如已经建议的那样,您使用sizeof是完全错误的。 sizeof(L)将给出指针的大小(char s),因此在64位系统上可能为8或在32位系统上为4。
  6. 您不是在更改节点,而是在节点之间移动值。如果它是您想要做的,那就没关系,但算法的描述建议您改为移动节点。
  7. 你的功能做得太多,IMO。这可能很难分割,但更好的方法是将查找/提取最小值并将其放在列表的末尾。
  8. 您修改的内容比您原先想要的要多得多。考虑像1, 2, 3, 0, 4这样的列表。使用您的算法,列表将更改为2, 3, 1, 4, 0。这样做不仅对性能有害,而且对于呼叫者来说也是非常令人惊讶的。在编程方面,惊喜并不好!
  9. 所以,让我们一步一步地实现良好的实施:

    struct node {
      int item;
      struct node * next;
    };
    

    我假设您要将包含最小值的节点移动到列表末尾,如说明中所示。尽管如上所述,我还是要将它保留在接收struct node * head指针的单个函数中,以便更接近原始代码。让我们先得出特殊/基本案例:移动空列表的最小元素以及单个元素列表是微不足道的:什么都不做。

    if (head == NULL || head->next == NULL) {
      return head;
    }
    

    我正在回复&#34;新&#34;列表的头部允许调用者更新它自己的头指针。 (如上所述,head只是调用者头部指针的副本,修改它不会对调用站点产生任何影响。)

    因为我们在这里处理单个链接列表,并且实现不应该不必要地遍历列表,我们应该记住我们之前访问过的节点。否则,我们无法从列表中轻松提取节点:

    struct node * follow, * point;
    

    follow紧跟在point

    后面

    最初,我们将该点放在列表的第二个节点上(我们已经检查过列表中至少有2个节点)。因此,follow将指向头部:

    point = head->next;
    follow = head;
    

    由于我们想要找到最小项目,我们需要跟踪列表中已搜索部分的最小值。我们用头节点的值初始化它:

    int currentMinimum = head->item;
    

    现在我们已准备好迭代列表,以便找到包含最小值的节点。但是我们不仅要找到包含最小值的节点,还要找到包含它的节点和它之后的节点,以便能够轻松地提取它。所以,3个指针:

    struct node * predecessor,* minimum,* successor;

    当我们将currentMinimum设置为head项时,我们也应该相应地设置指针:

    predecessor = NULL; // Nothing preceding the head
    minimum = head;
    successor = head->next;
    

    现在让我们进行迭代,将点完全移到列表上,直到最后它落下:

    while (point != NULL) {
      // to be continued
      follow = point;
      point = point->next;
    }
    // when we're here, follow will point to the last node
    

    在每次迭代中,我们需要检查是否找到了比当前最小值更小的值,并最终记住包含它的节点:

    if (point->item < currentMinimum) {
      predecessor = follow;
      minimum = point;
      successor = point->next;
      currentMinimum = point->item;
    }
    

    现在,当我们离开循环时,应该达到以下状态:

    • minimum指向包含最小值的节点。
    • follow指向列表的最后一个节点。
    • 上面两个可能是相同的,这是一个特例!
    • predecessor仍可能是NULL,这是另一个特殊情况!

    首先考虑minimum = follow的特殊情况:在这种情况下,最小值已经在列表的末尾,所以获利!否则,我们需要&#34; cut&#34; minimum之外的节点从列表中出来并将其附加到follow所指向的最后一个节点:

    if (follow != minimum) {
      if (predecessor != NULL) {
        predecessor->next = successor; // Cut out
        minimum->next = NULL; // will be the last node
        follow->next = minimum; // append at end
      } else {
        // to be continued
      }
    }
    

    正如您所看到的,第二个特殊情况需要考虑:如果predecessor仍为NULL,则没有任何项目小于head项目。 (因此,我们也可以测试minimum == head)因此,列表的第一个节点将被移动到最后。我们需要告知来电者这个!

    head = head->next; // Second node is now the first one, though this is not all we need to do, see further down!
    minimum->next = NULL; // Will be the last node
    follow->next = minimum; // Append at end
    

    由于赋值给head只改变了函数参数(它是调用函数的指针的副本),我们需要返回(可能修改过的!)头指针,给调用者能够更新自己的头指针:

    return head;
    

    调用者因此会使用此函数:

    struct node * head = get_a_fancy_list();
    head = move_minimum_to_end(head); // This is our function being called!
    

    最后,需要考虑的事情:正如您所看到的,移动节点(而不是项目)更复杂。我们需要修改至少2个指针才能达到我们想要的效果。相反:移动项目值需要对项目值进行两次修改(迭代更容易)。因此,仅当指针分配比项目分配更快时,移动节点而不是项目才有意义。由于项目属于int类型,因此

    移动项目而不是包含项目的节点要容易得多。首先,我们需要跟踪最小值(值和节点):

    struct node * minimum;
    int currentMinimum;
    

    为了迭代,我们再次使用两个指针。它可以用一个完成,但代码将以这种方式更具可读性:

    struct node * point, * follow;
    

    我们从相同的初始状态开始:

    minimum = head;
    currentMinimum = head->item;
    follow = head;
    point = head->next;
    

    迭代与其他实现类似,迭代步骤也是如此:

    while (point != NULL) {
      if (point->item < currentMinimum) {
        minimum = point;
        currentMinimum = point->item;
      }
      follow = point;
      point = point->next;
    }
    // follow points to the last node now
    

    现在,与前一个实现相同,我们可以将最后一个节点和节点的项目交换为最小值:

    minimum->item = follow->item;
    follow->item = currentMinimum; // contains minimum->item
    

    在上一种方法中检查follow != minimum没有意义:您可以这样做,但是用自己的项目交换节点的项目不会造成任何伤害。 OTOH添加if将添加一个分支,从而可能会降低性能。

    由于我们没有更改列表结构(节点之间的链接),因此不需要考虑更多内容。我们甚至不需要通知来电者新头,因为它永远不会有任何改变。出于样式目的,我会以任何一种方式添加它:

    return head;
    

    好的,现在有点长了,但希望它很容易理解!

答案 1 :(得分:0)

尝试此功能

int connecting(linkk A)
{
 linkk L = A;
  while(L->next!=NULL)
  {
    if (L->item < L->next->item)
    {
        int a = L->item;
        L->item = L->next->item;
        L->next->item = a;

    }

    L=L->next;
  }
  return 0;
 }
相关问题