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 ...
随机推荐
- ios获取左右眼图片景深图
cv::Mat leftMat,rightMat,depthMapMat; UIImageToMat(leftImage, leftMat); UIImageToMat(rightImage, rig ...
- 深入NSQ 之旅[转载]
介绍 NSQ是一个实时的分布式消息平台.它的设计目标是为在多台计算机上运行的松散服务提供一个现代化的基础设施骨架.这篇文章介绍了 基于go语言的NSQ的内部架构,它能够为高吞吐量的网络服务器带来 性能 ...
- mono 3.10.0 正式发布:性能进一步改进
Mono是Xamarin资助的一个项目,是微软的.NET框架的开源实现.它使得使用C#.F#和其他.NET语言进行跨平台开发成为可能.Xamarin在Mono之上构建了跨平台开发工具以及像Xamari ...
- Android安全开发之通用签名风险
Android安全开发之通用签名风险 作者:伊樵.舟海.呆狐@阿里聚安全 1 通用签名风险简介 1.1 Android应用签名机制 阿里聚安全漏洞扫描器有一项检测服务是检测APP的通用签名风险.And ...
- 自己动手写一个简单的MVC框架(第一版)
一.MVC概念回顾 路由(Route).控制器(Controller).行为(Action).模型(Model).视图(View) 用一句简单地话来描述以上关键点: 路由(Route)就相当于一个公司 ...
- ASP.Net MVC3 图片上传详解(form.js,bootstrap)
图片上传的插件很多,但很多时候还是不能切合我们的需求,我这里给大家分享个我用一个form,file实现上传四张图片的小demo.完全是用jquery前后交互,没有用插件. 最终效果图如下: 玩过花田人 ...
- [ASP.NET MVC 小牛之路]03 - Razor语法
本人博客已转移至:http://www.exblr.com/liam Razor是MVC3中才有的新的视图引擎.我们知道,在ASP.NET中,ASPX的视图引擎依靠<%和%>来调用C#指 ...
- Windows Azure Storage (22) Azure Storage如何支持多级目录
<Windows Azure Platform 系列文章目录> 熟悉Azure平台的读者都知道,Azure Blob有三层架构.如下图:(注意blob.core.chinacloudapi ...
- React 生命周期
前言 学习React,生命周期很重要,我们了解完生命周期的各个组件,对写高性能组件会有很大的帮助. Ract生命周期 React 生命周期分为三种状态 1. 初始化 2.更新 3.销毁 初始化 1.g ...
- VS无法设置断点的解决方案
第一种情况的处理 第二种情况的处理