larbin之哈希之谈

由于工作原因,打算对larbin的源码进行分析一番

用的事2.6.3版本的larbin源码,由于这是业余,会断断续续的分析上传,已做记录笔记

今天我们分析一下larbin的哈希表

这个哈希表结构比较简单,因为它的主要用处是排重,因此只给出了用于排重的简单函数,

我们来看一下头文件怎么定义的:

// Larbin
// Sebastien Ailleret
// 23-11-99 -> 14-01-00

/* class hashTable
 * This class is in charge of making sure we don‘t crawl twice the same url
 */

#ifndef HASHTABLE_H
#define HASHTABLE_H

#include "types.h"
#include "utils/url.h"

class hashTable {
 private:
  ssize_t size;
  char *table;

 public:
  /* constructor */
  hashTable (bool create);

  /* destructor */
  ~hashTable ();

  /* save the hashTable in a file */
  void save();

  /* test if this url is allready in the hashtable
   * return true if it has been added
   * return false if it has allready been seen
   */
  bool test (url *U);

  /* set a url as present in the hashtable
   */
  void set (url *U);

  /* add a new url in the hashtable
   * return true if it has been added
   * return false if it has allready been seen
   */
  bool testSet (url *U);
};

#endif // HASHTABLE_H

由头文件我们可以看出,这个哈希表仅仅有四个成员函数(除了构造和析构)

save 函数是用于保存哈希表内部的数据,用于防止程序异常退出而造成数据丢失,因此把哈希内数据保存到一个文件中

test  函数用于测试参数指定的URL是否在哈希表内存在,只要是排重

set   函数就是判断出需要设置哈希表内值得时候设置该位置的URL对应的值,表示该URL从此开始存在于哈希表中

testset 是一个辅助函数,先判断,然后设置该位置的值,并且返回设置前的判断结果

下面我们就仔细来看一看各个函数的实现,比较简单,我就在程序中做了简单注释,就不再多余的文字解释了

构造函数:

hashTable::hashTable (bool create) {  //构造函数,申请哈希需求的空间并初始化
  ssize_t total = hashSize/8;   //因为是位集合判断,所以每个字节8位,对于哈希的总成都除以8
  table = new char[total];      //申请哈希空间,其实这个地方主要是以数组巧妙勾勒哈希功能
  if (create) {                 //是一个标志,也就是说哈希内部的数据是从文件内读取还是初始化位0
    for (ssize_t i=0; i<hashSize/8; i++) {
      table[i] = 0;
    }
  } else {
    int fds = open("hashtable.bak", O_RDONLY);   //从bak备份文件读取数据
    if (fds < 0) {
      cerr << "Cannot find hashtable.bak, restart from scratch\n";
      for (ssize_t i=0; i<hashSize/8; i++) {     //如果打开备份文件失败,就重新赋值位0,当做第一次看待
        table[i] = 0;
      }
    } else {
      ssize_t sr = 0;
      while (sr < total) {
        ssize_t tmp = read(fds, table+sr, total-sr); //然后循环读取文件,直到成功读取所有数据
        if (tmp <= 0) {
          cerr << "Cannot read hashtable.bak : "
               << strerror(errno) << endl;
          exit(1);
        } else {
          sr += tmp;        //增加每次读取的数据
        }
      }
      close(fds);          //关闭文件描述符
    }
  }
}

析构函数:

hashTable::~hashTable () {    //析构函数,释放哈希申请的空间
  delete [] table;
}

测试函数test:

bool hashTable::test (url *U) {    //判断该url对应的是否存在哈希中,如果存在返回true,否则false
  unsigned int code = U->hashCode();  //根据hashCode函数求散列值
  unsigned int pos = code / 8;
  unsigned int bits = 1 << (code % 8);
  return table[pos] & bits;
}

设置函数:

void hashTable::set (url *U) {   //设置url对应哈希值
  unsigned int code = U->hashCode();
  unsigned int pos = code / 8;
  unsigned int bits = 1 << (code % 8);
  table[pos] |= bits;
}

测试设置函数:

bool hashTable::testSet (url *U) { //返回测试结果,并且设置url对应的值
  unsigned int code = U->hashCode();
  unsigned int pos = code / 8;
  unsigned int bits = 1 << (code % 8);
  int res = table[pos] & bits;
  table[pos] |= bits;
  return !res;
}

保存文件函数:

void hashTable::save() {     //把哈希内部数据存到文件,该过程是循序渐进的,防止时间间隔过程造成数据大量失真
  rename("hashtable.bak", "hashtable.old");   //先把先前备份文件保存,直到最后本次成功备份后删除
  int fds = creat("hashtable.bak", 00600);
  if (fds >= 0) {
    ecrireBuff(fds, table, hashSize/8);       //辅助函数,把哈希数据存到备份文件
    close(fds);
  }
  unlink("hashtable.old");
}

