【问题标题】:Basic Issues with Linked Lists链表的基本问题
【发布时间】:2010-09-12 14:05:16
【问题描述】:

我正在处理 CS1 的家庭作业,我几乎完成了,但与我尝试实现的一些功能相关的错误不断出现。赋值是使用链表对大整数进行经典的加法和减法。我的问题不在于程序的任何数学功能,而是让链接列表在完成后正确打印。我很确定大部分问题都存在于stripLeadingZeros();功能如下。

/*
 * Function stripLeadingZeros
 * 
 * @Parameter STRUCT** Integer
 * 
 * Step through a linked list, recursively unlinking 
 * all leading zeros and making the first
 * non-zero integer the head of the list.
 */
struct integer* stripLeadingZeros( struct integer *p )
{
    // Are we at the end of the list?
    if( p == NULL ) return NULL;

    // Are we deleting the current node?
    if( p->digit == 0 )
    {
        struct integer *pNext;

        pNext = p->next;

        // Deallocate the node
        free( p );

        // Return the pointer to the next node
        return pNext;
    }

    // Recurse to make sure next node is not 0
    p->next = stripLeadingZeros( p->next );

        return p;
}

---///---

/*
 * Function print
 *
 * @Parameter STRUCT* Integer
 *
 * Given a linked list, will traverse through
 * the nodes and print out, one at a time,
 * the digits comprising the struct integer that the
 * linked list represents.
 *
 * TODO: Print to file
 */
void print( struct integer *p )
{   
    struct integer *head = p;
    reverse( &p );
    p = stripLeadingZeros( p );

    while( p )
    {
        fprintf(outFile, "%d", p->digit);
        p = p->next;
    }

    reverse( &head );
}

---///---

/*
 * Function reverse
 * 
 * @Parameter STRUCT** Integer
 * 
 * Recursively reverses a linked list by
 * finding the tail each time, and linking the
 * tail to the node before it.
 */
void reverse (struct integer **p)
{
    /*
     * Example p: 1->2->3->4->NULL
     */
    if( (*p)->next == NULL ) return;

    struct integer *pCurr = *p, *i, *pTail;

    // Make pCurr into the tail
    while( pCurr->next )
    {
        i = pCurr;
        pCurr = pCurr->next;
    }

    // Syntactic Sugar
    pTail = pCurr;

    pTail->next = i;
    /*
     * p now looks like:
     * 1->2->3<->4
     */

    i->next = NULL;
    /*
     * p now looks like:
     * 1 -> 2 -> 3 <- 4
     *           |
     *           v
     *          NULL
     */

    reverse( p ); // Recurse using p: 1 -> 2 -> 3;
    *p = i;   
}

我目前得到的整个程序的输出是:

888888888 + 222222222 = 11111111
000000000 - 999999999 = 000000001
000000000 - 999999999 = 000000001

而预期的输出是

8888888888 + 2222222222 = 11111111110
10000000000 – 9999999999 = 1
10000000000 – 9999999999 = 1

任何人都可以提供的任何帮助都很棒;我已经为此工作了很长时间,如果我有任何头发,我现在已经把它拔掉了。

EDIT我的read_integer函数如下:

/*
 * Function read_integer
 *
 * @Parameter CHAR* stringInt
 *
 * Parameter contains a string representing a struct integer.
 * Tokenizes the string by each character, converts each char
 * into an integer, and constructs a backwards linked list out
 * of the digits.
 *
 * @Return STRUCT* Integer
 */
struct integer* read_integer( char* stringInt )
{
    int i, n;
    struct integer *curr, *head;

    int numDigits = strlen( stringInt ); // Find the length of the struct integer
    head = NULL;

    for( i = 0; i < numDigits; i++ )
    {
        n = stringInt[i] - '0'; // Convert char to an integer

        curr = (struct integer *) malloc (sizeof( struct integer )); // Allocate memory for node
        curr->digit = n; // Digit of current node is assigned to n
        curr->next = head; // Move to the next node in the list.
        head = curr; // Move head up to the front of the list.
    }

    return head; // Return a pointer to the first node in the list.
} 

