`

模仿st_table写的StTable类

    博客分类:
  • java
阅读更多
    读ruby hacking guide,其中专门辟了一个章节介绍了st.c中的st_table,这个数据结构也就是类似java中的HashMap,基本原理是利用数组存储,数组的每一个元素是一个单向链表,链表中再存储具体的元素,如下图所示的结构

   ruby中利用这个结构来存储对象变量、类方法、常量、全局变量等信息,在c ruby中,方法、变量都是用一个整型作为键值来存储在st_table中,因此这个数据结构对于以整性为键的map类型来说速度非常不错(我没有测试内存的占用情况)。
源码如下:
java 代码
 
  1. //接口,用于定义hash函数  
  2. //HashFunction.java  
  3. public interface HashFunction<T> {  
  4.    public int hash(T key);  
  5. }  

链表元素类:
java 代码
 
  1. public class StTableEntry<T, V> {  
  2.     protected int hash; //hash值  
  3.   
  4.     protected T key;   //键  
  5.   
  6.     protected V value; //存储值  
  7.   
  8.     protected StTableEntry<T, V> next; //下一节点  
  9.   
  10.     public StTableEntry() {  
  11.   
  12.     }  
  13.   
  14.     public StTableEntry(int hash, T key, V value, StTableEntry<T, V> next) {  
  15.         super();  
  16.         this.hash = hash;  
  17.         this.key = key;  
  18.         this.value = value;  
  19.         this.next = next;  
  20.     }  
  21.   
  22.     public int getHash() {  
  23.         return hash;  
  24.     }  
  25.   
  26.     public void setHash(int hash) {  
  27.         this.hash = hash;  
  28.     }  
  29.   
  30.     public T getKey() {  
  31.         return key;  
  32.     }  
  33.   
  34.     public void setKey(T key) {  
  35.         this.key = key;  
  36.     }  
  37.   
  38.     public StTableEntry<T, V> getNext() {  
  39.         return next;  
  40.     }  
  41.   
  42.     public void setNext(StTableEntry<T, V> next) {  
  43.         this.next = next;  
  44.     }  
  45.   
  46.     public V getValue() {  
  47.         return value;  
  48.     }  
  49.   
  50.     public void setValue(V value) {  
  51.         this.value = value;  
  52.     }  
  53.   
  54. }  

完整的StTable实现,没有实现remove,有兴趣的话自己实现一下:
java 代码
 
  1. public final class StTable<T, V> {  
  2.     private HashFunction<T> hashFunction;  
  3.   
  4.     private int num_bins;  
  5.   
  6.     int num_entries;  
  7.   
  8.     StTableEntry<T, V>[] bins;  
  9.   
  10.     public static int DEFAULT_SIZE = 10;  
  11.   
  12.     private static int DEFAULT_MAX_DENSITY = 5;  
  13.   
  14.     private static int DEFAULT_MIN_SIZE = 8;  
  15.   
  16.     private static long primes[] = { 8 + 316 + 332 + 564 + 3128 + 3,  
  17.             256 + 27512 + 91024 + 92048 + 54096 + 38192 + 27,  
  18.             16384 + 4332768 + 365536 + 45131072 + 29262144 + 3,  
  19.             524288 + 211048576 + 72097152 + 174194304 + 158388608 + 9,  
  20.             16777216 + 4333554432 + 3567108864 + 15134217728 + 29,  
  21.             268435456 + 3536870912 + 111073741824 + 850 };  
  22.   
  23.     public StTable(HashFunction<T> hashFunction) {  
  24.         this.hashFunction = hashFunction;  
  25.         this.num_bins = DEFAULT_SIZE;  
  26.         this.num_entries = 0;  
  27.         this.bins = (StTableEntry<T, V>[]) new StTableEntry[this.num_bins];  
  28.     }  
  29.   
  30.     public StTable(HashFunction<T> hashFunction, int size) {  
  31.         this.hashFunction = hashFunction;  
  32.         if (size == 0)  
  33.             throw new IllegalArgumentException(  
  34.                     "The size could not less than zero:" + size);  
  35.         this.num_bins = size;  
  36.         this.num_entries = 0;  
  37.         this.bins = (StTableEntry<T, V>[]) new StTableEntry[this.num_bins];  
  38.     }  
  39.   
  40.     private long newSize(int size) {  
  41.   
  42.         for (int i = 0, newsize = DEFAULT_MIN_SIZE; i < primes.length; i++, newsize <<= 1) {  
  43.             if (newsize > size)  
  44.                 return primes[i];  
  45.         }  
  46.         /* Ran out of polynomials */  
  47.         return -1/* should raise exception */  
  48.     }  
  49.   
  50.     public V get(T key) {  
  51.         int hash_val = doHash(key);  
  52.         StTableEntry<T, V> entry = findEntry(hash_val, key);  
  53.         if (entry == null)  
  54.             return null;  
  55.         else  
  56.             return entry.getValue();  
  57.     }  
  58.   
  59.     public V put(T key, V value) {  
  60.         int hash_val = doHash(key);  
  61.         StTableEntry<T, V> entry = findEntry(hash_val, key);  
  62.         if (entry == null) {  
  63.             // 未有键值,直接添加  
  64.             addDirect(key, value);  
  65.             return value;  
  66.         } else {  
  67.             V v = entry.value;  
  68.             entry.value = value;  
  69.             return v;  
  70.         }  
  71.     }  
  72.   
  73.     // hash函数,调用hashFunction的hash方法  
  74.     private int doHash(T key) {  
  75.         if (hashFunction.hash(key) < 0)  
  76.             throw new IllegalArgumentException(  
  77.                     "hash value could not less than zero:"  
  78.                             + hashFunction.hash(key));  
  79.         return hashFunction.hash(key);  
  80.     }  
  81.   
  82.     // 过于拥挤,重新分布  
  83.     public void reHash() {  
  84.         int new_size = (int) newSize(this.num_bins);  
  85.         StTableEntry<T, V>[] new_bins = (StTableEntry<T, V>[]) new StTableEntry[new_size];  
  86.         for (int i = 0; i < this.num_bins; i++) {  
  87.             StTableEntry<T, V> entry = this.bins[i];  
  88.             while (entry != null) {  
  89.                 StTableEntry<T, V> next = entry.next;  
  90.                 int hash_val = entry.hash % new_size;  
  91.                 entry.next = new_bins[hash_val];  
  92.                 new_bins[hash_val] = entry;  
  93.                 entry = next;  
  94.             }  
  95.         }  
  96.         this.bins = null//gc  
  97.         this.num_bins = new_size;  
  98.         this.bins = new_bins;  
  99.   
  100.     }  
  101.   
  102.     private void addDirect(T key, V value) {  
  103.         int hash_val = doHash(key);  
  104.         int bin_pos = hash_val % this.num_bins;  
  105.         if ((this.num_entries / this.num_bins) > DEFAULT_MAX_DENSITY) {  
  106.             reHash();  
  107.             bin_pos = hash_val % this.num_bins;  
  108.         }  
  109.         StTableEntry<T, V> entry = new StTableEntry<T, V>();  
  110.         entry.setHash(hash_val);  
  111.         entry.setKey(key);  
  112.         entry.setValue(value);  
  113.         entry.setNext(this.bins[bin_pos]);  
  114.         this.bins[bin_pos] = entry;  
  115.         this.num_entries++;  
  116.     }  
  117.   
  118.     private StTableEntry<T, V> findEntry(int hash_val, T key) {  
  119.         int bin_pos = hash_val % this.num_bins;  
  120.         StTableEntry<T, V> entry = this.bins[bin_pos];  
  121.         if (entryNotEqual(entry, key, hash_val)) {  
  122.             entry = entry.next;  
  123.             while (entryNotEqual(entry, key, hash_val)) {  
  124.                 entry = entry.next;  
  125.             }  
  126.         }  
  127.         return entry;  
  128.     }  
  129.   
  130.     // 判断元素是否相同  
  131.     private boolean entryNotEqual(StTableEntry<T, V> entry, T key, int hash_val) {  
  132.         return entry != null  
  133.                 && (entry.getHash() != hash_val || (!key.equals(entry.getKey())));  
  134.     }  
  135.   
  136. }  

   单元测试类就不列了,给一个与HashMap的简单性能对比,以整型为键,显然StTable快多了,对于字符串型,关键是HashFunction的定义,我直接调用String的hashCode方法,不知道有没有其他更好的方法让元素分布的更均匀些:
java 代码
 
  1. import java.util.HashMap;  
  2. import java.util.Map;  
  3.   
  4. public class Benchmark {  
  5.     public static void main(String args[]) {  
  6.         long map_cost = testStringMap();  
  7.         long table_cost = testStringTable();  
  8.         if (map_cost <= table_cost)  
  9.             System.out.println("map is faster than table ");  
  10.         else  
  11.             System.out.println("table is faster than map ");  
  12.   
  13.         map_cost = testIntegerMap();  
  14.         table_cost = testIntegerTable();  
  15.         if (map_cost <= table_cost)  
  16.             System.out.println("map is faster than table ");  
  17.         else  
  18.             System.out.println("table is faster than map ");  
  19.     }  
  20.   
  21.     public static long testIntegerMap() {  
  22.         Map<Integer, Integer> map = new HashMap<Integer, Integer>();  
  23.         long start = System.nanoTime();  
  24.         for (int i = 0; i < 10000; i++)  
  25.             map.put(i, i);  
  26.         long result = 0;  
  27.         for (int i = 0; i < 10000; i++)  
  28.             result += map.get(i);  
  29.         long end = System.nanoTime();  
  30.         System.out.println("result:" + result);  
  31.         System.out.println("map:" + (end - start));  
  32.         return (end - start);  
  33.     }  
  34.   
  35.     public static long testIntegerTable() {  
  36.         HashFunction<Integer> intHash = new HashFunction<Integer>() {  
  37.             public int hash(Integer key) {  
  38.                 return key;  
  39.             }  
  40.         };  
  41.         StTable<Integer, Integer> table = new StTable<Integer, Integer>(intHash);  
  42.         long start = System.nanoTime();  
  43.         for (int i = 0; i < 10000; i++)  
  44.             table.put(i, i);  
  45.         long result = 0;  
  46.         for (int i = 0; i < 10000; i++)  
  47.             result += table.get(i);  
  48.         long end = System.nanoTime();  
  49.         System.out.println("result:" + result);  
  50.         System.out.println("table:" + (end - start));  
  51.         return (end - start);  
  52.     }  
  53.   
  54.     public static long testStringMap() {  
  55.         Map<String, String> map = new HashMap<String, String>();  
  56.         long start = System.nanoTime();  
  57.         for (int i = 0; i < 10000; i++)  
  58.             map.put(String.valueOf(i), String.valueOf(i));  
  59.         long result = 0;  
  60.         for (int i = 0; i < 10000; i++)  
  61.             result += Integer.parseInt(map.get(String.valueOf(i)));  
  62.         long end = System.nanoTime();  
  63.         System.out.println("result:" + result);  
  64.         System.out.println("map:" + (end - start));  
  65.         return (end - start);  
  66.     }  
  67.   
  68.     public static long testStringTable() {  
  69.         HashFunction<String> intHash = new HashFunction<String>() {  
  70.             int i = 0;  
  71.             public int hash(String key) {  
  72.                 int hashCode = key.hashCode();  
  73.                 return hashCode < 0 ? -hashCode : hashCode;  
  74.             }  
  75.         };  
  76.         StTable<String, String> table = new StTable<String, String>(intHash);  
  77.         long start = System.nanoTime();  
  78.         for (int i = 0; i < 10000; i++)  
  79.             table.put(String.valueOf(i), String.valueOf(i));  
  80.         long result = 0;  
  81.         for (int i = 0; i < 10000; i++)  
  82.             result += Integer.parseInt(table.get(String.valueOf(i)));  
  83.         long end = System.nanoTime();  
  84.         System.out.println("result:" + result);  
  85.         System.out.println("table:" + (end - start));  
  86.         return (end - start);  
  87.     }  
  88.   
  89. }  

结果为:
result:49995000
map:55501468
result:49995000
table:60999652
map is faster than table

 
result:49995000
map:44634444
result:49995000
table:26209477
table is faster than map



分享到:
评论

相关推荐

    gcc_except_table的资料

    `gcc_except_table`是GCC(GNU Compiler Collection)编译器在处理C++异常处理时使用的一个内部机制。这个表格在编译过程中自动生成,用于在程序执行期间有效地管理异常捕获和传播。在这个主题中,我们将深入探讨`...

    ALSM_EXCEL_TO_INTERNAL_TABLE函数的修改

    【ALSM_EXCEL_TO_INTERNAL_TABLE函数的修改】 在SAP ABAP编程中,ALSM_EXCEL_TO_INTERNAL_TABLE是一个标准函数,用于将Excel文件中的数据读取到内部表中。这个函数通常在处理从用户界面上传的Excel数据时非常有用。...

    DBMS_STATS.GATHER_TABLE_STATS详解.pdf

    ### DBMS_STATS.GATHER_TABLE_STATS详解 #### 一、概述 `DBMS_STATS.GATHER_TABLE_STATS` 是 Oracle 数据库中的一个重要过程,主要用于收集表、列和索引的统计信息,这些统计信息对于优化器选择合适的执行计划至关...

    trans_table.rar_Table_trans_table

    标题中的"trans_table.rar_Table_trans_table"提示我们关注的核心是“trans_table”,它似乎是一个与数据转换相关的表格或矩阵,可能用于生物信息学、数据库管理或其他需要数据转换的领域。"rar"是一个压缩文件格式...

    SAP-ABAP-OO-实现-CL-SALV-TABLE

    面向对象的 ALV 显示主要依赖于 `CL_SALV_TABLE` 这个类。该类提供了一系列的方法来帮助开发者更加灵活地控制 ALV 的显示效果。相比传统的面向过程的方式,面向对象的方法提供了更多的灵活性和可扩展性。 #### 2. ...

    u_hash_table.rar_Table For Two

    例如,`u_hash_table_init()`函数可能是用来初始化一个新的哈希表,`u_hash_table_insert()`用于插入键值对,`u_hash_table_find()`用于根据键查找对应的值,而`u_hash_table_remove()`则用于删除指定键的键值对。...

    get_size_database_and_table.rar_Table_get_table_size sql

    标题“get_size_database_and_table.rar_Table_get_table_size_sql”和描述“如何获取SQL数据库大小”都指向了这个核心主题。本文将深入探讨如何使用SQL语句来获取数据库和表的大小信息。 1. 数据库大小获取: ...

    test_table_Table_incomplete_

    标题 "test_table_Table_incomplete_" 和描述 "test_table(incompleted)" 暗示我们正在处理一个与数据库或数据表相关的项目,其中可能包含一个名为 "test_table" 的表格,但这个表格似乎不完整或者存在一些问题。...

    st表.zip_St table_Table

    在IT领域,特别是数据结构和算法的学习中,ST表(Sqrt-Decomposition Table)是一种高效的数据结构,常用于处理动态区间最值查询问题。它主要适用于那些对一个数组进行频繁的更新和查询操作,而更新操作是局部的,...

    关联规则代码实现资料order_table.csv

    商品交叉销售分析所需数据,对同一个订单编号不同的产品进行组合分析相关性.

    mysql tmp_table_size和max_heap_table_size大小配置

    `tmp_table_size` 和 `max_heap_table_size` 这两个系统变量就与这种内存中的临时表息息相关,它们对数据库性能有着显著的影响。 `tmp_table_size` 是一个重要的配置参数,它决定了在每个线程中创建的内存临时表的...

    newhh_table1_src.rar_c# console_newhh_table1_src

    【标题】"newhh_table1_src.rar_c# console_newhh_table1_src" 指的是一款基于C#语言开发的控制台应用程序,主要用于哈希计算。哈希(Hash)算法是一种将任意长度的数据映射为固定长度输出的算法,常用于数据校验、...

    最好的CRC程序_Table_available9b9_crc16table_Vc_

    创建CRC16所需要的Table、创建CRC32所需要的Table、执行对数据段的CRC16循环冗余校验、执行对数据段的CRC32循环冗余校验,处理CRC循环校验所需要的方法,可选择临时计算,或者一次计算出数值查表以增加速度。

    CC_Table.rar_Table

    《CC_Table:深入理解Visual C++中的Table原代码实现》 在编程领域,尤其是在Windows应用程序开发中,Table控件是一种常见的用户界面元素,用于展示数据并允许用户进行交互。本篇将围绕“CC_Table.rar_Table”这个...

    loca_table.rar_Table

    这里的改动可能是为了允许其他类或外部代码能够创建和操作"loca_table"这个类的实例。 因此,我们可以深入探讨以下几个知识点: 1. **数据库表格**:在数据库管理中,表格是存储和组织数据的主要方式,由行和列...

    parse_reduce_table.rar_Table

    在编程和计算机科学领域,尤其是编译器设计中,`parse_reduce_table` 是一个关键的概念,它涉及到解析和语法分析的过程。这个压缩包文件 `parse_reduce_table.rar_Table` 显然是与创建或使用解析减少表(Parse ...

    initrd_table_override.rar_Table

    具体到`initrd_table_override.txt`的内容,可能包含了一系列的PCI设备ID、设备类码、中断线路等信息,这些信息会被内核的PCI子系统读取,并用以覆盖默认的PCI中断路由设置。配置文件的格式通常是文本形式,每行代表...

    lock_table.rar_Table_lock table_oracle lock table

    标题“lock_table.rar_Table_lock table_oracle lock table”表明这个压缩包包含了与Oracle数据库中的表锁定相关的资料,可能是用于诊断和解决表被特定用户锁定的问题。下面将详细解释这些知识点: 1. **Table ...

    glsl_symbol_table.rar_Table_symbol table

    Wraps the existing \c _mesa_symbol_table data structure to enforce some type safe and some symbol table invariants.

Global site tag (gtag.js) - Google Analytics