该哈希的处理部分就这么多,下面重点来看看我们两个知识点

1,散列函数 hashCode:

uint url::hashCode () {
  unsigned int h=port;
  unsigned int i=0;
  while (host[i] != 0) {
    h = 31*h + host[i];
    i++;
  }
  i=0;
  while (file[i] != 0) {
    h = 31*h + file[i];
    i++;
  }
  return h % hashSize;
}

说起来散列函数,要求很有艺术的,而且散列函数也不可能有百分百的通用性。

一般都要自己根据哈希设置自己的散列函数。最起码要设置某些数值,用同一个散列方法和框架

该散列函数比较简单,就是把host和file(URL类中的两个字段,表示主机和文件路径)依次乘以31

然后对哈希最大值求余数,最大值这样定义的:

#define hashSize 64000000

另外对于host和file的先后哈希顺序也是设计的,先host而后file是为了让同一host对应的file的差异更大,减缓相似冲突

2,下面我们就来谈谈URL这个类,上面那个哈希散列函数就是这个类中的一个成员函数,之所以单独摘出去说,是因为散列函数也是重大的一块

我们先来看一下URL类的定义:

class url {
 private:
  char *host;
  char *file;
  uint16_t port; // the order of variables is important for physical size
  int8_t depth;
  /* parse the url */
  void parse (char *s);
  /** parse a file with base */
  void parseWithBase (char *u, url *base);
  /* normalize file name */
  bool normalize (char *file);
  /* Does this url starts with a protocol name */
  bool isProtocol (char *s);
  /* constructor used by giveBase */
  url (char *host, uint port, char *file);

 public:
  /* Constructor : Parses an url (u is deleted) */
  url (char *u, int8_t depth, url *base);

  /* constructor used by input */
  url (char *line, int8_t depth);

  /* Constructor : read the url from a file (cf serialize) */
  url (char *line);

  /* Destructor */
  ~url ();

  /* inet addr (once calculated) */
  struct in_addr addr;

  /* Is it a valid url ? */
  bool isValid ();

  /* print an URL */
  void print ();

  /* return the host */
  inline char *getHost () { return host; }

  /* return the port */
  inline uint getPort () { return port; }

  /* return the file */
  inline char *getFile () { return file; }

  /** Depth in the Site */
  inline int8_t getDepth () { return depth; }

  /* Set depth to max if we are at an entry point in the site
   * try to find the ip addr
   * answer false if forbidden by robots.txt, true otherwise */
  bool initOK (url *from);

  /** return the base of the url
   * give means that you have to delete the string yourself
   */
  url *giveBase ();

  /** return a char * representation of the url
   * give means that you have to delete the string yourself
   */
  char *giveUrl ();

  /** write the url in a buffer
   * buf must be at least of size maxUrlSize
   * returns the size of what has been written (not including ‘\0‘)
   */
  int writeUrl (char *buf);

  /* serialize the url for the Persistent Fifo */
  char *serialize ();

  /* very thread unsafe serialisation in a static buffer */
  char *getUrl();

  /* return a hashcode for the host of this url */
  uint hostHashCode ();

  /* return a hashcode for this url */
  uint hashCode ();

#ifdef URL_TAGS
  /* tag associated to this url */
  uint tag;
#endif // URL_TAGS

#ifdef COOKIES
  /* cookies associated with this page */
  char *cookie;
  void addCookie(char *header);
#else // COOKIES
  inline void addCookie(char *header) {}
#endif // COOKIES
};

稍后待续。。。

larbin之哈希之谈

时间: 2024-08-03 19:21:08

larbin之哈希之谈的相关文章

如何度过有用的每一天

有用的一天,你的敌人是钝感.走神和拖延症. 有用的一天,不包括慵懒的早晨.闲逛的午后和一个人无所事事的黄昏. 有用的一天,你不是生活在生活里,而是狂奔在日程表上填得满当当的逼仄格子中. 07:00 新的一天尽在掌握 有用的一天必须从早起开始. <哈佛商业评论>的一项调查报告是这么说的:“早晨精力最充沛的人更能明确自己的长期目标,更有把握实现自己的目标.” 你把这句话奉为格言.你醒来,叼着牙刷打开电视,频道锁定在<凤凰早班车>——哪怕头脑还不够清醒,你也要从睁眼的第一时间开始,就了解

浅谈算法和数据结构: 十一 哈希表

在前面的系列文章中,依次介绍了基于无序列表的顺序查找,基于有序数组的二分查找,平衡查找树,以及红黑树,下图是他们在平均以及最差情况下的时间复杂度: 可以看到在时间复杂度上,红黑树在平均情况下插入,查找以及删除上都达到了lgN的时间复杂度. 那么有没有查找效率更高的数据结构呢,答案就是本文接下来要介绍了散列表,也叫哈希表(Hash Table) 什么是哈希表 哈希表就是一种以 键-值(key-indexed) 存储数据的结构,我们只要输入待查找的值即key,即可查找到其对应的值. 哈希的思路很简单

