C 双链表问题?

C 双链表问题?,c,list,linked-list,structure,C,List,Linked List,Structure,我创建了一个我认为是双重链接的列表。其想法是将每行输入的单词的输出反转为一行,因此: Hello\nAll\n. .\nAll\nHello 我们的想法是遍历我的列表,直到找到'\n',然后朝相反的方向打印,回到我离开的地方,继续遍历,直到找到另一行,然后再次向前打印,等等 然而,我目前的实现我似乎无法开始工作,而且我遇到了困难,我们非常感谢您的提示和提示 typedef struct L { char val; struct L *next; struct L *prev; }List;

我创建了一个我认为是双重链接的列表。其想法是将每行输入的单词的输出反转为一行,因此:

Hello\nAll\n.
.\nAll\nHello
我们的想法是遍历我的列表,直到找到
'\n'
,然后朝相反的方向打印,回到我离开的地方,继续遍历,直到找到另一行,然后再次向前打印,等等

然而,我目前的实现我似乎无法开始工作,而且我遇到了困难,我们非常感谢您的提示和提示

typedef struct L { 
char val;
struct L *next;
struct L *prev;
}List;

List *insertList(char val, List *t1 );
List *createList(void);

int main(void) {
  List *z = createList();
  List *pos = z;
  while (pos != NULL) {
    while ( z->val != '\n' ) {
        if (z == NULL)
            break;
            z = z->next;
            pos = z;
}
    while (z != NULL) {
        printf("%c", z->val);
        z = z->prev;
    }
}
return 0;
}
List *createList(void) {
  List *h = NULL;
  char c;
  do { 
    c =(char)getchar();
    h = insertList(c, h);
  }while(c != '.');
  return h;
 }
List *insertList( char val, List *t1) {
  List *t = calloc(1, sizeof( List ));
  t->prev = NULL;
  t->val = val;
  t->next = t1;
    if (t1 != NULL) {
     t1->prev = t;
  }
return t;
}

改为尝试这些while循环[编辑以注意Chris关于检查LL结尾的评论]:

while (pos != NULL) {
    while (z != NULL) {
        // if you've reached the line feed or the end of the linked list
        if ((z->val == '\n') || (z->next == NULL)) {
            pos = z->next; // store list position just after this char for next time through
            break;
        }
        z = z->next;
    }
    while (z != NULL) {
        printf("%c", z->val);
        z = z->prev;
        // don't print more than just this word!:
        if ((z != NULL) && (z->val == '\n'))
            break;
    }
    // reset z for top inner while loop
    z = pos;
}
基本问题是,当外部while循环缠绕时,z没有复位;第二个问题是链表的末尾并没有跳出第一个内部while循环;第三个问题是第二个内部循环,而循环并没有检查它正在打印的字的结尾


您还需要在末尾释放链表,否则将导致内存泄漏。您还应该检查
calloc()
的返回值,以确保它没有返回null。

请尝试这些while循环[编辑以注意Chris关于检查LL结尾的注释]:

while (pos != NULL) {
    while (z != NULL) {
        // if you've reached the line feed or the end of the linked list
        if ((z->val == '\n') || (z->next == NULL)) {
            pos = z->next; // store list position just after this char for next time through
            break;
        }
        z = z->next;
    }
    while (z != NULL) {
        printf("%c", z->val);
        z = z->prev;
        // don't print more than just this word!:
        if ((z != NULL) && (z->val == '\n'))
            break;
    }
    // reset z for top inner while loop
    z = pos;
}
基本问题是,当外部while循环缠绕时,z没有复位;第二个问题是链表的末尾并没有跳出第一个内部while循环;第三个问题是第二个内部循环,而循环并没有检查它正在打印的字的结尾


您还需要在末尾释放链表,否则将导致内存泄漏。您还应该检查
calloc()
的返回值,以确保它没有返回null。

我认为您的结构需要更改,没有理由使用双链接列表来解决您的问题

您的结构应该包含

struct node {
char *word;
struct node *next;
};
那么您的主循环应该是这样的:

