AI大法之C语言哈希表算法比较两个文件去重

最近朋友在工作上遇到了一个问题,经常需要比对两个文件,筛选出文件中不同的订单号。比如有两个文件:计费.txt受理.txt,文件中每一行都是一个订单号,需要找出计费.txt文件中有而受理.txt文件中没有的单号和计费.txt文件中没有而受理.txt文件中有的单号。

虽然有点绕,但仔细一看不就是简单的去重问题吗。于是我就说,这都2024年了,你把这两个文件上传给豆包文心一言kimi这些AI模型,直接让AI帮你找出来不就完事了么。结果并没有想象的那么顺利,由于文件行数不确定,大致在1W-20W行不等,上传给AI时,只给你加载一半数据,也不知道是不是没开会员的原因,想白嫖AI这条路算是行不通了。

于是我提出,干脆写个shell脚本去做这个操作呗。但朋友嫌弃shell脚本太慢了,想让我用C语言帮忙写一个,并请我喝奶茶。我心想这事情简单,有奶茶喝我就给你干了。

刚开始思路是,打开一个文件读一行,跟另一个文件每一行比,比完发现没有重复就存到一个新文件。后面一想,这样做文件行数一多,效率肯定极慢。于是问了问豆包,有什么好办法,豆包给出了个哈希表算法的建议。当了这么久牛马了,现在有了AI这个牛马,我肯定是不会自己从零开始撸代码的了,先让AI帮我写一段。

我copy过来,果然不出所料,编译都编不过。返回来质问AI,AI又老老实实给我整了一段,我找朋友要了两个测试数据,一测试发现不行,然后又让它改,然后给他提了一系列要求、比如哈希碰撞处理什么的,就这么一步步在我的调教下,终于写出了一段能用的代码。大家如果用得上可自取:

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h> // 用于isspace函数

#define MAX_LINE_LENGTH 1024
#define HASH_TABLE_SIZE 100000

typedef struct Node {
    char *singleNumber;
    struct Node *next;
} Node;

Node *hashTable[HASH_TABLE_SIZE];

// 函数声明
unsigned int hashFunction(const char *str);
void insertHash(Node **hashTable, const char *singleNumber);
int containsHash(Node **hashTable, const char *singleNumber);
void freeHashTable(Node *hashTable[]);
int isNotBlankLine(const char *line);
char* trim(const char *str);

int generaFile(const char *filename1, const char *filename2)
{
    FILE *file1, *file2, *outputfd;
    char output_filename[1024] = {0};
    strncpy(output_filename, filename2, strlen(filename2) - 4);
    strcat(output_filename, "_去重后.txt");

    char line[MAX_LINE_LENGTH];
    // 初始化哈希表
    for (int i = 0; i < HASH_TABLE_SIZE; i++) {
        hashTable[i] = NULL;
    }
    // 读取第一个文件并构建哈希表
    file1 = fopen(filename1, "r");
    if (!file1) {
        perror("Error opening file1");
        return EXIT_FAILURE;
    }
    while (fgets(line, MAX_LINE_LENGTH, file1)) {
        char *trimmedLine = trim(line);
        if (isNotBlankLine(trimmedLine)) {
            insertHash(hashTable, trimmedLine);
        }
        free(trimmedLine);
    }
    fclose(file1);
    printf("load %s hash finish!\n", filename1);

    // 读取第二个文件并删除共同的单号
    file2 = fopen(filename2, "r");
    outputfd = fopen(output_filename, "w+");
    if (!file2 || !outputfd) {
        perror("Error opening file2 or outputfd");
        return EXIT_FAILURE;
    }

    while (fgets(line, MAX_LINE_LENGTH, file2)) {
        char *trimmedLine = trim(line);
        line[strcspn(line, "\n")] = 0; // 移除换行符
        if (isNotBlankLine(trimmedLine) && !containsHash(hashTable, trimmedLine)) { // 没有找到相同的且不是空行
            fputs(trimmedLine, outputfd);
            fputc('\n', outputfd); // 使用fputc确保只写入一个换行符
        }
        free(trimmedLine);
    }
    fclose(file2);
    fclose(outputfd);

    // 释放哈希表
    freeHashTable(hashTable);

    return EXIT_SUCCESS;
}