关于哈希的浅谈

我们都知道python的字典是由key,value组成的呢.你应该也听过,字典找某一个值的速度很快,那么为什么呢? 就是因为字典里面运用了“哈希”这种技术.那么到底什么是哈希呢? {这里做一个限定, 我们只讨论查找这单一功能的实现中哈希的运用,并不像扯到加密和保证文件完整性的机制,恩恩就这样} 这里为了解释什么事哈希,我要做一个非常不严禁的比喻 我们都用过360吧,在访问”某些“网页的时候,那个是不是会报出提醒xxxx.那我们可以猜到,他内部是一定有一个表格上面吧所有不合格的网址都记录在上面了.

浅谈数据结构:哈希表

一.  基本概念 哈希表(hash table )是一种根据关键字直接访问内存存储位置的数据结构,通过哈希表,数据元素的存放位置和数据元素的关键字之间建立起某种对应关系,建立这种对应关系的函数称为哈希函数 二.哈希表的构造方法 假设要存储的数据元素个数是n,设置一个长度为m(m > n)的连续存储单元,分别以每个数据元素的关键字Ki(0<=i<=n-1)为自变量,通过哈希函数hash(Ki),把Ki映射为内存单元的某个地址hash(Ki),并将数据元素存储在内存单元中 从数学的角度看,哈

图书管理(Loj0034)+浅谈哈希表

图书管理 题目描述 图书管理是一件十分繁杂的工作,在一个图书馆中每天都会有许多新书加入.为了更方便的管理图书(以便于帮助想要借书的客人快速查找他们是否有他们所需要的书),我们需要设计一个图书查找系统. 该系统需要支持 2 种操作: add(s) 表示新加入一本书名为 s 的图书. find(s) 表示查询是否存在一本书名为 s 的图书. 输入格式 第一行包括一个正整数 n,表示操作数. 以下 n 行,每行给出 2 种操作中的某一个指令条,指令格式为: add s find s 在书名 s 与指令

单页应用SEO浅谈

单页应用SEO浅谈 前言 单页应用(Single Page Application)越来越受web开发者欢迎,单页应用的体验可以模拟原生应用,一次开发,多端兼容.单页应用并不是一个全新发明的技术,而是随着互联网的发展,满足用户体验的一种综合技术. SEO 一直以来,搜索引擎优化(SEO)是开发者容易忽略的部分.SEO是针对搜索(Google.百度.雅虎搜索等)在技术细节上的优化,例如语义.搜索关键词与内容相关性.收录量.搜索排名等.SEO也是同行.市场竞争常用的的营销手段.Google.百度的搜

架构师之路--从业务角度谈缓存的选型

想起来几年前挺火的前岛国国民女神学霸-小岛方晴子.当时替她说话的人都很惨,导师被逼自杀.她收到的压力侮辱不是常人可以想象的.但是她却坚强的活着,去年还出了书.我去日本的时候,下了新干线,前面有一群女学生,她们看到我了,立刻聚集成一团,一边看我一边说悄悄话.我才发现日本人穿的衣服基本就是黑,白,灰.他们也不穿羽绒服,女孩子大冬天都是光着腿.而我穿着黄绿色的羽绒服,确实像个怪胎.为什么来之前没人告诉我[大哭][大哭].8年过去了,想起来还觉得尴尬.日本人是很爱背后说别人坏话的.所以我感谢我是个很普通

浅谈HTML5单页面架构(二)——backbone + requirejs + zepto + underscore

本文转载自:http://www.cnblogs.com/kenkofox/p/4648472.html 上一篇<浅谈HTML5单页面架构(一)——requirejs + angular + angular-route>探讨了angular+requirejs的一个简单架构,这一篇继续来看看backbone如何跟requirejs结合. 相同地,项目架构好与坏不是说用了多少牛逼的框架,而是怎么合理利用框架,让项目开发更流畅,代码更容易管理.那么带着这个目的,我们来继续探讨backbone. 首

社区专家谈 12306

由于春运,铁道部官方订票网站12306流量暴增,其Alexa排名一度进入前200,网友戏称,12306已经成为“全球最大.最牛的电商网站”.由于流量激增,12306系统频频瘫痪,一度出现登不上去.登上去抢不了票.抢到票需排队.排队后出票失败等局面.系统的用户体验.性能遭到用户大量的不满. 我们邀请了几位系统架构方面的专家,请他们从技术的角度为你剖析12306(我们会陆续增加其他几位专家的回复).同时我们还从论坛活动(畅聊12306,赢精美礼品)中选取了一些精彩回复.如果您对这些问题有独到的见解,