Dynamiczne sortowanie ciągu - prośba o pomoc

0

Witam wszystkich. Prosiłbym o analizę funkcji mającej na zadanie pozamieniać kolejność elementów w sposób bąbelkowy. Na tą chwilę jest niedokończona i nie mam pojęcia, jak ją zrobić. Pozdrawiam.

#include <iostream>
#include <cmath>
#include <ctime>
using namespace std;

struct liczba {
	int wartosc;
	liczba *nastepna; 
};

struct ciag {
	liczba *glowa;
	liczba *ogon;
};

static unsigned long int i = 0;

void dodajLiczbe (liczba * Liczba)
{
	Liczba->wartosc = rand()%30;
	cout << "Wprowadzono liczbe: " << Liczba->wartosc;
	Liczba->nastepna = nullptr;
	cout << endl;
	system ("pause");
	i++;
}

void wyswietlLiczbe (liczba Liczba)
{
	cout << Liczba.wartosc << "\t";

}

void dodajDoCiagu (ciag &Ciag)
{
	liczba * tmp = new liczba;
	dodajLiczbe (tmp);
	Ciag.ogon=Ciag.glowa;

	if (Ciag.glowa == nullptr)
	{
		Ciag.ogon = tmp;
		Ciag.glowa = Ciag.ogon;
	}

	else
		{
			while (Ciag.ogon->nastepna != nullptr)
			{
				Ciag.ogon = Ciag.ogon->nastepna; // przemieszczamy sie po wskaznikach, od glowy do pustego
			}
			Ciag.ogon->nastepna = tmp;
			Ciag.ogon = tmp;
		}
}

void wyswietlCiag (ciag Ciag)
{
	if (Ciag.glowa == nullptr)
	{
		cout << "Ciag jest pusty." << endl;
		system ("pause");
		return;
	}

	else
		{
			while (Ciag.glowa != nullptr)
			{
				wyswietlLiczbe(*Ciag.glowa);
				Ciag.glowa = Ciag.glowa ->nastepna;
			}
		}
	system ("pause");
}

void posortujCiag (ciag &Ciag)
{
	liczba * tmp = Ciag.glowa;
	for (unsigned long int j=0; j<i; j++)
		{
		while (Ciag.glowa != nullptr)
		{
			if (Ciag.glowa->wartosc < Ciag.glowa->nastepna->wartosc)
			{
				liczba * tmp1 = Ciag.glowa;
				Ciag.glowa = Ciag.glowa->nastepna;
				Ciag.glowa->nastepna = tmp1;
				delete tmp1;
			}
			Ciag.glowa = Ciag.glowa->nastepna;
		}
		Ciag.glowa = tmp;
	}
}

void usunCiag (ciag &deleted)
{
	liczba *skasuj = deleted.glowa;
	if (deleted.glowa == nullptr)
	{
		cout << "Nie ma czego usuwac.";
		system ("pause");
		return;
	}
	else
		while (deleted.glowa != nullptr)
		{
			skasuj = deleted.glowa;
			deleted.glowa = deleted.glowa->nastepna;
			delete skasuj;
		}
}

int main ()
{
	srand (time (NULL));
	ciag Ciag;
	Ciag.glowa = nullptr;
	Ciag.ogon = Ciag.glowa;
	short liczba;

	do {
		system ("cls");
		liczba = 6;
		cout << "Dostepne operacje:\n1. Dodaj liczbe do ciagu\n2. Wyswietl ciag\n3. Posortuj ciag\n4. Usun ciag\n5. Koniec\n";
		cout << "Wprowadz numer operacji: ";
		cin >> liczba;
		switch (liczba)
		{
		case 1: dodajDoCiagu (Ciag); break;
		case 2: wyswietlCiag (Ciag); break;
		case 3: posortujCiag (Ciag); break;
		case 4: usunCiag(Ciag);
		default: break;
		}
	} while (liczba!=5);

		
	system ("pause");
	return 0;
}
0

