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

#define TYPE int
#define TYPE_DESC d

typedef struct _elem {
	TYPE data;
	struct _elem *next;
} elem;

void print_lista(elem *l);

elem *create_elem(TYPE data){
	elem *res=(elem *)malloc(sizeof(elem));
	res->data=data;
	res->next=0;
    return res;
}

void free_elem(elem *e){
	free(e);
}

void free_lista(elem *e){
	if (e->next!=0) free_lista(e->next);
	free_elem(e);
}

elem *conc_lista(elem *l1, elem *l2){
	elem *curr;
	if (l1==0) return l2; /* necessaria per evitare curr->next su 0 */
	if (l2==0) return l1; /* per performance */
	for(curr=l1; curr->next!=0; curr=curr->next);
	curr->next=l2;
	return l1;
}

elem *insert_in_order(elem *l, elem *e){
	elem *curr=0;
	elem *prec=0;
	
	/* Cerca la posizione per l'inserimento */
	for(curr=l, prec=0;  /* posizione iniziale (in testa) */
	    (curr!=0) && (curr->data < e->data); 
                             /* controllo (1) di non essere in coda e (2) 
                                se l'elemento corrente e' maggiore di quello
                                da inserire */
	    prec=curr, curr=curr->next) /* non c'e' corpo */;  
                             /* mantiene memoria dell'ultima posizione 
                                visitata */
	
	/* Esegui inserimento */
	if (prec==0) { /* curr == l, inserimento in testa */
		e->next=l;
		return e;
	} else { /* in posizione diversa dalla testa, fra prec e curr */
		prec->next=e;
		e->next=curr;
		return l;
	}
}

elem *sort_lista(elem *l){
	elem *res;	
	if (!l || l->next==0) return l;
	res=sort_lista(l->next);
	print_lista(res);
	l->next=0;
	return insert_in_order(res, l);
}

elem *insert_in_testa(elem *l, TYPE data){
	elem *curr=create_elem(data);
	curr->next=l;
	return curr;
}

void print_lista(elem *l){
	if (l==0) {
		printf("\n");
	} else {
		printf("%d ", l->data);
		print_lista(l->next);
	}
}

elem *insert_in_coda(elem *l, TYPE data){
	elem *curr;
	if (l==0) return create_elem(data);
	for(curr=l; curr->next!=0; curr=curr->next);
	curr->next=create_elem(data);
	return l;
}

elem *delete_from_lista(elem *l, elem *e){
	elem *curr;
	if (l==0) return 0;
	if (l==e) {
		curr=e->next;
		free_elem(e);
		return curr;
	}
	for(curr=l; curr!=0 && curr->next!=e; curr=curr->next);
	if (curr==0) return l; /* elemento non presente */
	curr->next=e->next; 
	free_elem(e);
	return l;
}

elem *search_lista(elem *l, TYPE data){
	if (l==0) return 0;
	if (l->data==data) return l;
	return search_lista(l->next, data);
}

int main(int argc, char **argv){
	elem *l=0, *curr;
	l=insert_in_testa(l,10);
	l=insert_in_testa(l,5);
	l=insert_in_testa(l,11);
	l=insert_in_testa(l,7);
	l=insert_in_testa(l,2);
	print_lista(l);
	l=sort_lista(l);
	print_lista(l);
}