1) Read character data until delimiter into expandable buffer. Add NULL string terminator.
2) When delimiter is reached create node that points to buffer.
3) Insert NODE at HEAD of list.
4) When '.' is reached print each string starting from head of list.

我认为你的结构需要改变,没有理由用一个双链接列表来解决你的问题

您的结构应该包含

struct node {
char *word;
struct node *next;
};
那么您的主循环应该是这样的:

1) Read character data until delimiter into expandable buffer. Add NULL string terminator.
2) When delimiter is reached create node that points to buffer.
3) Insert NODE at HEAD of list.
4) When '.' is reached print each string starting from head of list.

好的,我已经有时间了解为什么我的第一个答案不起作用了——如果您通过调试器运行代码,那么有一些显而易见的事情。这是一个完整的工作版本。它可能会被优化很多,但它遵循与原始代码相同的结构,因此希望您能够遵循它:

typedef struct L { 
    char val;
    struct L *next;
    struct L *prev;
} List;

List* insertList( char val, List *t1 ) {
    List *t = calloc(1, sizeof( List ));
    t->prev = NULL;
    t->val = val;
    t->next = t1;
    if (t1 != NULL)
        t1->prev = t;
    return t;
}

List* createList( void ) {
    List *h = NULL;
    char c;

    do {
        c =(char)getchar();
        h = insertList( c, h );
    } while (c != '.');

    return h;
}

void freeList( List *list ) {
    // free the linked list
    if (list != NULL) {
        freeList( list->next );
        free( list );
    }
}

int main( void ) {
    // create list
    List *head = createList();
    List *pos = head, *currentChar = NULL, *wordStart = NULL;

    while (pos != NULL)
    {
        // find next word
        wordStart = NULL;
        while (pos != NULL)
        {
            // gone past the beginning of a word yet?
            if ((pos->val == '\n') || (pos->next == NULL)) 
            {
                wordStart = (pos->next == NULL) ? pos : pos->prev; // note where this word starts
                pos = pos->next; // jump over \n, or go to end of list (null), for next time into this loop
                break; // jump out of this loop so we can output the word
            }
            else // not found end of word yet - on to next char
                pos = pos->next;
        }

        // have we found a word? if so, output it!
        if (wordStart != NULL)
        {
            currentChar = wordStart; // start at first char in the word
            while (currentChar != NULL)
            {
                printf( "%c", currentChar->val ); // output this char
                currentChar = currentChar->prev; // on to next char in the word
                if ((currentChar != NULL) && (currentChar->val == '\n')) 
                    break; // stop after last char of the word
            }
            // print the line-feed just before wordStart (if there is one)
            if (wordStart->next != NULL)
                printf( "%c", wordStart->next->val );
        }
        else // we've reached the end - stop
            break; // not really necessary - pos should be NULL at this point anyway
    }

    freeList( head ); // free linked list memory

    return 0;
}

主要的变化是如何输出换行符。我意识到这不是你需要的每个单词后面的换行符,而是它前面的换行符(一点也不符合逻辑——我想知道这是否是问题的初衷?)。但它现在输出的正是您所需要的。我还为您添加了一个函数,可以在末尾释放链表内存。:)

好的,我已经有时间了解为什么我的第一个答案不起作用了——如果您通过调试器运行代码,那么有一些显而易见的事情。这是一个完整的工作版本。它可能会被优化很多,但它遵循与原始代码相同的结构,因此希望您能够遵循它:

typedef struct L { 
    char val;
    struct L *next;
    struct L *prev;
} List;

List* insertList( char val, List *t1 ) {
    List *t = calloc(1, sizeof( List ));
    t->prev = NULL;
    t->val = val;
    t->next = t1;
    if (t1 != NULL)
        t1->prev = t;
    return t;
}

List* createList( void ) {
    List *h = NULL;
    char c;

    do {
        c =(char)getchar();
        h = insertList( c, h );
    } while (c != '.');

    return h;
}

void freeList( List *list ) {
    // free the linked list
    if (list != NULL) {
        freeList( list->next );
        free( list );
    }
}

