【问题标题】:Can a linked list be sorted by changing the references?可以通过更改引用对链表进行排序吗?
【发布时间】:2017-03-25 12:09:47
【问题描述】:

我正在尝试通过更改节点的引用来使用冒泡排序算法对链表进行排序。我在很多书籍和互联网上进行了搜索,但我只找到了改变节点之间信息部分值的排序方法。 我想要做的是通过更改列表的顺序进行排序,而不是它们之间的值。 这是我的代码。 PS:排序算法不起作用。 它不是合并排序列表的重复,因为它完全是另一种算法。

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#define LINESIZE 128
struct Student {
    float medie;
    char nrMatricol[10];
    char *nume;
    char facltate[6];
};
struct Nod{
    Student stud;
    Nod* next;
};
Nod* inserareNodEnd(Nod *l,Student st)
{
    Nod *nou = (Nod*)malloc(sizeof(Nod));
    nou->next = NULL;//NOU->NEXT=0
    nou->stud = st;
    if (!l) {
        //lista este goala
        return nou;
    }
    else
    {
     //lista contine un nod
        Nod *t = l;
        while (t->next) {
            t = t->next;
        }
        t->next = nou;
        return l;
    }

}
float medieStudenti(Nod *lista) {
    float suma=0;
    int i=0;
    Nod *aux=lista;
    while (aux->next) {
        aux = aux->next;
        suma += aux->stud.medie;
        i++;
    }
    return suma/i;
}
Nod *stergerePrimulNodLista(Nod *l,Student *st) {
    if (l) {
        Nod *aux = l;
        l = l->next;
        aux->next = NULL;
        *st = aux->stud;
        //aux->next = NULL;
        free(aux);

    }
        return l;
}
Nod* sortareLista(Nod *l) {
    Nod *i=l;
    Nod *j=l;
    Nod *aux=l;
    Nod *min=l;
    min = i;
    while (i->next) {

        if (i->stud.medie < min->stud.medie) {
            min = i;
        }
        i = i->next;

    }
    i = l;
    int n = 0;
    while (i->next) {
        j = i->next;
        while (j->next) {
            if (i->stud.medie > j->stud.medie) {
                aux = i->next;
                i->next = j->next;
                j->next = aux;
            }
            j = j->next;
        }
        i = i->next;
    }

    return min;
    //return l;
}
void dezalocare(Nod *lista) {
    Nod *aux;
    aux = lista;
    while (aux->next) {
        lista = aux->next;
        free(aux->stud.nume);
        free(aux);
        aux = lista;
    }
}
void main()
{
    FILE *f;
    Student s;
    Nod *list=NULL;
    f = fopen("fisier.txt", "r");
    char fileBuff[LINESIZE], SEPARATORI[] = { "," };
    char *token;
    while (fgets(fileBuff, LINESIZE, f)) {
        token = strtok(fileBuff, SEPARATORI);
        strcpy(s.nrMatricol, token);
        //extragere token nume student din aceeasi linie
        //salvata in file Buff
        token = strtok(NULL, SEPARATORI);
        s.nume = (char*)malloc(sizeof(char)*strlen(token) + 1);
        strcpy(s.nume, token);
        token = strtok(NULL, SEPARATORI);
        strcpy(s.facltate, token);
        //extragere tokeni medie si conversia tokenului la float
        token = strtok(NULL, SEPARATORI);
        s.medie = atof(token);
        list = inserareNodEnd(list, s);
        printf("%s %s \n", s.nrMatricol, s.nume);
    }
    Nod *tmp = list;
    while (tmp) {
        printf("\nSe afiseaza din lista");
        printf("%s %s \n", tmp->stud.nrMatricol, tmp->stud.nume);
        tmp = tmp->next;
    }

    fclose(f);
    //determinarea mediei pentru studentii din lista
    float media = medieStudenti(list);
    printf("\nMedia este %.2f", media);
    //sortare lista dupa medie(cu modificarea adreselor de legatura)

    //tema dezalocare lista
    //tema dezalocari la nivel de aplicatie
    printf("\nAcesta este Ionel %s %s \n", s.nrMatricol, s.nume);
//  list = stergerePrimulNodLista(list, &s);
    tmp = list;
    while (tmp) {
        printf("\nSe afiseaza din lista");
        printf("%s %s \n", tmp->stud.nrMatricol, tmp->stud.nume);
        tmp = tmp->next;
    }

     tmp = list;
    while (tmp) {
        printf("\nSe afiseaza  lista sortata");
        printf("%s %s \n", tmp->stud.nrMatricol, tmp->stud.nume);
        tmp = tmp->next;
    }
    dezalocare(list);
  }