int isNotBlankLine(const char *line) {
    // 检查每一字符是否都是空白字符,如果是,则返回0,否则返回1
    while (*line) {
        if (!isspace((unsigned char)*line)) {
            return 1;
        }
        line++;
    }
    return 0;
}

char* trim(const char *str) {
    if (str == NULL) return NULL;
    const char *end;
    size_t len = strlen(str);
    // Trim leading space
    while (isspace((unsigned char)*str)) str++;
    if (*str == 0)  // All spaces?
        return strdup("");
    // Trim trailing space
    end = str + len - 1;
    while (end > str && isspace((unsigned char)*end)) end--;
    // The len is the number of non-space chars
    len = (end - str + 1);
    char *trimmed = (char *)malloc(len + 1);
    if (trimmed) {
        snprintf(trimmed, len + 1, "%s", str);
        trimmed[len] = '\0';
    }
    return trimmed;
}

int main(int argc, char *argv[])
{
    char *filename1 = argv[1];
    char *filename2 = argv[2];
    if (argc != 3) {
        printf("请指定要去重的两个文件!\n");
        printf("用法: ./quchong 文件1 文件2\n");
        printf("示例:./quchong 受理.txt 计费.txt\n");
        return 0;
    }

    if (generaFile(filename1, filename2) != EXIT_SUCCESS) {
        printf("%s 去重失败!", filename2);
        return EXIT_FAILURE;
    }

    // 注意:这里应该重新初始化哈希表
    for (int i = 0; i < HASH_TABLE_SIZE; i++) {
        hashTable[i] = NULL;
    }
    if (generaFile(filename2, filename1) != EXIT_SUCCESS) {
        printf("%s 去重失败!", filename1);
        return EXIT_FAILURE;
    }

    printf("数据去重完成!\n");

    return EXIT_SUCCESS;
}

// 哈希函数
unsigned int hashFunction(const char *str)
{
    unsigned int hash = 5381;
    int c;
    while ((c = *str++)) {
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
    }
    return hash % HASH_TABLE_SIZE;
}

// 插入哈希表
void insertHash(Node **hashTable, const char *singleNumber)
{
    unsigned int index = hashFunction(singleNumber);
    Node *newNode = (Node *)malloc(sizeof(Node));
    if (!newNode) {
        perror("Memory allocation failed");
        exit(EXIT_FAILURE);
    }
    newNode->singleNumber = strdup(singleNumber);
    if (!newNode->singleNumber) {
        free(newNode);
        perror("Memory allocation failed");
        exit(EXIT_FAILURE);
    }
    newNode->next = hashTable[index];
    hashTable[index] = newNode;
}

// 检查哈希表中是否包含某个单号
int containsHash(Node **hashTable, const char *singleNumber)
{
    unsigned int index = hashFunction(singleNumber);
    Node *current = hashTable[index];
    while (current) {
        if (strcmp(current->singleNumber, singleNumber) == 0) {
            return 1;
        }
        current = current->next;
    }
    return 0;
}

// 释放哈希表内存
void freeHashTable(Node *hashTable[])
{
    for (int i = 0; i < HASH_TABLE_SIZE; i++) {
        Node *current = hashTable[i];
        while (current) {
            Node *temp = current;
            current = current->next;
            free(temp->singleNumber);
            free(temp);
        }
    }
}

不得不感叹现在AI的强大啊,就几轮对话的功夫就给我写出了一个基本能用的代码,大大提高了我们的工作效率。

相关推荐
学传打活13 小时前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续1)
微信公众平台·1024程序员节·汉字·昆仑正义文化
fangzhanpeng1688 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心11 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552716 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u01030552717 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝18 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u01030552718 天前
Java图像处理实战指南
人工智能·1024程序员节
u01030552719 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u01030552721 天前
Java实用类应用精讲
人工智能·1024程序员节
u01030552722 天前
Java I/O核心操作实战
人工智能·1024程序员节