Całość jest do chrzanu:

  1. polskie nazwy
  2. system ("pause");
  3. mieszasz funkcjonalność z interfacem
    Np tak powinna wyglądać jedna z funkcji:
void dodajDoCiagu (ciag &Ciag,int wartosc)
  {
   liczba *tmp=new liczba;
   tmp->wartosc=wartosc;
   tmp->nastepna=nullptr;
   Ciag.ogon=(Ciag.ogon?Ciag.ogon->nastepna:Ciag.glowa)=tmp;
  }

Inne podobnie.

0

Witam. Na stylistykę przyjdzie czas - na tą chwilę mój poziom jest taki a nie inny, więc zależy mi wyłącznie na poprawnym działaniu programu, a dopiero w drugiej kolejności na estetyce i maksymalnym zaoszczędzeniu pamięci.
Prosiłbym o odpowiedź na moje pytanie - oczywiście jeśli na tym kodzie nie da się zrobić sortowania (w co, mimo wszystko, wątpię), to dopiero wtedy przejdę do przerabiania go. Pozdrawiam

1

Masz źle napisane usuwanie.
Zaś sortowanie nie ma nic wspólnego z tym co powinno być.

0

W porządku. Co jest nie tak z usuwaniem? Program działa, ale domyślam się, że to nie wystarczy. Czy dochodzi do wycieku pamięci?

0

Brak zerowania Ciag.ogon powoduje że kolejne poprawne dodawania (nie ten badziew co masz) nie doda się poprawnie.

0

Posłuchaj Panie programisto, bo przesadzasz ze swoją impertynencją. Jestem w stanie zrozumieć, że zwracasz uwagę na błędy zawarte w programie i to, uwierz, jak najbardziej doceniam. Ale kiedy po raz kolejny proszę o pomoc w niedociągnięciach zawartych w kodzie, muszę czytać, że stworzyłem badziew, że całość jest do chrzanu - a samo sortowanie jest złe (no też mi nowość - po to tutaj napisałem, żeby to sortowanie ZROBIĆ!).
Nie Panie programisto, ten program nie jest badziewiem. Patrząc na to, że dopiero niedawno rozpocząłem w ogóle przygodę ze wskaźnikami, uważam, że jest to całkiem niezły wyraz moich starań. Nawet jeśli jest w nim zawarte wiele błędów - proszę zwracać na to uwagę z kulturą, bo czytanie tych dyrdymałów może przyprawić człowieka o mdłości. Z całym szacunkiem dla Ciebie.

1

Przykro mi, ale ja też stwierdzam że kod nadaje się tylko do kosza, bo jedyne (!) co jest w nim napisane poprawnie to main(), usunCiag() oraz dodajLiczbe() [które to akurat powinno się nazywać zupełnie inaczej bo nic nie dodaje tylko inicjalizuje nowy węzeł listy]. Cała reszta jest albo bez sensu, albo bardzo bardzo zła.

  1. Dodanie nowego elementu do listy nie wymaga żadnego pętlenia się po liście (!). Jak dodajesz na początek to robisz
nowy_wezel->next = ciag.glowa;
ciag.glowa=nowy_wezel

a jak dodajesz na koniec to

ciag.ogon->next = nowy_wezel

sprawdzając wcześniej czy aby czasem lista nie jest pusta, bo jeśli jest to

ciag.ogon = ciag.glowa = nowy_wezel

Po co ty tam takie cuda na kiju robisz to nie wiem.
2. Wyświetlenie ciągu poprzez przesuwanie wskaźnika head to terroryzm, nawet jeśli wiesz że pracujesz na lokalnej kopii wewnątrz funkcji. Nie rób tak, bo jest to bardzo mylące.
3. Jesli chodzi o sortowanie to ja osobiście robiłbym to za pomocą 2 ciągów. Każdy obieg sortowania bąbelkowego powoduje przesunięcie na koniec elementu który będzie "na swoim miejscu". Ten element bym odcinał i przenosił do nowego ciągu. Wtedy znika cały ten twój meksyk z liczeniem ile elementów jest w ciągu.