【问题讨论】:

  • 我将其作为有关合并排序的问题的副本关闭,因为共识似乎是它是通过重新排列链接来对链表进行排序的最佳算法。
  • 它不是重复的。这个问题问如何合并2个列表。请再读一遍 //Merge subroutine to merge两个排序的列表。你现在明白了吗?
  • 注意:struct Nod{ Student stud; Nod* next; }; 是 C 中的语法错误。您使用的是 C++ 编译器吗?
  • Visual Studio。它工作正常
  • @Barmar - OP 似乎特别想实现冒泡排序。至于对链表进行排序的“最佳”算法,虽然我在“重复”线程中的答案中显示自下而上的合并排序对于链表排序来说是最快的,但将列表移动到数组中更快,排序数组,并从排序后的数组创建一个新列表。如果节点足够大,最快的方法是创建一个指向节点的指针数组并对指针数组进行排序,然后创建一个新列表。

标签: c sorting linked-list bubble-sort


【解决方案1】:

根据原始海报的要求,链表的冒泡排序示例。

更新 - 删除 swap,改为使用 pnEnd(指向未排序列表末尾的指针)。

/* bubble sort linked list */

NODE * SortList(NODE *pHead)    /* pHead used as local ptr to start of list */
{
NODE *pEnd = NULL;              /* ptr to end of unsorted part of list */
NODE *pnEnd;                    /* pEnd for next pass */
NODE *pNext;                    /* ptr to next node */
NODE **ppCurr;                  /* ptr to ptr to curr node */
    if(pHead == NULL)           /* return if empty list */
        return pHead;
    do{
        ppCurr = &pHead;        /* set ppCurr to start of list */
        pnEnd = pHead->next;    /* set pnEnd to 2nd node */
        while((pNext = (*ppCurr)->next) != pEnd){
            if((*ppCurr)->data > pNext->data){ /* if out of order swap */
                (*ppCurr)->next = pNext->next;
                pnEnd = pNext->next = *ppCurr;
                *ppCurr = pNext;
            }
            ppCurr = &(*ppCurr)->next;
        }
        pEnd = pnEnd;           /* update pEnd since rest of list is sorted */
    }while(pEnd != pHead->next);
    return pHead;
}

【讨论】:

  • 谢谢!我会在验证后立即将其标记为正确答案
  • @CovrigGeorge-Manuel - 我更新了我的答案,删除了swap,添加了pnEnd
【解决方案2】:

首先:冒泡排序很糟糕。 对于链表来说,就更可怕了…… [对链表进行排序的“自然”方式是合并排序,因为 zip 合并两个已排序的链表很容易]

冒泡排序的基本操作是:

  • { 比较两个相邻节点,并可能交换它们}
  • 并重复此操作,直到没有任何变化。
  • 这意味着最后一遍总是什么都不做。

#include <stdio.h>

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

struct node nodes[] =
{{ nodes+1, 9}
,{ nodes+2, 5}
,{ nodes+3, 0}
,{ nodes+4, 1}
,{ nodes+5, 4}
,{ nodes+6, 7}
,{ nodes+7, 2}
,{ nodes+8, 3}
,{ nodes+9, 8}
,{ NULL   , 6}
        };

void node_printlist(struct node *p) {
for (   ;p; p=p->next) {
        printf("%d\n", p->value);
        }
}

unsigned node_bubblepass(struct node **pp)
{
struct node *one, *two;
unsigned swaps;

for (swaps=0 ; one = *pp; pp=&(*pp)->next) {
        two = one->next;
        if(!two) break;
        if(two->value >= one->value) continue;
                /* wrong order: swap them*/
        one->next = two->next;
        two->next = one;
        *pp = two;
        swaps++;
        }
return swaps;
}

void node_bubblesort(struct node **pp)
{
unsigned swaps;
do      {
        swaps = node_bubblepass(pp);
        } while (swaps);
}

int main(void){
struct node *root =nodes;

printf("Original:\n");
node_printlist(root);

node_bubblesort(&root);

printf("Result:\n");
node_printlist(root);

return 0;
}

在内循环中更新(感谢@rcgldr),当我们碰到之前已经冒泡的项目时,我们可以停止冒泡。

struct node * node_bubblepass_2(struct node **pp, struct node *end)
{
struct node *one, *two;

for ( ; one = *pp; pp=&(*pp)->next) {
        two = one->next;
        if(two == end) break;
        if(two->value >= one->value) continue;
                /* wrong order: swap them*/
        one->next = two->next;
        two->next = one;
        *pp = two;
        }
return one;
}

void node_bubblesort_2(struct node **pp)
{
 struct node *end = NULL;
do      {
        end = node_bubblepass_2(pp, end);
        } while (*pp != end);
}

【讨论】:

  • 由于你的答案已经更新,我删除了我之前的cmets。我稍后会删除此评论。
猜你喜欢
  • 2014-03-02
  • 1970-01-01
  • 1970-01-01
  • 2017-12-13
  • 2016-02-17
  • 1970-01-01
  • 2018-06-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多