[C] List jednokierunkowa - dodawanie elementów

poranekk
Użytkownik
Użytkownik
Posty: 35
Rejestracja: 31 mar 2011, o 18:41
Płeć: Mężczyzna
Lokalizacja: Łódź
Podziękował: 6 razy
Pomógł: 1 raz

[C] List jednokierunkowa - dodawanie elementów

Post autor: poranekk »

Cześć! Potrzebuje pomocy z listami. Nie rozumiem co robie źle, gdzie robie błąd. Na razie napisałem jednokierunkową. Wiem, że coś robie nie tak w funkcji dodawania elementów. Przepuściłem przez debuggera, ale jakby się nie 'podpinały' elementy;

Kod: Zaznacz cały

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

typedef struct lst
{
	int value;	//prosta struktura
	lst *next;
} el;

el *pierwszy;

void dodaj(el* list, int wartosc, int *ct)
{
	el *wsk, *nowy;
	wsk = list;
	if(*ct == 0)	//wskaznik do count, patrz main
	{
		nowy = (el*)malloc(sizeof(el));	//rezerwacja miejsca pod strukture
		nowy->value = wartosc;	//przypisanie wartosci
		nowy->next = NULL;	//nastepny element = null
		nowy = wsk;		//przypisanie adresu wsk do nowego
		pierwszy = nowy;	//przypisanie nowego do pierwszego elementu
		*ct += 1;	//count = count + 1
	}
	else
	{
		nowy = (el*)malloc(sizeof(el));	//patrz wyzej
		nowy->value = wartosc;
		nowy->next = NULL;
		nowy = wsk;
	}
	
}

void drukuj(el *list)	//proste drukowanie
{
	el *wsk;
	wsk = list;
	while(wsk != NULL)
	{
		printf("%d\t", wsk->value);
		wsk->next = wsk;
	}
}

int main()
{
	el *lista;
	int *ct, count;	//stworzone po to by rozwiazac problem "pierwszego elementu (glowy)"
	ct = &count;
	count = 0;
	dodaj(lista, 10, ct);
	dodaj(lista, 20, ct);
	dodaj(lista, 30, ct);
	drukuj(lista);
}
Starałem się w miare opisać co się dzieje, żeby wprawne oko nie musiało się za dużo namęczyć : )
Ostatnio zmieniony 8 sie 2012, o 20:13 przez Afish, łącznie zmieniany 1 raz.
Powód: Staraj się lepiej dobierać nazwy tematów, tak by wskazywały o czym jest treść zadania.
Awatar użytkownika
Zordon
Użytkownik
Użytkownik
Posty: 4977
Rejestracja: 12 lut 2008, o 21:42
Płeć: Mężczyzna
Lokalizacja: Kraków
Podziękował: 75 razy
Pomógł: 910 razy

[C] - nauka prostego pisania list

Post autor: Zordon »

Operowanie na wskaźnikach nie jest łatwą sztuką, spróbuj najpierw poczytać gotowe kody i zobaczyć jak to działa, bo to co napisałeś ma kilka koncepcyjnych błędów.
Pierwsze na co zwróciłem uwagę, to:

Kod: Zaznacz cały

nowy = wsk;
Za bardzo nie widać co to powinno robić.
poranekk
Użytkownik
Użytkownik
Posty: 35
Rejestracja: 31 mar 2011, o 18:41
Płeć: Mężczyzna
Lokalizacja: Łódź
Podziękował: 6 razy
Pomógł: 1 raz

[C] - nauka prostego pisania list

Post autor: poranekk »

Ogarnąłem trochę funkcję dodawania i teraz ni z tego ni z owego wiesza się na wsk->next = nowy.

Kod: Zaznacz cały