0

W porządku, przyjmuję do wiadomości. Nie kwestionuję i nawet nie zamierzam poddawać dyskusji jakości kodu. Powiem tak, stworzyłem póki co swój dom z drewna, przed deszczem nawet nie chroni, ale stopniowo go będę modernizował.
To tyle, dziękuję za konstruktywną odpowiedź. Pozdrawiam :).

Ps. jeszcze jedna rzecz - w takim razie jak swobodnie przesuwać się po elementach ciągu, skoro nawet jeśli nie użyję głowy, a podciąg/tymczasowy obiekt, to i tak sortowanie muszę zaczynać od pierwszego elementu, na który wskazuje przecież głowa. Prosiłbym o wytłumaczenie tego. Pozdrawiam.

Odświeżam.

1
void posortujCiag (ciag &Ciag)
  {
   for(liczba *i=Ciag.glowa;i;i=i->nastepna)
     {
      ...
     }
  }
0

W porządku, dziękuję.

0

Niestety muszę po raz kolejny wrzucić kod - nie jestem w stanie napisać sortowania. Próbowałem dopisać do obiektu jeszcze wskaźnik na poprzedni, ale podejrzewam, że go zapisałem w zły sposób (lista od tyłu nie chciała się odtworzyć). Prosiłbym o pomoc w dokończeniu tego programu - siedzę nad tym już wiele godzin, a niestety brak doświadczenia z tym wcześniej sprawia mi na tą chwilę mnóstwo kłopotów. Pozdrawiam.

#include <iostream>
#include <cmath>
#include <ctime>
using namespace std;

struct liczba {
	int wartosc;
	liczba *nastepna;
	liczba *poprzednia;
};

struct ciag {
	liczba *glowa;
	liczba *ogon;
};


void dodajLiczbe (liczba * Liczba)
{
	Liczba->wartosc = rand()%30;
	Liczba->nastepna = nullptr;
	cout << endl;
}

void wyswietlLiczbe (liczba Liczba)
{
	cout << Liczba.wartosc << "\t";

}

void dodajDoPoczatku (ciag &ciag)
{
	liczba *tmp = new liczba;
	dodajLiczbe (tmp); // 7

	if (ciag.glowa == nullptr)
	{
		ciag.ogon = tmp;
		ciag.glowa = ciag.ogon;
	}

	 else {
		tmp->nastepna = ciag.glowa;
		ciag.glowa->poprzednia = tmp;
		ciag.glowa = tmp; 
	 }
}

void dodajDoKonca (ciag &ciag)
{
	liczba *tmp = new liczba;
	dodajLiczbe (tmp); 

	if (ciag.glowa == nullptr)
	{
		ciag.ogon = tmp;
		ciag.glowa = ciag.ogon;
	}

	else {
			ciag.ogon->poprzednia = ciag.ogon ; //
			ciag.ogon = ciag.ogon->nastepna = tmp;
		}
}

void wyswietlCiag (ciag Ciag)
{
	if (Ciag.glowa == nullptr)
	{
		cout << "Ciag jest pusty." << endl;
		system ("pause");
		return;
	}

	else
		{
			while (Ciag.glowa != nullptr)
			{
				wyswietlLiczbe(*Ciag.glowa);
				Ciag.glowa = Ciag.glowa ->nastepna;
			}

		}
	cout << endl;
	system ("pause");
}

void posortujCiag (ciag &Ciag)
{
	for (liczba *j = Ciag.ogon; j->poprzednia == nullptr; j= j->poprzednia)
	{
		for (liczba *i = Ciag.glowa; i->nastepna == nullptr; i= i->nastepna)
		{

			if (i->wartosc > i->nastepna->wartosc)
				{
					liczba *tmp = i->nastepna;
					i->nastepna = i;
					i = tmp;
				}

		}
	}
}

