Pers.narod.ru. Алгоритмы. Cортировка односвязного списка перестановкой указателей |
Сортировка односвязного списка - одна из самых типовых "головоломных" задач для начинающих.
В принципе, если список состоит, к примеру, из больших структур, теоретически имеет смысл при сортировке не копировать данные, а менять их местами с помощью имеющихся в структуре указателей на связанные элементы...
Но на практике даже простейшая пузырьковая сортировка заметно усложняется связями указателей... поэтому в инете куча неработающих решений и неверных мнений, не стану приводить ссылки на все.
По-моему, вся беда типовых "студенческих" кодов в том, что авторы пытались применить любимый "пузырёк" к списку по аналогии с массивом, а в списке из-за перестановок указателей начиналась путаница...
Метод вставок рулит, что б там не писали на форумах. Остальные комменты в исходнике:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 30
typedef struct student {
unsigned char f[MAX]; //Фамилия
int ekz[4]; //4 оценки
student *next; //Указатель на следующего студента
};
int show (student *head) {
//Показать список, начиная с эл. head и вернуть кол-во записей
int count=0;
while (1) {
printf ("\n%s",head->f);
for (int i=0; i<4; i++) printf (" %d",head->ekz[i]);
count++;
if (!head->next) break;
head=head->next;
}
return count;
}
student *sort (student *ph) {
//Сортируем список по алфавиту (фамилии, полю f) и возвращаем
//указатель на начало измененного списка
student *q,*out=NULL,*p,*pr; //out - выход - сначала пуст
while (ph !=NULL) { //пока не конец входного списка
q = ph; ph = ph->next; //исключить очередной элемент
for (p=out,pr=NULL; p!=NULL && strcmp(q->f,p->f)>0; pr=p,p=p->next);
//ищем, куда включить очередной элемент - тут strcmp
//задает критерий сравнения элементов, в вашей задаче м.б. другой
if (pr==NULL) { q->next=out; out=q; } //включение в начало
else { q->next=p; pr->next=q; } //или после предыдущего
}
return out;
}
void main () {
student group[] = { //В начале фамилии в списке расставлены как в массиве -
//предыдущий элемент показывает на следующий
{"Popov",{4,4,3,3},&group[1]},
{"Belugin",{4,5,3,5},&group[2]},
{"Ivanov",{4,4,5,5},&group[3]},
{"Yakovlev",{5,4,3,2},&group[4]},
{"Petrov",{5,5,5,5},NULL}
};
printf ("\nИсходный список:");
int count=show (&group[0]);
printf ("\nВсего записей: %d",count);
//Сортируем список структур по алфавиту
student *ptr=sort (group);
printf ("\nОтсортированный список:");
show (ptr);
getchar();
}
Проверил в консольном Borland C++ 3.1, работает, завершается без Null pointer assignment, значит, есть надежда, что нормально... хотя вырожденные случаи не смотрел, а писал в спешке, мож чего и не так, тогда жду поправок.
|
|