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

C语言中高效近期集合成员测试及12字节消息去重优化方案咨询

Great question! Let's break down your problem: you're handling infinite 12-byte random messages, need to deduplicate only the most recent 1000 entries, and your current linear scan of a circular buffer is CPU-intensive for high-throughput scenarios. Below are several far more efficient approaches tailored for C, balancing CPU and memory performance:

1. Open-Addressing Hash Table with LRU Eviction

This is the gold standard for precise deduplication with fast lookups and controlled memory usage.

How it works:

  • Use an open-addressing hash table (no linked lists, better cache locality than chained hash tables) to store your 12-byte message keys. Lookups are average O(1) since you compute a hash of the 12-byte message, jump directly to the candidate slot, and do at most a few memcmp checks.
  • Pair the hash table with a doubly linked list to track insertion order. When you exceed 1000 entries, evict the oldest entry (tail of the list) from both the list and hash table.

Implementation Notes for C:

  • For the hash function, use a fast, collision-resistant algorithm like MurmurHash3 (optimized for 12-byte inputs) to generate a 64-bit hash value. This minimizes collision chances for random data.
  • Define a compact slot structure to save memory:
    typedef struct {
        uint8_t key[12];
        bool occupied;
        struct ListNode* list_node; // Pointer to linked list entry for eviction
    } HashSlot;
    
    typedef struct ListNode {
        uint8_t key[12];
        struct ListNode* prev;
        struct ListNode* next;
    } ListNode;
    
  • Keep the hash table's load factor around 0.75 (capacity = ~1333 slots for 1000 entries) to balance memory usage and lookup speed.

Pros:

  • Precise deduplication (no false positives)
  • Near-constant time lookups/insertions/evictions
  • Better cache performance than chained hash tables

2. Bloom Filter (For Memory-Conscious Scenarios)

If you can tolerate an extremely low false positive rate (e.g., <0.1%), a Bloom Filter is unbeatable for memory efficiency.

How it works:

  • A Bloom Filter uses a bit array and multiple hash functions to mark the presence of keys. For your 12-byte messages and 1000-entry limit, you only need ~880 bytes of memory — way smaller than your 12KB circular buffer.
  • To handle "recent only" entries, use a sliding window Bloom Filter or periodically rebuild the filter when it reaches capacity. Alternatively, use a counting Bloom Filter (each bit becomes a small counter) to support evictions, though this increases memory usage slightly.

Implementation Snippet:

// Bloom Filter with ~0.1% false positive rate for 1000 entries
typedef struct {
    uint64_t bits[110]; // 7040 bits (~880 bytes)
    size_t entry_count;
} BloomFilter;

// 3 distinct hash functions using MurmurHash3 with different seeds
uint64_t hash_seed1(const uint8_t* key) { /* ... */ }
uint64_t hash_seed2(const uint8_t* key) { /* ... */ }
uint64_t hash_seed3(const uint8_t* key) { /* ... */ }

bool bloom_contains(BloomFilter* bf, const uint8_t* key) {
    uint64_t h1 = hash_seed1(key) % (sizeof(bf->bits)*8);
    uint64_t h2 = hash_seed2(key) % (sizeof(bf->bits)*8);
    uint64_t h3 = hash_seed3(key) % (sizeof(bf->bits)*8);
    return (bf->bits[h1/64] & (1ULL << (h1%64))) &&
           (bf->bits[h2/64] & (1ULL << (h2%64))) &&
           (bf->bits[h3/64] & (1ULL << (h3%64)));
}

Pros:

  • Minimal memory footprint
  • Extremely fast lookups (just a few hash computations and bit checks)

Caveat:

  • False positives are possible. If your use case can't tolerate this, pair the Bloom Filter with a small hash table to verify positive hits (this is called a "filter-and-verify" approach).

3. Direct 96-bit Key Hash Set

Since your messages are exactly 12 bytes (96 bits), you can treat the message itself as a unique hash key (collisions are statistically negligible for 1000 random entries).

How it works:

  • Use an open-addressing hash table where the key is the 12-byte message directly. Compute a 64-bit hash of the 12-byte value to find the initial slot, then use linear probing to resolve collisions.
  • Track insertion order with a circular buffer or linked list to evict old entries when you hit the 1000 limit.

Pros:

  • No need for a separate hash function (though using one still helps with slot distribution)
  • Zero collision risk for practical purposes (the probability of two random 12-byte messages colliding is ~1 in 3e28 for 1000 entries)
  • Simple to implement since the key is the raw message

Comparison to Your Current Approach

Your circular buffer requires an O(n) linear scan (1000 memcmp operations per check) which becomes a CPU bottleneck at high throughput. All the methods above reduce lookup time to average O(1), cutting CPU usage dramatically while keeping memory usage comparable or lower.

Final Recommendations:

  • Precise deduplication, high throughput: Use an open-addressing hash table with LRU eviction.
  • Memory is critical, low false positives acceptable: Use a Bloom Filter (with optional verification layer).
  • Simple implementation, no third-party libs: Use a direct 96-bit key hash set.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:19:46