void usunCiag (ciag &deleted)
{
	liczba *skasuj = deleted.glowa;

	if (deleted.glowa == nullptr)
	{
		cout << "Nie ma czego usuwac.";
		system ("pause");
		return;
	}
	else
		while (deleted.glowa != nullptr)
		{
			skasuj = deleted.glowa;
			deleted.glowa = deleted.glowa->nastepna;
			delete skasuj;
		}
	
	deleted.ogon = nullptr;

}

int main ()
{
	srand (time (NULL));
	ciag Ciag;
	Ciag.glowa = nullptr;
	Ciag.ogon = Ciag.glowa;
	short liczba,liczba2;

	do {
		system ("cls");
		liczba = 6;
		cout << "Dostepne operacje:\n1. Dodaj liczbe do ciagu\n2. Wyswietl ciag\n3. Posortuj ciag\n4. Usun ciag\n5. Koniec\n";
		cout << "Wprowadz numer operacji: ";
		cin >> liczba;
		switch (liczba)
		{
		case 1: system ("cls");
		cout << "Dostepne instrukcje:\n1. Dodaj do poczatku.\n2. Dodaj na koniec. ";
		cout << endl;
		cout << "Wprowadz: ";
		cin>>liczba2;
		switch (liczba2)
		{
		case 1: dodajDoPoczatku (Ciag); break;
		case 2: dodajDoKonca (Ciag); break;
		}
		; break;
		case 2: wyswietlCiag (Ciag); break;
		case 3: posortujCiag (Ciag); break;
		case 4: usunCiag(Ciag);
		default: break;
		}
	} while (liczba!=5);

	return 0;
}
0

Wymieniaj wartości nie węzły

0

Tak byłoby najlepiej, niestety na zadanie mamy przepiąć wskaźniki. Jak taki rezultat uzyskać - to dla mnie na tą chwilę czarna magia. Czy wskaźnik *prev (poprzedni) zamontowany jest poprawnie?

0

Aby zacząć rozumieć wymianę miejscami dwóch sąsiednich węzłów listy trzeba:

  1. Zrozumieć i zrobić maksymalne poprawnie pozostałe proste operacji, niestety ignorujesz wszelkie sugestie
  2. Zrobić prosty sobie rysunek tego co zamierzasz zrealizować
  3. Najlepiej użyć podwójnych wskaźników dla zapisania "miejsca podczepienia".
0

Ciag.ogon zeruje się w funkcji kasującej ciąg - tak zrozumiałem tą wskazówkę. W przypadku pozostałych, gdzie umieszczam obiekty na początku i końcu ciągu, skorzystałem z rad Shalom. Jeśli chodzi o system ("pause") - jest już tylko w tym momencie, kiedy wyświetla się ciąg - można jeszcze tutaj coś poprawić? Jeśli chodzi o polskie nazwy - następny program będę robił już na pewno na angielskich.
Pytam ponownie: czy wskaźnik na poprzedni obiekt umieściłem poprawnie? No i kluczowa sprawa: może mi się on raczej przydać, czy tylko skomplikuje sytuacje? Wydaje mi się, że ułatwiłby całość, bo mógłbym zrezygnować z przesuwania głowy.

0
Plusce napisał(a):

Pytam ponownie: czy wskaźnik na poprzedni obiekt umieściłem poprawnie?
Mylisz programowanie z grą kolo fortuny - to tam nazywasz literę i tobie mówią czy taka jest a jak jest to wskazują gdzie.

0

Oczywiście sugestię bym przyjął, gdybym próbował podjąć cokolwiek bez próby zrozumienia - nic z tych rzeczy, naprawdę daję z siebie wszystko. Chciałbym jedynie kawałek kodu, żeby sobie pewne rzeczy przyswoić i uzmysłowić na zasadzie przykładu.
W takim razie próbuję nadal - jak uda mi się doprowadzić program do stanu chociażby działania, dam kod ponownie do oceny. Pozdrawiam.