***RESZTA JAK W POPRZEDNIM KODZIE***
void dodaj(el* list, int wartosc, int *ct)
{
	el *wsk, *nowy;
	wsk = list;
	if(*ct == 0)
	{
		nowy = (el*)malloc(sizeof(el));
		nowy->value = wartosc;
		nowy->next = NULL;
		wsk->next = nowy;  //poprawiłem
		pierwszy = nowy;
		*ct += 1;	
	}
	else
	{
		while(wsk->next != NULL)
		{
			wsk = wsk->next;
		}
		nowy = (el*)malloc(sizeof(el));
		nowy->value = wartosc;
		nowy->next = NULL;
		wsk->next = nowy;  
	}
}
Awatar użytkownika
Zordon
Użytkownik
Użytkownik
Posty: 4977
Rejestracja: 12 lut 2008, o 21:42
Płeć: Mężczyzna
Lokalizacja: Kraków
Podziękował: 75 razy
Pomógł: 910 razy

[C] - nauka prostego pisania list

Post autor: Zordon »

Z tego co widze to wsk będzie nullem, więc wsk->next powoduje błąd.
poranekk
Użytkownik
Użytkownik
Posty: 35
Rejestracja: 31 mar 2011, o 18:41
Płeć: Mężczyzna
Lokalizacja: Łódź
Podziękował: 6 razy
Pomógł: 1 raz

[C] List jednokierunkowa - dodawanie elementów

Post autor: poranekk »

Wałkujemy od nowa : )

Ten kod jest zły, bo nadal wsk=NULL i otrzymuje segmentation fault. Przez debuggera puściłem to okazuje się, że *lst jest od uruchomienia NULLem. Nie wiem czego nie zauważam i jak to ruszyć.

Kod: Zaznacz cały

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

typedef struct element
{
	struct element *next;
	int val;
} el_listy;

el_listy *lst;

void dodaj (el_listy *lista, int liczba, int chk)
{
	if(chk == 0)
	{
		while (wsk->next != NULL)
		{
			wsk = wsk->next;
		}
		nowy =(el_listy*) malloc (sizeof(el_listy));
		nowy->val = liczba;
		nowy->next = NULL;
		wsk->next = nowy;
	}
	else
	{
		nowy =(el_listy*) malloc (sizeof(el_listy));  //tutaj, tutaj : )
	        nowy->val = liczba;
		nowy->next = NULL;
	}

}

