链接列表的基本问题

时间:2010-09-12 14:05:17

标签: c linked-list

我正在为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

任何人都可以给予的任何帮助都会很棒;我一直在研究这个问题已经很长时间了,如果我有任何头发,我现在就把它拉出来。

编辑我的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.
} 

5 个答案:

答案 0 :(得分:5)

在“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;
}

答案 1 :(得分: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以一个开头时会发生什么?它会跳过if语句,但递归。这也是错误的,因为一旦看到一个,你想停止删除零,因为它们不再领先。

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

删除零后,您想要递归,而在删除零之后只想 ,所以将递归调用移到if语句中。换句话说,将return pNext;替换为return stripLeadingZeros(pNext);,并从循环外部删除递归。

答案 2 :(得分:1)

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

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;
}

答案 3 :(得分:1)

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

答案 4 :(得分:0)

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

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

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