0

Zamieszczam aktualny kod. Usunąłem funkcję tworzącą nową liczbę - wszystko dzieje się teraz w obrębie jednej funkcji. Prosiłbym o ocenę funkcjonalności funkcji sortujących i zamieniających elementy - na tą chwilę wszystko działa.

 #include <iostream>
#include <cmath>
#include <ctime>
using namespace std;

struct liczba {
	int wartosc;
	liczba *nastepna;
	liczba *poprzednia;
};

struct ciag {
	liczba *glowa;
	liczba *ogon;
};

void wyswietlLiczbe(const liczba &Liczba)
{
	cout << Liczba.wartosc << "\t";
	//cout << Liczba.poprzednia << " " << &Liczba << " " << Liczba.nastepna << endl;

}

void dodajDoPoczatku(ciag &ciag)
{
	system ("cls");
	liczba *tmp = new liczba;
	tmp->wartosc = rand()%30;
	tmp->nastepna = nullptr;
	tmp->poprzednia = nullptr;

	if (ciag.glowa == nullptr)
	{
		ciag.ogon = tmp;
		ciag.glowa = ciag.ogon;
	}

	else {		
		tmp->nastepna = ciag.glowa;
		ciag.glowa->poprzednia = tmp;
		ciag.glowa = tmp;
	}
}

void dodajDoKonca(ciag &ciag)
{
	liczba *tmp = new liczba;
	tmp->wartosc = rand() % 30;
	tmp->nastepna = nullptr;

	if (ciag.glowa == nullptr)
	{
		tmp->poprzednia = nullptr;
		ciag.ogon = tmp;
		ciag.glowa = ciag.ogon;
	}

	else {
		ciag.ogon = ciag.glowa;
		while (ciag.ogon->nastepna != nullptr){ ciag.ogon = ciag.ogon->nastepna; }
		tmp->poprzednia = ciag.ogon;
		ciag.ogon->nastepna = tmp;
	}
}

void wyswietlCiag(ciag Ciag)
{
	if (Ciag.glowa == nullptr)
	{
		cout << "Ciag jest pusty." << endl;
		system("pause");
		return;
	}

	else
	{
		while (Ciag.glowa != nullptr)
		{
			wyswietlLiczbe(*Ciag.glowa);
			Ciag.glowa = Ciag.glowa->nastepna;
		}

	}
	cout << endl;
	system("pause");
}

void zamienElementy(ciag &Ciag, liczba *elem1, liczba *elem2)
{
	liczba *tmp = elem2->nastepna;
	if (elem1->poprzednia!=nullptr) elem1->poprzednia->nastepna = elem2;
	else Ciag.glowa = elem2;
	elem2->poprzednia = elem1->poprzednia;
	elem2->nastepna = elem1;
	elem1->poprzednia = elem2;
	elem1->nastepna = tmp;
	if (elem1->nastepna!=nullptr) elem1->nastepna->poprzednia = elem1;
}

void posortujCiag(ciag &Ciag)
{
	int k;
	Ciag.ogon = Ciag.glowa;
	do
	{
		k = 0;
		Ciag.ogon = Ciag.glowa;
		while (Ciag.ogon->nastepna != nullptr)
		{
			if (Ciag.ogon->wartosc > Ciag.ogon->nastepna->wartosc)
			{ 
				zamienElementy(Ciag, Ciag.ogon, Ciag.ogon->nastepna); 
				k++; 
				continue; 
			}
			Ciag.ogon = Ciag.ogon->nastepna;
		}
	} while (k != 0);

}