【问题讨论】:

  • @Andrew,与昨天的问题相同的 cmets 适用:您遇到的错误是什么以及代码在哪里?你有所有警告吗?编译器说什么?您尝试了什么... 清楚而系统地写下这些内容将使您有机会几乎自己找到错误
  • 哈哈哈天哪,对不起。我的睡眠几乎为零。我修复了这个问题,包括输出与预期输出。
  • 嗨,只是对您的 stripLeadingZeros 函数的猜测,实际上您在 while 循环中只删除了一个零,因为您通过在每个循环循环中返回 pNext 而跳出函数,没有任何条件。第二个猜测(这可能是错误的 - 取决于您的实现):您在删除前导零之前反转列表,因此如果数字处于“正确”顺序,则从错误的一端删除零。
  • 如果您在第一个循环后返回,为什么在 stripLeadingZeros 中使用 while 循环而不是 if
  • @Cristian 实际上我刚刚从if 切换到while 只是为了看看它是否有效。 ://

标签: c linked-list


【解决方案1】:

在“0004”上模拟 stripLeadingZeros()。

它不起作用。您还忽略了一个边缘情况:如果它只是“0”怎么办。在这种情况下,您不能去除唯一的 0。

正确代码:

struct integer* stripLeadingZeros( struct integer *p )
{
    // Are we at the end of the list?
    if( p == NULL ) return NULL;

    // Are we deleting the current node? Also it should not strip last 0
    if( p->digit == 0 && p->next != NULL)
    {
        struct integer *pNext;

        pNext = p->next;

        // Deallocate the node
        free( p );

        // Try to strip zeros on pointer to the next node and return that pointer
        return stripLeadingZeros(pNext);
    }
    return p;
}

【讨论】:

    【解决方案2】:

    考虑这个函数的控制流程:

    struct integer* stripLeadingZeros( struct integer *p )
    {
        // Are we at the end of the list?
        if( p == NULL ) return NULL;
    
        // Are we deleting the current node?
        if( p->digit == 0 )
        {
            struct integer *pNext;
    
            pNext = p->next;
    
            // Deallocate the node
            free( p );
    
            // Return the pointer to the next node
            return pNext;
        }
    
        // Recurse to make sure next node is not 0
        p->next = stripLeadingZeros( p->next );
    
        return p;
    }
    

    p 以零开头时会发生什么?它进入if 语句,删除前导零,然后返回。它确实递归,因为您已经在if 语句中返回。这意味着stripLeadingZeros 最多会删除一个零。

    现在p 以 1 开头会发生什么?它跳过if 语句,但它确实递归。这也是错误的,因为一旦看到 1,您就想停止删除零,因为它们不再领先。

    所以这个函数实际上正在做的是删除它遇到的第一个零,无论是否领先,然后停止。这不是你想要的。

    您希望在删除零后进行递归,并且仅在删除零后,因此将递归调用移至if 语句。换句话说,将return pNext;替换为return stripLeadingZeros(pNext);,并从循环外移除递归。

    【讨论】:

      【解决方案3】:

      您可以通过将原始列表反转为另一个列表来改进您的反向功能:

      void reverse(struct integer** p)
      {
          struct integer* old = *p;
          struct integer* new = NULL;
      
          while(old != NULL)
          {
              struct integer* oldNext = old->next;
              old->next = new;
              new = old;
      
              old = oldNext;
          }
          *p = new;
      }
      

      【讨论】:

        【解决方案4】:
        stripLeadingZeros( nodeptr s )
        {
        if(s!=NULL)
            stripLeadingZeros(s->next);
               if((s!=NULL)&&s->data==0&&on)
               flg=1;
               if((s!=NULL)&&(s->data!=0)&&flg)
               on=0,flg=0,s->next=NULL;
               if(flg)
         s->next=NULL;
        }
        

        这是我去除前导零的代码,on 和 flg 的初始值分别为 1 和 0。

        http://programmingconsole.blogspot.in/2013/10/all-basic-calculator-functions-on-large.html

        【讨论】:

          【解决方案5】:

          在您当前版本的stripLeadingZeros 中,您可以用if 语句替换while 循环,结果将相同。也许这就是问题所在。

          while (1) {
              /* ... */
              return 0; /* this "infinite loop" only runs once */
          }
          

          比较

          if (1) {
              /* ... */
              return 0;
          }
          

          【讨论】:

          • 谢谢,但遗憾的是这不会影响任何事情。 :(
          猜你喜欢
          • 2020-12-05
          • 1970-01-01
          • 2014-10-15
          • 1970-01-01
          • 2011-10-21
          • 2020-03-07
          • 1970-01-01
          • 2016-12-30
          • 2021-09-26
          相关资源
          最近更新 更多