void wypisz(el_listy *lista)
{
	el_listy *wsk=lista;
	while( wsk != NULL )
	{
		printf ("%d
", wsk->val);
		wsk = wsk->next;
	}
}

int main ()
{
	int chk = 1;
	dodaj(lst, 10, chk);
	chk = 0;
	dodaj(lst, 20, chk);
	wypisz(lst);
	return 0;
}
Działa natomiast bezpośrednie przypisanie pierwszego elementu do listy, nie wiem jednak czy to jest poprawnie

Kod: Zaznacz cały

else
	{
		lst =(el_listy*) malloc (sizeof(el_listy));
		lst->val = liczba;
		lst->next = NULL;
	}
W tym momencie lst nie jest już NULLem, pierwszy element zostaje poprawnie utworzony i następne się podczepiają. Nie kumam, pomocy
royas
Użytkownik
Użytkownik
Posty: 363
Rejestracja: 24 sie 2012, o 09:27
Płeć: Mężczyzna
Lokalizacja: Cieszyn
Pomógł: 80 razy

[C] List jednokierunkowa - dodawanie elementów

Post autor: royas »

Jeśli do funkcji dodaj przekazujesz wskaźnik do elementu listy i przekazujesz tam NULL, to funkcja nawet jak coś utworzy to nie ma tego jak zwrócić. Konkretniej: przekazujesz wartość zmiennej lst czyli NULL więc funkcja nie ma jak zmodyfikować zmiennej lst. Możesz np. wymagać aby dodawać do niepustej listy, zwracać początek listy z funkcji, przekazywać wskaźnik do wskaźnika do elementu listy.
Proponuje coś takiego:
Zrezygnuj ze zmiennych globalnych. Zrezygnuj z parametru ct. Niech "dodaj" zwraca wskaźnik na pierwszy element listy.
Czyli:
el_listy* dodaj (el_listy *lista, int liczba)
Na początek utwórz nowy element listy i ustaw jego pola - po co pisać to dwa razy.
Jeśli lista jest pusta (lista==NULL) to po prostu zwróć nowy i zakończ.
Jeśli jednak na liście coś jest to, używając roboczego wskaźnika na elementy listy, przewiń go do ostatniego elementu i podepnij pod niego element nowy.
Zwróć wskaźnik do pierwszego elementu listy.
I tyle.
Wtedy jeśli nie wiesz czy lista jest pusta robisz
lst=dodaj(lst,i);, a jeśli wiesz, że coś tam jest to możesz po prostu dodaj(lst,i);
Awatar użytkownika
Mariusz M
Użytkownik
Użytkownik
Posty: 6908
Rejestracja: 25 wrz 2007, o 01:03
Płeć: Mężczyzna
Lokalizacja: 53°02'N 18°35'E
Podziękował: 2 razy
Pomógł: 1246 razy

[C] List jednokierunkowa - dodawanie elementów

Post autor: Mariusz M »

Zordon pisze:spróbuj najpierw poczytać gotowe kody i zobaczyć jak to działa
Zordon w jakim ty świecie żyjesz? Kto będzie gotowe kody pisał jak nawet kodu im się nie chce czytać
i tylko próbują wyciągnąć pieniądze
Zdarzają się nawet tacy że gdy nawet jakiś freier zgodzi się im zapłacić to okazuje się że nie umieją
napisać kodu

Oczywiście przejrzenie gotowego kodu i poeksperymentowanie z nim
(komentowanie bądź dopisywanie pewnych linijek) to dobry pomysł ale
problem w tym że nikomu się nie chce pisać gotowych kodów
Gouranga
Użytkownik
Użytkownik
Posty: 1588
Rejestracja: 16 maja 2013, o 17:56
Płeć: Mężczyzna
Lokalizacja: Trójmiasto
Podziękował: 11 razy
Pomógł: 245 razy

[C] List jednokierunkowa - dodawanie elementów

Post autor: Gouranga »

Zacznijmy od samej definicji typu i funkcji dodaj:

Kod: Zaznacz cały

typedef struct lista {
  int wart;
  lista *nast;
} lista;

void dodaj(lista *l, int nowy){
  if(l != null){
    dodaj(l->nast, nowy);
  } else {
    l = (lista*)malloc(sizeof(lista));
    l->wart = nowy;
    l->nast = null;
  }
}
przejrzyj ten kawałek kodu i powiedz, czy masz pytania co do niego-- 5 mar 2016, o 21:09 --do tego dorzućmy wyświetlanie listy:

Kod: Zaznacz cały

void pokaz(lista *l){
  if(l != null){
    printf("%i ", l->wart);
    pokaz(l->nast);
  }
}
Awatar użytkownika
Mariusz M
Użytkownik
Użytkownik
Posty: 6908
Rejestracja: 25 wrz 2007, o 01:03
Płeć: Mężczyzna
Lokalizacja: 53°02'N 18°35'E
Podziękował: 2 razy
Pomógł: 1246 razy

[C] List jednokierunkowa - dodawanie elementów

Post autor: Mariusz M »

Gdzie masz sprawdzanie czy wystarczy pamięci na węzeł ?
Po co ten warunek na początku ?
Nie wygląda na to abyś wstawiał za bądź przed elementem o danym kluczu
Ja to pisałem z użyciem podwójnego wskaźnika z czego jeden z nich
zastępował referencję która jest dostępna dopiero w C++
Gouranga
Użytkownik
Użytkownik
Posty: 1588
Rejestracja: 16 maja 2013, o 17:56
Płeć: Mężczyzna
Lokalizacja: Trójmiasto
Podziękował: 11 razy
Pomógł: 245 razy

[C] List jednokierunkowa - dodawanie elementów

Post autor: Gouranga »

Pierwszy warunek powoduje rekurencyjne wywołanie żeby dodać na koniec listy.
Awatar użytkownika
Mariusz M
Użytkownik
Użytkownik
Posty: 6908
Rejestracja: 25 wrz 2007, o 01:03
Płeć: Mężczyzna
Lokalizacja: 53°02'N 18°35'E
Podziękował: 2 razy
Pomógł: 1246 razy

[C] List jednokierunkowa - dodawanie elementów

Post autor: Mariusz M »

Gouranga, a co z dodawaniem elementów za i przed elementem o danym kluczu
Ta rekurencja nie przepełni ci stosu ?
Gouranga
Użytkownik
Użytkownik
Posty: 1588
Rejestracja: 16 maja 2013, o 17:56
Płeć: Mężczyzna
Lokalizacja: Trójmiasto
Podziękował: 11 razy
Pomógł: 245 razy

[C] List jednokierunkowa - dodawanie elementów

Post autor: Gouranga »

Jak mamy mieć indeksowanie elementów po kluczach to trzeba to zaimplementować, ja dałem najprostszą gdzie dopisuję zawsze na koniec listy, czyli w sumie bardziej kolejkę.
Awatar użytkownika
Mariusz M
Użytkownik
Użytkownik
Posty: 6908
Rejestracja: 25 wrz 2007, o 01:03
Płeć: Mężczyzna
Lokalizacja: 53°02'N 18°35'E
Podziękował: 2 razy
Pomógł: 1246 razy

[C] List jednokierunkowa - dodawanie elementów

Post autor: Mariusz M »

Ja w sumie mam już napisaną całą listę
no może jeszcze można by dodać zapis i odczyt z pliku

Mam takie funkcje

Kod: Zaznacz cały

// funkcje do obsługi stosu i kolejki 

Funkcja sprawdzają czy lista jest pusta
Funkcja dodająca węzeł na początek listy
Funkcja dodająca węzeł na koniec listy
Funkcja zdejmująca pierwszy węzeł  listy

// funkcje dodające i usuwające węzły

Funkcja dodająca węzeł za węzłem o danym kluczu 
Funkcja dodająca węzeł przed węzłem o danym kluczu
Funkcja usuwająca węzeł o danym kluczu
Funkcja usuwająca wszystkie węzły z listy


// funkcje dodatkowe 

Funkcja zwracająca liczbę węzłów 
Funkcja wyszukująca węzeł o danym kluczu
Funkcja sortująca listę przez scalanie
Funkcja wypisująca dane zawarte w węzłach listy

Plik nagłówkowy

Kod: Zaznacz cały


#ifndef _LISTA_H_
#define _LISTA_H_


struct Node {
       int data;
       struct Node* next;
       };

int isEmpty(struct Node*);
void pushFront(struct Node**,int);
void pushBack(struct Node**,int);
int pop(struct Node**);

void insertNodeBefore(struct Node**,int,int);
void insertNodeAfter(struct Node** ,int ,int );
void deleteNode(struct Node**,int);
void deleteList(struct Node**);

void saveToFile(struct Node* head,char* path);
void loadFromFile(struct Node** head,char* path);

struct Node* findNode(struct Node*,int);
void reverse(struct Node**);
int size(struct Node*);
void printList(struct Node*);

void split(struct Node*,struct Node**,struct Node**);
void merge(struct Node**,struct Node*,struct Node*);
void mergesort(struct Node**);

#endif

Plik z funkcjami obsługującymi listę

Kod: Zaznacz cały


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

 int isEmpty(struct Node* head)
 {
 return (head==NULL);
 }

 void pushFront(struct Node** head,int n)
 {
 struct Node* newNode;
 if((newNode=(struct Node*)malloc(sizeof(struct Node)))==NULL)
{
printf("Brak pamieci na wezel
");
return;
 }
newNode->data=n;
newNode->next=(*head);
 (*head)=newNode;
 }

void pushBack(struct Node** head,int n)
 {
struct Node* newNode;
struct Node* temp;
 if((newNode=(struct Node*)malloc(sizeof(struct Node)))==NULL)
{
printf("Brak pamieci na wezel
");
return;
}
 newNode->data=n;
 newNode->next=NULL;
if(isEmpty((*head)))
{
(*head)=newNode;
 }
else
{
 temp=(*head);
while(temp->next!=NULL)
temp=temp->next;
temp->next=newNode;
}
 }

 int pop(struct Node** head)
{
int val=0;
 struct Node* temp;
 if(!isEmpty((*head)))
{
 temp=(*head);
 val=temp->data;
(*head)=(*head)->next;
free(temp);
 }
 else printf("Struktura jest pusta
");
return val;
}

void deleteNode(struct Node** head,int n)
{
struct Node* aux;
struct Node* previous;
if(isEmpty((*head)))
{
printf("Lista jest pusta
");
}
else
{
aux=(*head);
previous=NULL;
while(aux!=NULL&&aux->data!=n){
previous=aux;
aux=aux->next;
}
if(aux==NULL){
printf("Liczby nie znaleziono na liscie
");
}
else
{
if(previous==NULL)
{
(*head)=(*head)->next;
}
else
{
previous->next=aux->next;
}
free(aux);
}
}
}

void printList(struct Node* head)
{
struct Node* temp;
temp=head;
while(temp!=NULL)
{
printf("%d
",temp->data);
temp=temp->next;
}
}

void deleteList(struct Node** head)
{
    while(!isEmpty((*head)))
    {
        deleteNode(head,(*head)->data);
    }
}

struct Node* findNode(struct Node* head,int n)
{
 struct Node* temp;
 temp=head;
 while(temp!=NULL&&temp->data!=n)
    temp=temp->next;
 return temp;
}

void insertNodeBefore(struct Node** head,int x1,int x2)
{
    struct Node* newNode;
    struct Node* save;
    struct Node* pred;

    if((newNode=(struct Node*)malloc(sizeof(struct Node)))==NULL)
    {
        printf("Brak pamieci na wezel
");
    }
    newNode->data=x2;
    if((*head)==NULL)
    {
        printf("Wezla nie znaleziono 
");
    }
    else
    {
        save=(*head);
        while(x1!=save->data&&save->next!=NULL)
        {
            pred=save;
            save=save->next;
        }
        if(save->data==x1)
        {
            if((*head)==save)
            {
                newNode->next=save;
                (*head)=newNode;
            }
            else
            {
                newNode->next=save;
                pred->next=newNode;
            }
        }
        else
        {
            printf("Wezla nie znaleziono
");
        }
    }

}

void insertNodeAfter(struct Node** head,int x1,int x2)
{
    struct Node* newNode;
    struct Node* save;
    struct Node* pred;

    if((newNode=(struct Node*)malloc(sizeof(struct Node)))==NULL)
    {
        printf("Brak pamieci na wezel
");
        return;
    }
    newNode->data=x2;
    if((*head)==NULL)
    {
        printf("Wezla nie znaleziono
");
    }
    else
    {
        save=(*head);
        while((x1!=save->data)&&(save->next!=NULL))
        {
            pred=save;
            save=save->next;
        }
        if(save->data==x1)
        {
            newNode->next=save->next;
            save->next=newNode;
        }
        else
            {
            printf("Wezla nie znaleziono
");
        }
    }
}

void reverse(struct Node ** head)
{
    struct Node * temp;
    struct Node * curr;
    if(!isEmpty((*head)))
    {
        curr=(*head);
        while(curr->next!=NULL)
        {
            temp=curr->next;
            curr->next=temp->next;
            temp->next=(*head);
            (*head)=temp;
        }
    }
}

void saveToFile(struct Node* head,char* path)
{
    FILE* fp;
    struct Node* temp;

    if ((fp = fopen(path, "wt"))
       == NULL)
   {
      fprintf(stderr, "Cannot open output file.
");
      return ;
   }
   temp=head;
   while(temp!=NULL)
   {
       fprintf(fp,"%d",temp->data);
       temp=temp->next;
   }
   fclose(fp);

}
void loadFromFile(struct Node** head,char* path)
{
    FILE* fp;
    int value;
    if ((fp = fopen(path, "rt"))
       == NULL)
   {
      fprintf(stderr, "Cannot open input file.
");
      return ;
   }
   while(!feof(fp))
   {
     fscanf(fp,"%d",&value);
     pushFront(head,value);
   }
   fclose(fp);
}


int size(struct Node* head)
{
    int no=0;
    struct Node* temp;
    temp=head;
    while(temp!=NULL)
    {
        no++;
        temp=temp->next;
    }
    return no;
}

    void split(struct Node* head,struct Node** front,struct Node** back)
    {
    struct Node* slow;
    struct Node* fast;
    if(head==NULL||head->next==NULL)
    {
    (*front)=head;
    (*back)=NULL;
    }
    else
    {
    slow=head;
    fast=head->next;

    while(fast!=NULL)
    {
    fast=fast->next;
    if(fast!=NULL)
    {
    slow=slow->next;
    fast=fast->next;
    }
    }
    (*front)=head;
    (*back)=slow->next;
    slow->next=NULL;
    }
    }

    void merge(struct Node** head,struct Node* list1,struct Node* list2)
    {
    struct Node* tmp;
    if(list1==NULL) (*head)=list2;
    if (list2==NULL) (*head)=list1;
     if(list1->data<=list2->data)
     {
     (*head)=list1;
     }else{
     (*head)=list2;
     list2=list1;
     list1=(*head);
     }
     while((list1->next!=NULL)&&(list2!=NULL))
     {
     if(list1->next->data<=list2->data){
     list1=list1->next;
     }else{
     tmp=list1->next;
     list1->next=list2;
     list2=tmp;
     }
    }
    if(list1->next==NULL) list1->next=list2;
    }

    void mergesort(struct Node** head)
    {
    struct Node* h1=NULL;
    struct Node* h2=NULL;
    if((*head)!=NULL&&(*head)->next!=NULL)
    {
    split((*head),&h1,&h2);
    mergesort(&h1);
    mergesort(&h2);
    merge(head,h1,h2);
    }
    }


Powinna działać chociaż lepiej aby typem danych był

Kod: Zaznacz cały

void*
Ostatnio zmieniony 24 mar 2016, o 07:48 przez Afish, łącznie zmieniany 1 raz.
Powód: Poprawa wiadomości.
Awatar użytkownika
Mariusz M
Użytkownik
Użytkownik
Posty: 6908
Rejestracja: 25 wrz 2007, o 01:03
Płeć: Mężczyzna
Lokalizacja: 53°02'N 18°35'E
Podziękował: 2 razy
Pomógł: 1246 razy

[C] List jednokierunkowa - dodawanie elementów

Post autor: Mariusz M »

Procedura scalająca niestety nie jest stabilna
(nie zachowuje oryginalnej kolejności przy powtarzających się kluczach)

Znalazłem rekurencyjną funkcję na jakiejś stronie i ciekaw jestem
jak zapisać tę funkcję iteracyjnie z użyciem pętli
Jeszcze jedno przypuśćmy że z jakichś powodów chcemy aby funkcja była
typu

Kod: Zaznacz cały

void
a zwracana wartość przekazywana byłaby jako parametr

Kod tej rekurencyjnej funkcji

Kod: Zaznacz cały

struct node* SortedMerge(struct node* a, struct node* b)
{
  struct node* result = NULL;
 
  /* Base cases */
  if (a == NULL)
     return(b);
  else if (b==NULL)
     return(a);
 
  /* Pick either a or b, and recur */
  if (a->data <= b->data)
  {
     result = a;
     result->next = SortedMerge(a->next, b);
  }
  else
  {
     result = b;
     result->next = SortedMerge(a, b->next);
  }
  return(result);
}
Awatar użytkownika
Mariusz M
Użytkownik
Użytkownik
Posty: 6908
Rejestracja: 25 wrz 2007, o 01:03
Płeć: Mężczyzna
Lokalizacja: 53°02'N 18°35'E
Podziękował: 2 razy
Pomógł: 1246 razy

[C] List jednokierunkowa - dodawanie elementów

Post autor: Mariusz M »

Pytanie do wpisu z 5 marca 2016, 21:04
Sprawdzałeś czy to działa czy pisałeś z pamięci
Przydałaby się do pary procedura usun którą też można napisać rekurencyjnie
ODPOWIEDZ