int main( void ) {
    // create list
    List *head = createList();
    List *pos = head, *currentChar = NULL, *wordStart = NULL;

    while (pos != NULL)
    {
        // find next word
        wordStart = NULL;
        while (pos != NULL)
        {
            // gone past the beginning of a word yet?
            if ((pos->val == '\n') || (pos->next == NULL)) 
            {
                wordStart = (pos->next == NULL) ? pos : pos->prev; // note where this word starts
                pos = pos->next; // jump over \n, or go to end of list (null), for next time into this loop
                break; // jump out of this loop so we can output the word
            }
            else // not found end of word yet - on to next char
                pos = pos->next;
        }

        // have we found a word? if so, output it!
        if (wordStart != NULL)
        {
            currentChar = wordStart; // start at first char in the word
            while (currentChar != NULL)
            {
                printf( "%c", currentChar->val ); // output this char
                currentChar = currentChar->prev; // on to next char in the word
                if ((currentChar != NULL) && (currentChar->val == '\n')) 
                    break; // stop after last char of the word
            }
            // print the line-feed just before wordStart (if there is one)
            if (wordStart->next != NULL)
                printf( "%c", wordStart->next->val );
        }
        else // we've reached the end - stop
            break; // not really necessary - pos should be NULL at this point anyway
    }

    freeList( head ); // free linked list memory

    return 0;
}
主要的变化是如何输出换行符。我意识到这不是你需要的每个单词后面的换行符,而是它前面的换行符(一点也不符合逻辑——我想知道这是否是问题的初衷?)。但它现在输出的正是您所需要的。我还为您添加了一个函数,可以在末尾释放链表内存。:)

}

//删除函数

int removeNode(int key){
DNODE *curr;
if(first==NULL){ //if node is creating first time
    printf("\n\nList is Empty");
    return -1;    
}
curr=first;
if(first->data==key){  //if first node has key
   first=first->next;
   first->prev=NULL;
   curr->next = NULL;
   free(curr);
   return;
}

while(curr && curr->data!=key){
    curr=curr->next;   
} 
if(!curr){   //if search not found then curr will be NULL, 
    return -1;
}

curr->prev->next=curr->next;
curr->next->prev=curr->prev;
curr->next = curr->prev = NULL;
printf("\n\n%d is Successfully Deleted: ",curr->data);
free(curr);
return;
}

void display(){
DNODE *curr;
if(first==NULL)
    printf("\n\nNothing to Display\n\n");
curr=first;
printf("\n\n\tElement in List\n\n\t");
while(curr){
    printf("%d ",curr->data);
    curr=curr->next;    
  }
 }
 main(){
int ele,ch,key;
do{
    printf("\nEnter Your Choice: \n");
    printf("1-Insert First\t2-Insert Last\n3-Insert Before\t4-Insert After\n5-Remove  \t6-Display\n");
    scanf("%d",&ch);
    switch(ch){
        case 1:
            printf("Enter Element To Insert: ");
            scanf("%d",&ele);
            insertFirst(ele);
            break;  
        case 2:
            printf("Enter Element To Insert: ");
            scanf("%d",&ele);
            insertLast(ele);
            break;
         case 3:
            printf("Enter Element To Insert: ");
            scanf("%d",&ele);
            printf("\nEnter Key: ");
            scanf("%d",&key);
            insertBefore(ele,key);
            break;  
        case 4:
            printf("Enter Element To Insert: ");
            scanf("%d",&ele);
            printf("\nEnter Key: ");
            scanf("%d",&key);
            insertAfter(ele,key);
            break; 
        case 5:
            printf("Enter Key to Delete: ");
            fflush(stdin);
            scanf("%d",&key);
            removeNode(key);
            break;
        case 6:
            display();
            break;
    }  
}while(ch!=7);
getch();
return 0;    
}

}

//删除函数

