Замена элементов в связанном списке

#c #list #loops #struct #linked-list

#c #Список #петли #структура #связанный список

Вопрос:

Так что я столкнулся с небольшой проблемой с моей функцией сортировки. В то время как он делает то, что должен делать во втором крайнем случае, элементы меняются местами, а затем непрерывно меняются местами.

Пример здесь происходит, когда Свен(25) и Боб(22) встречаются.

 void sortPerson(person *pers, person* newPerson) {  if(pers == NULL || pers-gt;next == NULL)  {  printf("List is emtpy");  return;  }  person* tempValue;  person* prev = pers;  person* curr = pers-gt;next;  //person* newValue = pers;   while(prev != NULL amp;amp; curr != NULL)  {  //first edge case  //adds a new person  if(prev-gt;age lt; newPerson-gt;age)  {  newPerson-gt;next = prev-gt;next;  prev-gt;next = newPerson;    }  //second edge case  //swapping process when prev age greater than curr age  //forming a decending order of ages  if(prev-gt;age gt; curr-gt;age)  {  tempValue = prev;   prev = prev-gt;next;   prev-gt;next = tempValue;    printf("nPerson age: %dn", tempValue-gt;age);  printf("loop testn");  printf("%d and %dn",prev-gt;age, prev-gt;next-gt;age);  }  //third edge case  //if age is the same do nothing  if(prev-gt;age == curr-gt;age)  {  return;  }  prev = prev-gt;next;  curr = curr-gt;next;     } }  

Эта функция возвращает нового человека

 person* addPerson( person *newPers ){  return newPers; }  

И вот мое главное, если вы хотите проверить это сами

 int main(){  person* person1 = construct_person("Max", 20);  person* person2 = construct_person("Sven", 25);  person* person3 = construct_person("Bob", 22);  person* person4 = construct_person("John", 23);  person* newPerson = construct_person("Markus", 21);   person1-gt;next = person2;  person2-gt;next = person3;  person3-gt;next = person4;  //person4-gt;next = addPerson(person1, newPerson);       //swapPerson(person1);  sortPerson(person1, addPerson(newPerson));  printperson(person1);   free(person1);  free(person2);  free(person3);  free(person4);  free(newPerson);  }  

Мой структурный сотрудник и конструктор

 typedef struct person person; struct person{  char *name;  int age;  person *next; };  person* construct_person(char *name, int age) {  person* pers = (person*) malloc (sizeof(person));  pers-gt;name = name;  pers-gt;age = age;  pers-gt;next = NULL;  return pers; }  

Я подозреваю, что проблема в том, что мой указатель структуры «prev» изменяется на протяжении всего процесса, но я хотел бы получить второе мнение и возможное исправление.

*Обратите внимание, что я освобождаю его таким образом только потому, что это только тестирование, и я не собираюсь добавлять больше людей, которых я сделал бы итеративно.

Комментарии:

1. Вместо того, чтобы менять prev curr местами сами узлы и, почему бы не поменять местами их содержимое (т. Е. Данные внутри узлов)?

2. Потому что, если я, например, создам еще большие объекты, мне придется переключать их один за другим, верно? Например, если у меня есть имя, возраст, адрес, идентификатор и т. Д. Или есть способ их объединить?

3. Возможно, проще всего, если вы абстрагируете список и структуры узлов из данных. Поэтому, если бы узлы имели указатель на person структуру, а не были person структурой, это было бы очень просто (простая инициализация и назначение объектов структуры).

4. Кроме этого, я рекомендую вам использовать отладчик для пошагового выполнения инструкции кода за инструкцией, используя карандаш и бумагу для рисования списка и операций, которые вы выполняете над ним. Используйте поля для узлов и стрелки для указателей (включая next ссылки). При изменении указателя или ссылки сотрите стрелку и перерисуйте ее. Если вам это нравится, имеют ли смысл выполняемые операции, когда вы видите визуальное представление на бумаге? Использование карандаша и бумаги также является хорошим способом начать экспериментировать, прежде чем писать код. Сделайте так, чтобы это работало на бумаге, а затем переведите это в код.

5. Вы должны опубликовать construct_person и person

Ответ №1:

Некоторые замечания:

  • Название sortPerson выбрано не очень удачно. Его лучше назвать insertPerson
  • Вы не можете надеяться отсортировать список всего за одну итерацию и поменять местами местами во время этой итерации. Если бы это было возможно, вы бы изобрели самый эффективный алгоритм сортировки. Так что это не может сработать-по крайней мере, не всегда.
  • Вместо того, чтобы реализовывать какой-либо алгоритм сортировки (например, сортировка пузырьков, сортировка выбора,…), убедитесь, что вы добавили всех людей, использующих эту insertPerson функцию. Таким образом, вы можете быть уверены, что список, в который вставлен новый человек, уже отсортирован. Таким образом, вам вообще не придется менять местами элементы. Вам нужно только найти правильную точку вставки и вставить туда нового человека. Поэтому в основной программе вам не следует возиться с next указателями. Предоставьте это этой insertPerson функции.
  • Если список пуст или в нем только один человек, вы все равно должны вставить нового человека. Нет смысла не делать этого, когда список пуст (или содержит только один элемент).
  • Единственный базовый случай-это когда вам нужно вставить человека раньше всех других людей. В этом случае ссылка на первого человека должна измениться, так как новый человек становится этим первым человеком. Один из способов заставить это работать-сделать первый параметр вызовом по ссылке. Другими словами: передайте адрес, где хранится указатель первого лица, чтобы этот указатель можно было изменить, и вызывающий абонент будет иметь доступ к этому изменению.
  • Я не вижу логики в том, чтобы опустить вставку, когда возраст нового человека совпадает с возрастом человека, уже включенного в список. Конечно, в вашем списке должны быть Боб и Алиса, даже если им обоим по 28 лет.
  • Есть еще несколько моментов, которые следует отметить…

Вот рабочая версия. Мне пришлось сделать некоторые предположения о коде, которым вы не поделились, но принцип должен быть ясен, даже если ваш код отличается:

 #include lt;stdio.hgt; #include lt;stdlib.hgt; #include lt;string.hgt;  typedef struct person_s {  int age;  char name[100];  struct person_s * next; } person;  person* construct_person(char* name, int age) {  person* p = malloc(sizeof(person));  strcpy(p-gt;name, name);  p-gt;age = age;  p-gt;next = NULL;  return p; };  void insertPerson(person** youngest, char* name, int age) {  person* newPerson = construct_person(name, age);  // Even when list is empty, still add it  if (*youngest == NULL || (*youngest)-gt;age gt; age) {  newPerson-gt;next = *youngest;  *youngest = newPerson;  return;  }  person* prev = *youngest;  person* curr = prev-gt;next;  // Search insertion point  while (curr != NULL amp;amp; curr-gt;age lt; age) {  prev = curr;  curr = curr-gt;next;  }  // Found it:  prev-gt;next = newPerson;  newPerson-gt;next = curr; }  void printList(person* pers) {  while (pers != NULL) {  printf("%s is %d years old.n", pers-gt;name, pers-gt;age);  pers = pers-gt;next;  } }  void freeList(person** pers) {  while (*pers != NULL) {  person* temp = *pers;  *pers = (*pers)-gt;next;  free(temp);  } }   int main(){  person* personList = NULL;  insertPerson(amp;personList, "Max", 20);  insertPerson(amp;personList, "Sven", 25);  insertPerson(amp;personList, "Bob", 22);  insertPerson(amp;personList, "John", 23);  insertPerson(amp;personList, "Markus", 21);  printList(personList);  freeList(amp;personList); }