C语言基于谓词函数筛选链表元素构建新链表的实现问题
问题根因
你当前实现的split函数逻辑完全不符合筛选需求,存在以下核心错误:
- 没有逐个筛选节点并添加到新链表,每次匹配到符合谓词的节点时,直接把当前节点之后的整段原链表整体赋值给新链表,直接覆盖新链表之前的所有内容
- 直接篡改原链表的尾指针、节点指向、元素数量等元信息,彻底破坏了原链表的结构
- 硬编码判断谓词返回值等于1,不符合你最初定义的「谓词返回非零即符合条件」的规则
- 没有统计新链表的实际元素数量,直接复用原链表的数量值,元信息完全错误
基础依赖声明
首先明确你的链表结构通常的定义,以及默认已经实现的基础工具函数:
// 节点结构 typedef struct Noh { void *info; struct Noh *prox; } Noh, *pNoh; // 链表结构 typedef struct DLista { pNoh primeiro; pNoh ultimo; int quantidade; } DLista, *pDLista; // 基础工具函数,你已经实现无需额外编写 pDLista criarLista(); // 创建空链表 void adicionar(pDLista lista, void *info); // 向链表尾部追加元素
正确实现方案
根据你的需求不同,提供两种实现:
方案1:不修改原链表,复制符合条件的元素到新链表
适合只需要筛选结果、不需要改动原链表的场景:
pDLista split(pDLista pd, FuncaoPredicado fp) { pDLista pNovaListaComPredicado = criarLista(); pNoh atual = pd->primeiro; while(atual != NULL) { // 谓词返回非零即符合条件,不要硬判等于1 if(fp(atual->info)) { // 直接拷贝元素指针添加到新链表,如果是复杂结构可自行调整拷贝逻辑 adicionar(pNovaListaComPredicado, atual->info); } atual = atual->prox; } return pNovaListaComPredicado; }
方案2:拆分原链表,把符合条件的节点移到新链表
符合split函数的语义,执行后原链表仅保留不符合谓词的节点:
pDLista split(pDLista pd, FuncaoPredicado fp) { pDLista pNovaListaComPredicado = criarLista(); pNoh atual = pd->primeiro; pNoh anterior = NULL; while(atual != NULL) { pNoh proximo = atual->prox; if(fp(atual->info)) { // 把当前节点从原链表摘除 if(anterior == NULL) { pd->primeiro = proximo; } else { anterior->prox = proximo; } if(atual == pd->ultimo) { pd->ultimo = anterior; } pd->quantidade--; // 把当前节点挂载到新链表 atual->prox = NULL; if(pNovaListaComPredicado->primeiro == NULL) { pNovaListaComPredicado->primeiro = atual; pNovaListaComPredicado->ultimo = atual; } else { pNovaListaComPredicado->ultimo->prox = atual; pNovaListaComPredicado->ultimo = atual; } pNovaListaComPredicado->quantidade++; } else { anterior = atual; } atual = proximo; } return pNovaListaComPredicado; }
调用说明
你原来的调用逻辑不需要修改,针对原链表1-3-5-6-9,执行后新链表会返回3-6-9,完全符合筛选需求。注意你原来代码里的FuncaoImpressao pfi参数没有用到,可以直接删除。
内容的提问来源于stack exchange,提问作者Vagner Wentz
相关产品推荐
相关产品推荐

