Ir ao conteúdo
  • Cadastre-se

C Função para remover último elemento de uma lista encadeada em C


Posts recomendados

Minha função remover_valor_final para remover o último elemento de uma lista encadeada em C até que funciona com 2 ou mais elementos, porém quando a lista só possuí 1 elemento ela não funciona.

 

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <windows.h>
#include <ctype.h>

typedef struct sDisciplina{
	char nome[20];
	char codigo[10];
	int credito;
	int carga_horaria;
}Disciplina;

typedef struct sNo{
	Disciplina disciplina; // Guarda as informações, dados
	struct sNo *prox; // Guarda o próximo endereço da lista
}No;

No* inic(No* lista){ // Iniciar
	lista = NULL; // Atribui NULL mostrando que a lista está vazia
	return lista;
}


No* alocarNo(){ // Alocar
	return (No*) malloc(sizeof(No));
}

void desalocarNo(No* q){ // Desalocar
	free(q);
}

No* lista_vazia(No* lista){ // Verificar se a lista está vazia
	if(lista == NULL){ // Verificando se o primeiro No aponta para NULL
		return; // Sim, está vazia
	}else{
		return lista; // Não, não está vazia
	}
}

No* inserir_inicio(No *lista, char nome[], char codigo[], int credito, int carga_horaria){
	No *novo;
	novo = alocarNo(); // Novo nó criado na memória principal
	if(novo == NULL){ // Testando se alocou
		printf("Impossível alocar, erro");exit(1);
	}
	strcpy(novo->disciplina.nome,strupr(nome));
	strcpy(novo->disciplina.codigo,strupr(codigo)); // Deixando todo codigo em maiusculo
	novo->disciplina.credito = credito;
	novo->disciplina.carga_horaria = carga_horaria;
	novo ->prox = lista; // Aponta para o primeiro elemento
	lista = novo; // Aponta agora para o segundo elemento
	return lista; // Para o ponteiro da função main enxergue a alteração
}

void imprimir_lista(No *lista){
	system ("cls");
	if(lista_vazia(lista) != NULL){
		printf("\n\n >> Conteúdo da lista <<\n");
		while(lista != NULL){ // Percorrendo a lista até encontrar NULL que é o final
			printf("\n %s",lista->disciplina.nome);
			printf(" - %s", lista->disciplina.codigo);
			printf("\n %d Créditos",lista->disciplina.credito);
			printf("\n %d Horas",lista->disciplina.carga_horaria);
			printf("\n");
			lista=lista->prox;
		}
		printf("\n\n");
		system ("pause");
		system ("cls");
	}else{
		system ("cls");
		printf("\n\n >> Lista Vazia << \n\n");
		sleep(2);
		system("cls");
	}
}
	
No* pesquisar(No *lista, char codigo[]){

	No *aux;
	aux = lista; //Apontar o primeiro auxiliar para o início da lista para ele buscar dentro dela
	if(lista_vazia(lista) != NULL){ // Há itens na lista
		while(aux != NULL){
			if(strcmp(aux->disciplina.codigo,strupr(codigo)) == 0){ // Percorre a lista atrás do elemento
				return aux; // encontrou o nó e retorna o endereço dele
			}
			aux = aux->prox; // Passa para o próximo nó atrás do valor
		}
	}
	return NULL; // Não encontrou o nó
}

No* remover_inicio(No *lista){
	No *q;
	q = lista; // Aponta para o primeiro elemento
	
	if(lista_vazia(lista) != NULL){//Verifica se há itens na lista
		lista = q->prox; // Faz com que o ponteiro lista, aponte para o segundo elemento excluindo o primeiro
		desalocarNo(q); //Remover definitavamente o elemento que até então era o primeiro
		return lista; // Retornamos agora o primeiro o novo endereço do primeiro ponteiro
	}else{
		printf("\nERRO: LISTA VAZIA. \n");
		return NULL;
	}
}

