You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在带表头的C语言双向链表中按姓氏排序?

解决C语言双向链表存储字符串及按姓氏排序的问题

一、改造双向链表存储字符串

你原来的链表存整数,现在要存姓氏字符串,得从结构体开始改:

1. 修改结构体定义

把整数字段换成字符串指针,C里用char*存字符串:

typedef struct elemento{ 
    char *sobrenome;  // 存储姓氏
    struct elemento *ant; 
    struct elemento *prox;
}Elem;

typedef struct elemento* Lista;

2. 调整插入函数

插入时要给字符串分配内存,用strdup(自动分配内存并复制字符串)最方便,也可以用malloc加strcpy:

// 插入开头的修改版
int Inserir_Inicio(Lista *Lista_Nomes, const char *sobrenome){
    if(Lista_Nomes == NULL || sobrenome == NULL) 
        return 0;
        
    Elem *no = (Elem*)malloc(sizeof(Elem)); 
    if(no == NULL) 
        return 0;
    
    // 给字符串分配内存并复制内容
    no->sobrenome = strdup(sobrenome);
    if(no->sobrenome == NULL){ // 字符串分配失败就释放节点
        free(no);
        return 0;
    }
    
    no->ant = NULL; 
    no->prox = (*Lista_Nomes); 
    
    if (*Lista_Nomes != NULL) 
        (*Lista_Nomes)->ant = no; 
    *Lista_Nomes = no; 
    
    return 1; 
}

插入结尾的函数同理,只需要替换字符串处理部分。

3. 调整打印函数

打印时直接输出字符串,还要修改Printagem_Dinamica来适配字符串长度:

// 适配字符串的打印辅助函数
void Printagem_Dinamica(int margem, const char *str){ 
    int q_char = strlen(str);
    
    char *t = (char*)malloc((q_char + 1)*sizeof(char));
    if(t == NULL) return;
    
    int i=0;
    while(i < q_char){ 
        t[i]='-';
        i++;
    }
    t[q_char]='\0'; 
    
    if(margem == 1)
        printf(" ,_.--%s--.  ", t); 
    if(margem == 2)
        printf("   `--%s--´  ", t); 
    free(t); // 记得释放临时内存
}

// 修改打印链表的函数
void Printar_Elemento(Lista *Lista_Nomes){
    int br[3];
    Lista aux1, aux2, aux3;
    aux1 = aux2 = aux3 = (*Lista_Nomes);
    
    printf("NULL\n"); 
    do{
        br[0]=0;
        while(aux1 != NULL){
            Printagem_Dinamica(1, aux1->sobrenome); 
            aux1 = aux1->prox;
            
            br[0]++;
            if(br[0] % ELEM_LINHA == 0)
                break;
        }
        printf("\n");
        
        br[1]=0;
        while(aux2 != NULL){
            printf(" ` || %s ||->", aux2->sobrenome); // 这里改成输出字符串
            aux2 = aux2->prox;
            
            br[1]++;
            if(br[1] % ELEM_LINHA == 0)
                break;
        }
        
        br[2]=0;
        printf("\n");
        while(aux3 != NULL){
            Printagem_Dinamica(2, aux3->sobrenome); 
            aux3 = aux3->prox;
            
            br[2]++;
            if(br[2] % ELEM_LINHA == 0)
                break;
        }
        
        if(br[0] < ELEM_LINHA) 
            printf("NULL"); 
        printf("\n\n");
        
    }while(aux3 != NULL); 
}

4. 新增内存释放函数

因为存了字符串,要先释放字符串再释放节点,避免内存泄漏:

void Liberar_Lista(Lista *Lista_Nomes){
    if(Lista_Nomes == NULL) return;
    Elem *aux = *Lista_Nomes;
    while(aux != NULL){
        Elem *prox = aux->prox;
        free(aux->sobrenome); // 先释放字符串
        free(aux); // 再释放节点
        aux = prox;
    }
    free(Lista_Nomes);
}

二、按姓氏字母排序双向链表

用冒泡排序最简单,直接交换节点里的字符串指针就行:

#include <string.h> // 要包含这个头文件用strcmp

void Ordenar_Lista(Lista *Lista_Nomes){
    if(Lista_Nomes == NULL || *Lista_Nomes == NULL) return;
    
    int trocou;
    Elem *atual;
    Elem *fim = NULL;
    
    do{
        trocou = 0;
        atual = *Lista_Nomes;
        
        while(atual->prox != fim){
            // strcmp返回正数表示前者字母顺序靠后,需要交换
            if(strcmp(atual->sobrenome, atual->prox->sobrenome) > 0){
                // 直接交换两个节点的字符串指针,比交换节点本身简单
                char *temp = atual->sobrenome;
                atual->sobrenome = atual->prox->sobrenome;
                atual->prox->sobrenome = temp;
                trocou = 1;
            }
            atual = atual->prox;
        }
        fim = atual;
    }while(trocou);
}

如果要支持葡萄牙语带重音的姓氏,把strcmp换成strcoll,配合你代码里的setlocale(LC_ALL, "portuguese")就能按本地化规则排序。

整合后的主函数示例

int main(void){
    setlocale(LC_ALL, "portuguese");
    char sobrenome[50];
    Lista *Lista_Nomes = Criar_Lista();
    
    printf("Digite sobrenomes (digite 'sair' para parar):\n");
    while(1){
        printf("Informe um sobrenome: ");
        scanf("%s", sobrenome);
        if(strcmp(sobrenome, "sair") == 0) break;
        
        if(!Inserir_Final(Lista_Nomes, sobrenome)){
            printf("Erro de memória!\n");
            break;
        }
        system("CLS");
        Printar_Elemento(Lista_Nomes);
    }
    
    // 排序后打印
    printf("\nLista ordenada por sobrenome:\n");
    Ordenar_Lista(Lista_Nomes);
    Printar_Elemento(Lista_Nomes);
    
    Liberar_Lista(Lista_Nomes);
    return 0;
}

内容的提问来源于stack exchange,提问作者Otacir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 08:55:19