C语言如何将未排序链表过滤后无需预先排序直接按升序写入文件
数据结构作业问题解决方案
核心实现逻辑
作业要求写入文件前不能对原列表排序,我们可以通过构建临时有序链表实现需求,全程不会修改原链表的内容和顺序:
- 遍历原链表,过滤掉所有需移除的元素(能被3整除、包含数字3)
- 对每个符合保留条件的元素,创建新节点复制值后,按升序插入到临时链表中
- 遍历完成后直接将临时有序链表的内容写入文件即可
修改后的完整代码
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<time.h> #include<string.h> #include<stdbool.h> #define BUFFER_LENGTH 256 typedef struct lista* Poz; typedef struct lista { int br; Poz next; }lista; bool containsDigit(int, int); int PrintList(Poz); int PrintRandom(int, int); Poz StvoriCvor(); int PrintToFile(Poz); // 新增:向有序链表插入元素的函数 int InsertSorted(Poz sortedHead, int num); bool containsDigit(int number, int digit) { // 单独处理数字0的情况,避免进入循环直接返回false if (number == 0) { return digit == 0; } while (number != 0) { int curr_digit = number % 10; if (curr_digit == digit) return true; number /= 10; } return false; } int InsertSorted(Poz sortedHead, int num) { Poz newNode = StvoriCvor(); if (newNode == NULL) { return -1; } newNode->br = num; // 寻找插入位置 Poz curr = sortedHead; while (curr->next != NULL && curr->next->br < num) { curr = curr->next; } // 插入节点 newNode->next = curr->next; curr->next = newNode; return 0; } int PrintToFile(Poz P) { int digit = 3; if (P == NULL) return -1; char* fileName = NULL; FILE* fp; fileName = (char*)malloc(sizeof(char) * BUFFER_LENGTH); if (fileName == NULL) return -1; printf("请输入文件名:\n"); scanf("%s", fileName); fp = fopen(fileName, "w+"); if (fp == NULL) { free(fileName); return -1; } // 初始化临时有序链表头 lista sortedHead = {0, NULL}; while (P != NULL) { if (!(P->br % 3 == 0 || containsDigit(P->br, digit) == true)) { // 符合保留条件的元素插入有序链表 InsertSorted(&sortedHead, P->br); } P = P->next; } // 将有序链表写入文件 Poz temp = sortedHead.next; while (temp != NULL) { fprintf(fp, "%d\n", temp->br); // 写入后释放临时节点内存 Poz toFree = temp; temp = temp->next; free(toFree); } fclose(fp); free(fileName); return 0; } int PrintRandom(int min, int max) { int num = (rand() % (max - min + 1) + min); return num; } int PrintList(Poz P) { P = P->next; if (P == NULL) { printf("链表为空.\n"); } else { printf("链表中的元素如下:\n"); while (P != NULL) { printf("%d ", P->br); P = P->next; } printf("\n"); } return 0; } Poz StvoriCvor() { Poz Q = NULL; Q = (Poz)malloc(sizeof(lista)); if (Q == NULL) { printf("创建节点失败.\n"); return NULL; } Q->next = NULL; return Q; } int main() { lista head; head.next = NULL; Poz Q = NULL; int min = 0, max = 100, count = 30; srand(time(0)); for (int i = 0; i < count; i++) { Q = StvoriCvor(); if (Q == NULL) { printf("创建节点失败.\n"); } else { Q->br = PrintRandom(min, max); // 这里如果要严格按生成顺序存链表,应该用尾插,原代码是头插会倒序,需要的话可以修改为尾插 Q->next = head.next; head.next = Q; } } PrintList(&head); PrintToFile(head.next); // 释放原链表内存,避免泄漏 Poz temp = head.next; while (temp != NULL) { Poz toFree = temp; temp = temp->next; free(toFree); } return 0; }
额外优化说明
- 修复了
containsDigit函数对数字0的判断逻辑漏洞 - 补充了所有动态分配内存的释放逻辑,避免内存泄漏
- 将原代码中的克罗地亚语提示替换为中文,更便于阅读
- 原代码生成链表用了头插法,存入顺序和生成顺序相反,如果需要严格符合"按生成顺序存入链表"的要求,可以修改为尾插法实现
内容的提问来源于stack exchange,提问作者duje.je
相关产品推荐
相关产品推荐

