Python字典实现分析
背景介绍
最近使用Python开发项目为主,当使用到字典时感觉非常方便实用。那么好奇心就驱使我要搞清楚字典是怎么实现的。为了真正的搞清楚字典的实现就不得不使用C语言来实现一遍,为此我查了一些资料现在总结一下。
字典简述
字典也被称为关联数组,还称为哈希数组等。实现的原理一般是有一个键值对,通过键可以索引到值。很多工具都使用这种方式保存数据,例如redis/memcached/mongo等。所以键是唯一的,要是实现字典的快速查询肯定不能使用字符串遍历对比的方式实现。那样实现的字典会非常非常的慢。我们都知道在数组中使用下标索引可以快速的得到对应值,所以我们需要做的就是怎样把键计算出一个唯一值并且这个值要唯一还要在我们的数组索引值范围呢。举例子说,当一个键为hello
的时候,我的数组最大索引是1024
这个范围呢!我们的键值对可以有1024
对。那么如果按照ascii
值对hello
进行一个简单的加法计算我们会得到什么呢?下面运行一段c
程序看看。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int sum_ascii(char * key){
unsigned long sum = 0;
unsigned long i;
for(i = 0; i < strlen(key);i++){
sum+= key[i];
}
return sum;
}
int main(int argc, char * argv[]){
int key_id = sum_ascii("hello");
printf("The key id %d\n", key_id);
return 0;
}
看到这个532
你会觉得正好,至少没有超过1024
这个索引范围,可以用了。不要着急,我们继续将hello
改成hellohashtable
看看会得到多少值。
糟糕了!超出索引范围了,你可能会想到两种解决方案。
*1,增加数组大小。
*2,写一篇说明书,说明你的这个键不能超过多少个字符。
这两个方案显然是无法让使用者开心的,所以我们需要解决掉。我们可以使用下面的方式获取绝对不会超过索引范围的值,猜猜什么办法。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE_ARRAY 1024
int sum_ascii(char * key){
unsigned long sum = 0;
unsigned long i;
for(i = 0; i < strlen(key);i++){
sum+= key[i];
}
return sum;
}
int residue(int size){
return size % SIZE_ARRAY;
}
int main(int argc, char * argv[]){
int key_id = sum_ascii("hellohashtable");
key_id = residue(key_id);
printf("The key id %d\n", key_id);
return 0;
}
现在好了,我们不会超出索引范围了。那么问题又来了,我们的计算值很明显非常容易出现冲突,下面举一个例子吧。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE_ARRAY 1024
int sum_ascii(char * key){
unsigned long sum = 0;
unsigned long i;
for(i = 0; i < strlen(key);i++){
sum+= key[i];
}
return sum;
}
int residue(int size){
return size % SIZE_ARRAY;
}
int main(int argc, char * argv[]){
char * key1 = "hellolandpack";
char * key2 = "hellohellohellohelloak6";
int key1_id = sum_ascii(key1);
int key2_id = sum_ascii(key2);
key1_id = residue(key1_id);
key2_id = residue(key2_id);
printf("The key[%s] id %d\n", key1,key1_id);
printf("The key[%s] id %d\n", key2,key2_id);
return 0;
}
可以看到,我们的key
显然是不同的,但是却生成了同样的一个索引值。这就会导致数据冲突了。下面换一种方式计算键值。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE_ARRAY 1024
int sum_ascii(char * key){
unsigned long sum = 0;
unsigned long i;
for(i = 0; i < strlen(key);i++){
//sum+= key[i];
sum = sum << 8;
sum += key[i];
}
return sum;
}
int residue(int size){
return size % SIZE_ARRAY;
}
int main(int argc, char * argv[]){
char * key1 = "hellolandpack";
char * key2 = "hellohellohellohelloak6";
int key1_id = sum_ascii(key1);
int key2_id = sum_ascii(key2);
key1_id = residue(key1_id);
key2_id = residue(key2_id);
printf("The key[%s] id %d\n", key1,key1_id);
printf("The key[%s] id %d\n", key2,key2_id);
return 0;
}
难道这样就不会生成重复的键值吗?不可能哈,来看看下面这个测试。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE_ARRAY 1024
int sum_ascii(char * key){
unsigned long sum = 0;
unsigned long i;
for(i = 0; i < strlen(key);i++){
//sum+= key[i];
sum = sum << 8;
sum += key[i];
}
return sum;
}
int residue(int size){
return size % SIZE_ARRAY;
}
int main(int argc, char * argv[]){
//char * key1 = "hellolandpack";
//char * key2 = "hellohellohellohelloak6";
char * key1 = "ddddd";
char * key2 = "dddd";
int key1_id = sum_ascii(key1);
int key2_id = sum_ascii(key2);
key1_id = residue(key1_id);
key2_id = residue(key2_id);
printf("The key[%s] id %d\n", key1,key1_id);
printf("The key[%s] id %d\n", key2,key2_id);
return 0;
}
好了,问题又来了!我们又遇到问题了。这个和之前的算法一样无法解决唯一键值问题。那么干嘛还要引入这个呢?来再看看原来的算法。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE_ARRAY 1024
int sum_ascii(char * key){
unsigned long sum = 0;
unsigned long i;
for(i = 0; i < strlen(key);i++){
//sum+= key[i];
//sum = sum << 8;
sum += key[i];
}
return sum;
}
int residue(int size){
return size % SIZE_ARRAY;
}
int main(int argc, char * argv[]){
//char * key1 = "hellolandpack";
//char * key2 = "hellohellohellohelloak6";
char * key1 = "hello";
char * key2 = "olleh";
int key1_id = sum_ascii(key1);
int key2_id = sum_ascii(key2);
key1_id = residue(key1_id);
key2_id = residue(key2_id);
printf("The key[%s] id %d\n", key1,key1_id);
printf("The key[%s] id %d\n", key2,key2_id);
return 0;
}
好了!可以看到。对于同一组字符的不同顺序它居然认为是同一个键,显然是错误的。而增加了向右移位处理后我们可以得到如下的结果。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE_ARRAY 1024
int sum_ascii(char * key){
unsigned long sum = 0;
unsigned long i;
for(i = 0; i < strlen(key);i++){
//sum+= key[i];
sum = sum << 8;
sum += key[i];
}
return sum;
}
int residue(int size){
return size % SIZE_ARRAY;
}
int main(int argc, char * argv[]){
//char * key1 = "hellolandpack";
//char * key2 = "hellohellohellohelloak6";
char * key1 = "hello";
char * key2 = "olleh";
int key1_id = sum_ascii(key1);
int key2_id = sum_ascii(key2);
key1_id = residue(key1_id);
key2_id = residue(key2_id);
printf("The key[%s] id %d\n", key1,key1_id);
printf("The key[%s] id %d\n", key2,key2_id);
return 0;
}
总结
现在大概了解了一下设计字典最大的难点就是怎样去容纳各种不同的键值,并且产生一个唯一的索引。下一章我将会具体实现一个字典,并且在最后我会将其编译为一个python
包。
如果你在使用字典或者键值数据库有什么有趣的发现就快快分享分享吧~~
Python字典实现分析的更多相关文章
- Python文章相关性分析---金庸武侠小说分析
百度到<金庸小说全集 14部>全(TXT)作者:金庸 下载下来,然后读取内容with open('names.txt') as f: data = [line.strip() for li ...
- 用python探索和分析网络数据
Edited by Markdown Refered from: John Ladd, Jessica Otis, Christopher N. Warren, and Scott Weingart, ...
- python爬虫之分析Ajax请求抓取抓取今日头条街拍美图(七)
python爬虫之分析Ajax请求抓取抓取今日头条街拍美图 一.分析网站 1.进入浏览器,搜索今日头条,在搜索栏搜索街拍,然后选择图集这一栏. 2.按F12打开开发者工具,刷新网页,这时网页回弹到综合 ...
- Python字典 你必须知道的用法系列
本文Python版本为3.7.X,阅读本文之前需了解python字典的基本用法. 介绍 字典(dict)是Python中内置的一个数据结构,由多个键值对组成,键(key)和值(value)用冒号分隔, ...
- Python文章相关性分析---金庸武侠小说分析-2018.1.16
最近常听同事提及相关性分析,正巧看到这个google的开源库,并把相关操作与调试结果记录下来. 输出结果: 比较有意思的巧合是黄蓉使出打狗棒,郭靖就用了降龙十八掌,再后测试了名词的解析. 小说集可以百 ...
- python字典推导式 - python基础入门(17)
在昨天的文章中,我们介绍了关于python列表推导式 的使用,字典推导式使用方法其实也类似,也是通过循环和条件判断表达式配合使用,不同的是字典推导式返回值是一个字典,所以整个表达式需要写在{}内部. ...
- 自己动手实现 HashMap(Python字典),彻底系统的学习哈希表(上篇)——不看血亏!!!
HashMap(Python字典)设计原理与实现(上篇)--哈希表的原理 在此前的四篇长文当中我们已经实现了我们自己的ArrayList和LinkedList,并且分析了ArrayList和Linke ...
- Python字典和集合
Python字典操作与遍历: 1.http://www.cnblogs.com/rubylouvre/archive/2011/06/19/2084739.html 2.http://5iqiong. ...
- python 字典排序 关于sort()、reversed()、sorted()
一.Python的排序 1.reversed() 这个很好理解,reversed英文意思就是:adj. 颠倒的:相反的:(判决等)撤销的 print list(reversed(['dream','a ...
随机推荐
- 安卓 自定义AlertDialog对话框(加载提示框)
AlertDialog有以下六种使用方法: 一.简单的AlertDialog(只显示一段简单的信息) 二.带按钮的AlertDialog(显示提示信息,让用户操作) 三.类似ListView的Aler ...
- 多位数每一位个系数:个位num%10;十位num/10%10.......
请输出满足这样条件的五位数. 个位=万位 十位=千位 个位+十位+千位+万位=百位 思路: 1.定义一个要操作的五位数变量num 2.求出每一位个系数 个:num%10 十:num/10%10 百:n ...
- 多线程中使用CheckForIllegalCrossThreadCalls = false访问窗口-转
在多线程程序中,新创建的线程不能访问UI线程创建的窗口控件,如果需要访问窗口中的控件,可以在窗口构造函数中将CheckForIllegalCrossThreadCalls设置为 false publi ...
- 求两点之间最短路径-Dijkstra算法
Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.D ...
- 浅析Yii2的view层设计
Yii2.0的view层提供了若干重要的功能:assets资源管理,widgets小组件,layouts布局... 下面将通过对Yii2.0代码直接进行分析,看一下上述功能都是如何实现的,当然细枝末节 ...
- Data Flow的Error Output
一,在Data Flow Task中,对于Error Row的处理通过Error Output Tab配置的. 1,操作失败的类型:Error(Conversion) 和 Truncation. 2, ...
- ArcGIS API for JavaScript(2)-ArcGIS Server发布要素图层服务
1.前言 上一篇该系列的文章我们主要讲了一下基础Web地图搭建,这篇我们主要讲一下ArcGIS Server发布服务,并且如何调用服务.将自己的数据加载到Web地图当中来,实现Web端浏览数据. 2. ...
- hudson部署过程
hudson部署过程: java安装 http://developer.51cto.com/art/201504/470683.htm tomcat安装 http://blog.csdn.net/hu ...
- 【转】oracle中in和exists的区别
原文地址:http://blog.itpub.net/7478833/viewspace-441043/ 感谢作者 in 和 exists区别 in 是把外表和内表作hash join,而ex ...
- IOS学习之NSNotificationCenter消息机制
NSNotificationCenter是 Cococa消息中心,统一管理单进程内不同线程的消息通迅. 添加观察者接收通知: //添加通知中心观察者 [[NSNotificationCenter de ...