冒泡在链表C中排序

时间:2015-04-18 19:44:08

标签: c linked-list

知道为什么我的程序在显示正确结果后会崩溃? (即我插入6 2 4 3他返回2 3 4 6但控制台在之后崩溃!)

主要思想是在用户给出整数后对链表进行排序。我试图解决它,就好像它是一个冒泡类型,但由于某种原因,它不是100%可操作的。对不起葡萄牙语的评论!

#define ITEM_TYPE int
typedef struct lnode* List;

typedef struct lnode{
    ITEM_TYPE info;
    List next;
}List_node;

void ordenalista(List lista){

    int contador = 0, i;
    /* lista é uma lista recebida */

    List head = lista; /* termos sempre disponível o início da lista*/
    List actual = NULL; /*lista vazia, ou nó */
    List temp = NULL;

    if(head == NULL || head->next == NULL){ /* caso de lista vazia ou so com 1 elemento*/
        printf("A lista esta vazia ou tem apenas um elemento");
        return 0;
    }

    while(head != NULL){ /* contar quantos elementos tem a lista*/
        contador++;
        head = head->next;
        printf("%d \n", contador);
    }

    for(i=0; i<contador; i++){ /* percorrer todos os elementos da lista*/
        while(head->next != NULL){ /* enquanto não chegarmos ao final da lista*/
            if(head->info > head->next->info){ /* se o valor do atual for maior que o valor do seguinte*/
                temp = head->next;
                head->next = head->next->next; /* não precisamos de usar actual->data, apenas precisamos de mudar os ponteiros*/
                temp->next = head;
            }
        }
    }
}

void ex213(){
    int numero;
    List lista;
    lista = create_list();

    while((scanf("%d",&numero)) == 1){ /* lê da esquerda para a direita. SCANF DÁ 1 SE INSERIR INTEIRO, 0 CASO CONTRÁRIO */
        insertwithoutorder(lista, numero);
    }

    ordenalista(lista);
    printlist(lista);
}

void insertwithoutorder(List lista, ITEM_TYPE it){
    List no;
    List ant, inutil;
    no = (List)malloc(sizeof(List_node));
    if (no != NULL) {
        no->info = it;
        searchwithoutorder(lista, it, &ant, &inutil);
        /*while(ant->next != NULL){
          ant = ant->next;
          }*/
        no->next = NULL;
        ant->next = no;
    }
}

void searchwithoutorder(List lista, ITEM_TYPE chave, List *ant, List*actual){
    *ant = lista; *actual = lista->next;
    while ((*actual) != NULL){
        *ant = *actual;
        *actual = (*actual)->next;
    }
    if ((*actual) != NULL && (*actual)->info != chave)
        *actual = NULL; /* Se elemento não encontrado*/
}

void printlist(List lista){
    List l = lista->next; /* Salta o header */
    while (l){
        printf("%d ", l->info);
        l=l->next;
    }
}

int main(){
    ex213();

    return 0;
}

3 个答案:

答案 0 :(得分:1)

崩溃必须发生在名为printlist()的函数(现在)中,因为在该函数返回后,程序不会执行任何其他操作。

我没有看到printlist()的任何内在错误,但它确实取决于列表处于有效状态。特别是,我最好猜测程序失败的原因是最后一个列表元素的next指针包含垃圾值而不是预期的NULL。您可以通过在调试器中运行程序来验证它。

那么列表可能会如何被破坏?

好吧,你的插入功能看起来不错。它所依赖的searchwithoutorder()函数实际上并不像它的名字所说的那样,但它确实做insertwithoutorder()需要它做的事情。

离开排序函数ordenalista(),这里我有点乱了。我不知道您发布的版本如何进行任何排序。你有一个像这样的while循环:while(head != NULL){...},内部没有breakgoto,所以当控制超出这个循环时,它必须是head == NULL。然后,在不修改head的值的情况下,您将进入如下的循环嵌套:

for(i=0; i<contador; i++) { /* percorrer todos os elementos da lista*/
    while(head->next != NULL) { /* enquanto não chegarmos ao final da lista*/
        ...
    }
}

但是那时headNULL,所以取消它会产生未定义的行为。如果该行为本身并不是崩溃,那么正确猜测和解除引用意味着的指针是一种极不可能的替代方案。此外,您不会修改循环体中的head,因此仍为 NULL。这个循环还有其他问题。

好像所有的东西都不够,你的排序函数也没有好办法改变列表中的哪个元素 - 至少没有一个对调用者有效。

基本上,我不相信你已经准确地描述了这个问题。它必须是您观察到的失败行为与您描述的失败行为不同,或者您提供的代码与您描述的行为不当的程序不对应。

答案 1 :(得分:1)

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

#define ITEM_TYPE int
typedef struct lnode* List;

typedef struct lnode{
    ITEM_TYPE info;
    List next;
} List_node;

List create_list(void){
    //top node unused
    return calloc(1, sizeof(List_node));//note : might NULL != 0
}

List lastNode(List lista){
    while (lista->next != NULL){
        lista = lista->next;
    }
    return lista;
}

void insertwithoutorder(List lista, ITEM_TYPE it){
    List no, ant;
    no = create_list();
    if (no != NULL) {
        no->info = it;
        no->next = NULL;
        ant = lastNode(lista);
        ant->next = no;
    } else {
        printf("failed to create a new node.\n");
    }
}

void ordenalista(List lista){
    List head = lista;
    List actual, neighbor, sentinel = NULL;

    if(head->next == NULL){
        printf("A lista esta vazia\n");
        return ;
    }

    while(head->next != sentinel){
        actual  = head->next;
        neighbor= actual->next;
        while(neighbor != sentinel){
            if(actual->info > neighbor->info){
                ITEM_TYPE temp = actual->info;
                actual->info   = neighbor->info;
                neighbor->info = temp;
            }
            actual  = neighbor;
            neighbor= neighbor->next;
        }
        sentinel = actual;
    }
}

void printlist(List lista){
    List l = lista->next;
    while (l){
        printf("%d ", l->info);
        l=l->next;
    }
    puts("");
}

void ex213(void){
    int numero;
    List lista = create_list();

    while((scanf("%d", &numero)) == 1){
        insertwithoutorder(lista, numero);
    }

    //printlist(lista);
    ordenalista(lista);
    printlist(lista);
    //deallocate ?
}

int main(void){
    ex213();

    return 0;
}

答案 2 :(得分:0)

当询问用户数据时,让用户知道您要求的内容以及如何处理/终止任何输入请求是很有用的。空白行上闪烁的光标告诉用户什么都没有。 (即使它正在测试你,它可以帮助防止错误类型的无意按键)。例如,您的ex213函数在空行上留下一个闪烁的光标,让用户想知道“程序是否挂起?” “它遇到了竞争条件吗?”当询问用户链接列表数据时,一个或两个简单的附加行可以真正起到帮助作用。例如:

void ex213 (void)
{
    int numero;
    List lista = create_list ();

    printf ("\nEnter a number to add to the list [CTRL+D] when done:\n\n");
    while (printf (" data: ") && (scanf ("%d", &numero)) == 1) {
        insertwithoutorder (lista, numero);
    }

    ordenalista (lista);

    printf ("\n\nThe ordered linked-list is:\n\n");
    printlist (lista);
    printf ("\n");

    //deallocate ?
}

<强>输出

$ ./bin/ll_single_sort

Enter a number to add to the list [CTRL+D] when done:

 data: 2
 data: 8
 data: 20
 data: 6
 data: 9
 data: 1
 data:

The ordered linked-list is:

1 2 6 8 9 20

将其添加到BLUEPIXY提供的答案中可提供您正在寻找的结果。