No* remover_valor(No *lista, char codigo[]){
	No *q; // Apontará para o elemento a ser removido
	No *aux; // Vai percorrer a lista
	if((q = pesquisar(lista, codigo)) != NULL){ //Procura na lista e passa a apontar para o elemento pesquisado
		aux = lista; // aponta para o início
		if(aux == q){ // Se o valor estiver no início, ele é excluido
			remover_inicio(lista);
		}else{ //Percorrer a lista
			while(aux -> prox!=q){ // Percorrer a lista e para uma ponsição antes do ponteiro q
				aux = aux->prox;
			}
			aux->prox = q->prox; // O nó auxiliar passa a apontar para o nó que o nó excluído apontava
			desalocarNo(q); // Apaga o nó desejado
		}
		system ("cls");
		printf("\n\n >> Disciplina removida com Sucesso! <<\n\n");
		sleep(2);
		return lista; // removeu o elemento e retornamos o ponteiro
	}
	system ("cls");
	printf("\n\n >> Disciplina não removida, pode não ter sido encontrado ou ocorreu um erro! <<\n\n");
	sleep (2);
	system ("cls");
	return NULL; // não removeu o elemento
}

void imprimir_lista_sistemas(No *lista){
	system ("cls");
	char aux[] = {'S','I','N'};
	if(lista_vazia(lista) != NULL){
		printf("\n\n >> Disciplinas de Sistemas de Informação <<\n");
		while(lista != NULL){ // Percorrendo a lista até encontrar NULL que é o final
			if((strstr(aux,lista->disciplina.codigo) == 0) && (lista->disciplina.carga_horaria >= 60)){
				printf("\n %s",lista->disciplina.nome);
				printf(" - %s", lista->disciplina.codigo);
				printf("\n %d Créditos",lista->disciplina.credito);
				printf("\n %d Horas",lista->disciplina.carga_horaria);
				printf("\n");
			}
			lista=lista->prox;
		}
		printf("\n\n");
		system ("pause");
		system ("cls");
	}else{
		system ("cls");
		printf("\n\n >> Lista Vazia << \n\n");
		sleep(2);
		system("cls");
	}
}

void ordenar_alfabeticamente(No* *lista){ //Bublle sort
	if(*lista == NULL || (*lista)->prox == NULL){
		return; // Se tiver apenas 1 disciplina ou se não tiver sido cadastrada nenhuma
	}
	
	No *aux = *lista, *t;
    char s[50]; // Armazenar o nome da disciplina

    while(aux != NULL) {
      t = aux->prox;
      while(t != NULL) {
        if(strcmp(aux->disciplina.nome, t->disciplina.nome) > 0) { //se vir depois
            strcpy(s, aux->disciplina.nome);
            strcpy(aux->disciplina.nome, t->disciplina.nome);
            strcpy(t->disciplina.nome, s);
        }
        t = t->prox;
      }
      aux = aux->prox;
	}
}

No* remover_valor_final(No* *lista){
	No* ultimo;
	No* penultimo;
	if(*lista == NULL){
        printf("\n\n >> Lista vazia << \n\n");
        return;// Não faz nada
    }
    else{
        ultimo = (*lista)->prox;
		penultimo = (*lista)->prox;
        while(ultimo->prox!=NULL){
            penultimo=ultimo;
            ultimo=ultimo->prox;
        }
        penultimo->prox=NULL;
    }
}

int main(){
	setlocale(LC_ALL, "Portuguese"); //Deixar em português, com acentos e ç
	int opc, credito, carga_horaria;
	char nome[50], codigo[10];
	
	No *ptrLista; // Aponta para o início da lista
	// O ultímo Nó armarzena o endereço NULL pra dizer que chegou ao fim
	ptrLista = inic(ptrLista); // Iniciar
	No *q = alocarNo(); // ALocar um nó vazio com um ponteiro apontado para ele

	do{
		printf("\n\n\t\t\t>> MENU <<");
		printf("\n\n 1- Inserir a disciplina na lista dinâmica em ordem alfabética");
		printf("\n\n 2- Remover uma determinada disciplina pelo código");
		printf("\n\n 3- Exibir as disciplinas que são do curso de Sistemas de Informação");
		printf("\n\n\n >> Exercícios complementares, favor ignorar << \n");
		printf("\n\n 4- Remover elemento do final da lista dinâmica");
		printf("\n\n 5- Concatenar com outra lista dinâmica, na qual terá apenas três disciplinas genéricas\n\n >> Digite a opção desejada: ");

		scanf("%d",&opc);

		switch(opc){
			case 1:
				printf("\n >> Digite o nome da disciplina que deseja inserir: ");
				fflush(stdin);
				gets(nome);
				printf("\n >> Digite o código da disciplina que deseja inserir: ");
				fflush(stdin);
				gets(codigo);
				printf("\n >> Digite o número de créditos da disciplina que deseja inserir: ");
				fflush(stdin);
				scanf("%d",&credito);
				printf("\n >> Digite a carga horária da disciplina que deseja inserir: ");
				fflush(stdin);
				scanf("%d",&carga_horaria);
				ptrLista = inserir_inicio(ptrLista, nome, codigo, credito, carga_horaria);
				system ("cls");
				printf("\n >> Inserido com Sucesso! <<\n\n");
				ordenar_alfabeticamente(&ptrLista);
				//sleep(2);
				system ("cls");
				imprimir_lista(ptrLista);
			break;
			case 2:
				printf("\n >> Digite o código da disciplina que deseja remover: ");
				fflush(stdin);
				gets(codigo);
				ptrLista = remover_valor(ptrLista, codigo);
				system ("cls");
				imprimir_lista(ptrLista);
			break;
			case 3:
				system ("cls");
				imprimir_lista_sistemas(ptrLista);
			break;
			case 4:
				ptrLista = remover_valor_final(&ptrLista);
				system ("cls");

			break;
			default:
				system ("cls");
				printf("\n\n >> DIGITE UM VALOR VÁLIDO << \n\n");
				sleep(2);
				system ("cls");
		}

	}while(1); // Mantendo em loop
	desalocarNo(q);
	return 0;
}

 

