Konwersja tablicy na listę jednokierunkową

0

Cześć, jestem podkreślam, dużym newbie jeżeli chodzi o C, pobawiłem się w sortowanie listy, poprzez zrzucanie jej do tablicy wskaźników, teraz tutaj jest moje pytanie, czy jest możliwość takiej konwersji w przypadku listy jednokierunkowej ? w dwukierunkowej wyobrażam sobię, że mogę się zacząć cofać po liście, lecz tutaj jak przejdę do ostatniego elementu, to tak jakby mam wskaźnik ustawiony na ostatni element, więc nie wiem jak mogę się cofnąć od ostatniego, do pierwszego elementu. Poniżej przesyłam kod, poprosiłbym o naprowadzenie na rozwiązanie problemu.

#include <stdlib.h>
#include <stdio.h>
typedef struct Node 
{
	int data;
	struct Node* next;
} Node;
void insert(Node** ,int x);
void print();
void insert_node_at_n(Node**, int, int);
int compare_data(const void* first, const void* second)
{
	Node*a=*((Node**)first);
	Node*b=*((Node**)second);
	if ((a->data)>(b->data)) return -1;
	else if((a->data)==(b->data)) return 0;
	else return 1;
	
}
int length_of_list(Node* head)
{
	int d=0;
	while(head!=NULL)
	{
		head = head->next;
		d++;
	}
	return d;
}
void sorting(Node*);
int main(void)
{
	Node* head ;
	head=NULL;
	printf("How many numbers? \n");
	int n, i, x;
	scanf("%d", &n);
	for(i=0;i<n;i++)
	{
		printf("Enter the number \n");
		scanf("%d", &x);
		insert(&head, x);
	}
	print(head);
	printf("length of list: %d", length_of_list(head));
	sorting(head);
	
	
	return 0;
}

void insert(Node** pointerToHead, int x)
{
	Node* temp=(Node*)malloc(sizeof(struct Node));
	temp->data = x;
	temp->next=*pointerToHead;
	if(*pointerToHead != NULL) temp->next=*pointerToHead;
	*pointerToHead = temp;
}
void print(Node* head)
{
	while(head != NULL)
	{
		printf("%d \n", head->data);
		head = head->next;
	}
}
void insert_node_at_n(Node** pointerToHead, int data, int n)
{
	Node* temp1 = (Node*)malloc(sizeof(Node*));
	temp1->data=data;
	temp1->next=NULL;
	if(n == 1)
	{
		temp1->next = *pointerToHead;
		*pointerToHead = temp1;
		return;
	}
	Node* temp2 = *pointerToHead;
	for(int i=0; i<n-2;i++)
	{
		temp2=temp2->next;
	}
	temp1->next = temp2->next;
	temp2->next = temp1;
}
void sorting(Node* head)
{
	int i=0;
	int d=length_of_list(head);
	Node** tab=(Node**)malloc(d*sizeof(Node*));
	while(head!=NULL)
	{
		tab[i]=head;
		head=head->next;
		i++;
	}
	qsort(tab, i, sizeof(tab), compare_data);
	int j=0;
	while (j<i) {
		printf("%d\t", tab[j]->data);
		j++;
	}
	free(tab);
}


1

Jak sama nazwa wskazuje - lista jednokierunkowa ma tylko jeden kierunek, nie możesz cofać. Rozwiązanie jest takie jak podałeś - użycie listy dwukierunkowej.

Ewentualnie, jeśli chodzi o powrót do pierwszego elementu to wystarczy że zachowasz kopię oryginalnego wskaźnika który jest pierwszym elementem listy.

0

Czyli nie ma takiej możliwości, aby tak posortowaną tablicę skonwertować z powrotem na listę?

0

Jeżeli masz tablicę wskaźników to nie powinien być to problem.

Załóżmy że istnieje tablica pointer_tab a jej rozmiar to size, wtedy:

Node *first = pointer_tab[0];
Node *node = first;

for (int i = 1; i < size; i++)
{
	Node *tmp = pointer_tab[i];
	node->next = tmp;
	node = tmp;
}

node->next = NULL;

Nie testowałem jeszcze tego kodu.

0

Wydaje mi się że udało mi się zrobić tą funkcję, @atmal zrobiłem tą funkcję zwracającą tablicę, i wydaje mi się że jest ok, widzisz jakieś rażące błędy?