int removeNode(int key){
DNODE *curr;
if(first==NULL){ //if node is creating first time
    printf("\n\nList is Empty");
    return -1;    
}
curr=first;
if(first->data==key){  //if first node has key
   first=first->next;
   first->prev=NULL;
   curr->next = NULL;
   free(curr);
   return;
}

while(curr && curr->data!=key){
    curr=curr->next;   
} 
if(!curr){   //if search not found then curr will be NULL, 
    return -1;
}

curr->prev->next=curr->next;
curr->next->prev=curr->prev;
curr->next = curr->prev = NULL;
printf("\n\n%d is Successfully Deleted: ",curr->data);
free(curr);
return;
}

void display(){
DNODE *curr;
if(first==NULL)
    printf("\n\nNothing to Display\n\n");
curr=first;
printf("\n\n\tElement in List\n\n\t");
while(curr){
    printf("%d ",curr->data);
    curr=curr->next;    
  }
 }
 main(){
int ele,ch,key;
do{
    printf("\nEnter Your Choice: \n");
    printf("1-Insert First\t2-Insert Last\n3-Insert Before\t4-Insert After\n5-Remove  \t6-Display\n");
    scanf("%d",&ch);
    switch(ch){
        case 1:
            printf("Enter Element To Insert: ");
            scanf("%d",&ele);
            insertFirst(ele);
            break;  
        case 2:
            printf("Enter Element To Insert: ");
            scanf("%d",&ele);
            insertLast(ele);
            break;
         case 3:
            printf("Enter Element To Insert: ");
            scanf("%d",&ele);
            printf("\nEnter Key: ");
            scanf("%d",&key);
            insertBefore(ele,key);
            break;  
        case 4:
            printf("Enter Element To Insert: ");
            scanf("%d",&ele);
            printf("\nEnter Key: ");
            scanf("%d",&key);
            insertAfter(ele,key);
            break; 
        case 5:
            printf("Enter Key to Delete: ");
            fflush(stdin);
            scanf("%d",&key);
            removeNode(key);
            break;
        case 6:
            display();
            break;
    }  
}while(ch!=7);
getch();
return 0;    


}

在此操作过程中,您是否可以更改列表结构?如果打印完一行后,可以释放所有节点并将其从列表中删除,可能会简化一些事情。不,我根本无法更改结构,这太愚蠢了。这并不是你的错,但是链表的主要优点是你可以对元素重新排序。(另外,如果这是家庭作业,你应该添加家庭作业标签。我们仍然会帮助你,但如果你应该学习,我们不想为你做所有的工作。)@user1048116你能澄清一下什么是不允许改变结构吗。您是否可以更改createList的功能,或者不允许对其进行修改。在此操作期间,您是否可以更改列表结构?如果打印完一行后,可以释放所有节点并将其从列表中删除,可能会简化一些事情。不,我根本无法更改结构,这太愚蠢了。这并不是你的错,但是链表的主要优点是你可以对元素重新排序。(另外,如果这是家庭作业,你应该添加家庭作业标签。我们仍然会帮助你,但如果你应该学习,我们不想为你做所有的工作。)@user1048116你能澄清一下什么是不允许改变结构吗。您是否可以更改createList的功能,或者不允许修改该功能。尽管当我输入Damien\nHello\n之类的内容时,您肯定会继续。我将其输出成功。\n错误\n然后程序崩溃。您需要处理输入的开头,它不是以
'\n'
字符结尾的,但仍然需要打印。但这已经很接近了。这是我需要在一个单独的循环中实现的东西,还是我可以集成到上面的链接列表中的东西?看看你创建的链接列表,不是所有的字符都按相反的顺序插入吗?另外,您能调试程序以定位崩溃点吗?还要注意的是,main()完成时并没有释放链表,这是内存泄漏。哦,不要检查calloc()的返回,如果操作系统内存不足,它可能会失败。克里斯,任何可能的小提示,我真的很难理解为了打印最后一个字要添加的假设语句!肯定会进步,尽管当我像Damien\nHello\n这样进入时。我将其输出成功。\n错误\n然后程序崩溃。您需要处理输入的开头,它不是以
'\n'
字符结尾的,但仍然需要打印。但这很接近,我会这么做吗