void usunCiag(ciag &deleted)
{
	liczba *skasuj = deleted.glowa;

	if (deleted.glowa == nullptr)
	{
		cout << "Nie ma czego usuwac.";
		system("pause");
		return;
	}
	else
	while (deleted.glowa != nullptr)
	{
		skasuj = deleted.glowa;
		deleted.glowa = deleted.glowa->nastepna;
		delete skasuj;
	}

	deleted.ogon = nullptr;

}

int main()
{
	srand(time(NULL));
	ciag Ciag;
	Ciag.glowa = nullptr;
	Ciag.ogon = Ciag.glowa;
	short liczba, liczba2;

	do {
		system("cls");
		liczba = 6;
		cout << "Dostepne operacje:\n1. Dodaj liczbe do ciagu\n2. Wyswietl ciag\n3. Posortuj ciag\n4. Usun ciag\n5. Koniec\n";
		cout << "Wprowadz numer operacji: ";
		cin >> liczba;
		switch (liczba)
		{
		case 1: system("cls");
			cout << "Dostepne instrukcje:\n1. Dodaj do poczatku.\n2. Dodaj na koniec. ";
			cout << endl;
			cout << "Wprowadz: ";
			cin >> liczba2;
			switch (liczba2)
			{
			case 1: dodajDoPoczatku(Ciag); break;
			case 2: dodajDoKonca(Ciag); break;
			}
			; break;
		case 2: wyswietlCiag(Ciag); break;
		case 3: posortujCiag(Ciag); break;
		case 4: usunCiag(Ciag);
		default: break;
		}
	} while (liczba != 5);

	return 0;
}
1

W C http://ideone.com/a4umQE

jakoś to wszystko u Cb skomplikowane i mieszasz. sortowania nie chce mi się pisać. tablice wskaźników łatwiej się sortuje niż takie coś. do NULLów z malloca możesz skorzystać z assert.

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

typedef struct elem {
	int val;
	struct elem *next;
	struct elem *prev;
} elem;

typedef struct {
	elem *first;
	elem *last;
} seq_t;

seq_t* seq_create(int val) {
	seq_t *seq= malloc(sizeof(seq_t));
	elem *e = malloc(sizeof(elem));
	e->val = val;
	seq->first = e;
	seq->last = e;
	e->next = NULL;
	e->prev = NULL;
	return seq;
}

/* add to the end */
void seq_adde(seq_t *seq, int val) {
	elem *e = malloc(sizeof(elem));
	e->val = val;
	e->next = NULL;
	e->prev = seq->last;
	seq->last->next = e;
	seq->last = e;
}

/* add to beginning */
void seq_addb(seq_t *seq, int val) {
	elem *e = malloc(sizeof(elem));
	e->val = val;
	e->next = seq->first;
	e->prev = NULL;
	seq->first->prev = e;
	seq->first = e;
}

void seq_free(seq_t *seq) {
	elem *e = seq->first;
	elem *ne;
	while(e!=NULL) {
		ne = e->next;
		free(e);
		e = ne;
	}
	free(seq);
}

void seq_print(seq_t *seq) {
	elem *e = seq->first;
	while(e!=NULL) {
		printf("%d\n",e->val);
		e = e->next;
	}
}

int main(void) {
	seq_t *seq = seq_create(3000);
	seq_addb(seq,2000);
	seq_adde(seq,4000);
	seq_addb(seq,1000);
	seq_adde(seq,5000);
	seq_print(seq);
	seq_free(seq);
	return 0;
}
0

"... troche ifów chyba trzeba byłoby dodać wtedy ..." - nie koniecznie:

elem *make_elem(int val,elem *prev,elem *next)
  {
   elem *e=malloc(sizeof(elem));
   e->val=val;
   e->prev=prev;
   e->next=next;
   return e;
  }

void seq_adde(seq_t *seq,int val)
  {
   seq->last=(seq->last?seq->last->next:seq->first)=make_elem(val,seq->last,NULL);
  }

1 użytkowników online, w tym zalogowanych: 0, gości: 1