#include <stdlib.h>
#include <stdio.h>
typedef struct Node 
{
	int data;
	struct Node* next;
} Node;
void insert(Node** ,int x);
void print();
void insert_node_at_n(Node**, int, int);
void array_to_list(Node**, Node **, int);
int compare_data(const void* first, const void* second)
{
	Node*a=*((Node**)first);
	Node*b=*((Node**)second);
	if ((a->data)>(b->data)) return -1;
	else if((a->data)==(b->data)) return 0;
	else return 1;
	
}
int length_of_list(Node* head)
{
	int d=0;
	while(head!=NULL)
	{
		head = head->next;
		d++;
	}
	return d;
}
Node** sorting(Node*);
int main(void)
{
	Node* head ;
	head=NULL;
	printf("%p, %p\n ",head, &head);
	printf("How many numbers? \n");
	int n, i, x;
	scanf("%d", &n);
	for(i=0;i<n;i++)
	{
		printf("Enter the number \n");
		scanf("%d", &x);
		insert(&head, x);
	}
	print(head);
	printf("length of list: %d", length_of_list(head));
	sorting(head);
	array_to_list(&head, sorting(head), i);
	print(head);
	return 0;
}

void insert(Node** pointerToHead, int x)
{
	Node* temp=(Node*)malloc(sizeof(struct Node));
	temp->data = x;
	temp->next=*pointerToHead;
	if(*pointerToHead != NULL) temp->next=*pointerToHead;
	*pointerToHead = temp;
}
void print(Node* head)
{
	while(head != NULL)
	{
		printf("%d \n", head->data);
		head = head->next;
	}
}
void insert_node_at_n(Node** pointerToHead, int data, int n)
{
	Node* temp1 = (Node*)malloc(sizeof(Node*));
	temp1->data=data;
	temp1->next=NULL;
	if(n == 1)
	{
		temp1->next = *pointerToHead;
		*pointerToHead = temp1;
		return;
	}
	Node* temp2 = *pointerToHead;
	for(int i=0; i<n-2;i++)
	{
		temp2=temp2->next;
	}
	temp1->next = temp2->next;
	temp2->next = temp1;
}
Node** sorting(Node* head)
{
	int i=0;
	int d=length_of_list(head);
	Node** tab=(Node**)malloc(d*sizeof(Node*));
	while(head!=NULL)
	{
		tab[i]=head;
		head=head->next;
		i++;
	}
	qsort(tab, i, sizeof(tab), compare_data);
	return tab;
}
void array_to_list(Node** head, Node **tab, int i)
{
	Node *temp1 = *head;
	*head=tab[0];
	int j=0;
	for(j=0;j<i;j++)
	{
		Node *temp2 = tab[j];
		temp1->next=temp2;
		temp1=temp2;
	}
	temp1->next=NULL;
}

0

Wydaję mi się że jest OK.

Jedyne co bym zmienił to deklarował wszystkie funkcje pod main, a nad main zostawić tylko prototypy.

0

już poprawiłem te deklaracje. @atmal: a tak właściwie jeszcze takie pytanie, po co dokładnie są te linijki, bo są to zmienne tylko lokalne dla tej funkcji i tak na prawdę zmieniamy tylko to na co wskazuje head, czyli że wskazuje na pierwszy element tablicy, ale tego całego fora nie rozumiem.

for(j=0;j<i;j++)
    {
        Node *temp2 = tab[j];
        temp1->next=temp2;
        temp1=temp2;
    }
    temp1->next=NULL;
0

Chodzi o taką tymczasową zmienną którą możesz ustawić jako wskaźnik następnego elementu - (temp1->next) a następnie przenieść się do tego następnego elementu za pomocą temp1 = temp2.

W sumie można byłoby to zapisać

temp1->next = tab[j];
temp1 = tab[j];
0

Tylko w jakim celu tak właściwie to robimy? żeby ustawić wskaźnik temp1->next na NULL? bo te zmienne chyba nic nie wnoszą do listy

0

Skomentowałem kod, mam nadzieję że teraz jest jasne co i dlaczego ;)

Node *first = pointer_tab[0]; // Pierwszy element - nie chcemy go ruszać
Node *node = first; //  Obecny element na którym jesteśmy
 
for (int i = 1; i < size; i++)
{
    Node *tmp = pointer_tab[i]; // Pobieramy element z tablicy i przykazujemy go do tmp
    node->next = tmp; // Jako że za pierwszym razem obecny == pierwszy to ustawiamy tmp jako element następny
    node = tmp; // I teraz przesuwamy obecny element na ten następny
}
 
node->next = NULL; // Po skończeniu iteracji przez listę ustawiamy następny element na NULL tak aby nie można było iść dalej
0

Problem rodzi się w momencie że gdy ustawie for od j=1 to nie wypisuje mi ostatniego elementu, jak zrobię od 0 to wypisuje wszystkie, staram się zrozumieć dlaczego, ale nie mogę dojść

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