Link para o comentário
Compartilhar em outros sites

No* inserir_inicio(No *lista, char nome[], char codigo[], int credito, int carga_horaria);

 

Evite esse tipo de construção. Prefira sempre escrever em torno dos dados enquanto estruturas. Você quer inserir uma nó na lista, e um nó é uma disciplina nesse caso mas podia ser qualquer coisa em outro caso. Prefira

 

    Lista* inserir_inicio( Disciplina* D, Lista* L );

 

passando o endereço de um registro e não os campos um por um. Não faz sentido escrever como fez e só atrasa os testes e dificulta  a manutenção. Imagine que ao mudar um campo na estrutura de disciplina você vai ter que mudar a rotina que insere na lista, e nada tem a ver uma coisa com a outra

 

E prefira um nó como

 

typedef struct sNo
{
    Disciplina*	    D; // Guarda as informações, dados
    struct sNo*     ant;
    struct sNo*     prox; // Guarda o próximo endereço da lista
}No;

 

porque do modo como escreveu a disciplina fica DENTRO do nó e em outros casos, muitos outros, você pode não querer isso. Por exemplo, pode querer remover o nó sem remover a Disciplina. Imagine que um programa entra com um vetor Grade que é um vetor de... Disciplina. Você tem isso na memória e pode usar para construir as turmas, onde os alunos usam referências --- ponteiros --- às mesmas disciplinas. Nada tem a ver com a lista. Do modo como escreveu isso não funcionaria, e como isso é a realidade você está dificultando sua própria solução.
 

Citação

Quanto mais perto da realidade seu modelo está menos trabalho você tem para programar. Escreva em torno dos dados.

 

Mais ainda imagine um nó como

 

typedef struct sNo
{
    void*           dado; // qualquer coisa
    struct sNo*     ant;
    struct sNo*     prox; // Guarda o próximo endereço da lista
  
}   No;

 

E perceba que se usar um ponteiro genérico não precisa mudar nunca...

 

Mais ainda: entenda que uma lista não é um nó e um nó não é uma lista. E um dado não é um nó. Um nó tem uma referência a um registro de dados. E um campo do registro de dados é uma chave, usada para comparar um registro com outro, e isso vale para todas essas estruturas tipo container, listas, mapas, filas, pilhas, conjuntos, hash e tal...

 

Uma lista é um conjunto S de nós, onde cada nó N tem referência a um dado x. E cada dado x tem uma chave k que pode ser por exemplo no seu caso o código da disciplina.
 

Imagine isso 

 

typedef struct
{
    No*     inicio;
    No*     fim;
    int     limite;
    char*   nome;
    int     tamanho;

}   Lista;

 

E entenda que assim não teria tido problemas ao remover o único elemento da lista, porque a Lista não é um nó. E a Lista tem DENTRO dela o contador de nós e o limite. E um ponteiro para o início e outro para o fim.

 

 

Evite a todo custo usar listas com ponteiros só para um lado: isso é um pesadelo e tudo que vai fazer dá muito mais trabalho. Só use quando for claramente adequado ao modelo de dados ou quando os bytes relativos ao ponteiro adicional forem realmente fazer falta.

Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...