首页 > 编程语言 >树(tree)和哈希算法(Hash)

树(tree)和哈希算法(Hash)

时间:2024-09-11 21:51:23浏览次数:10  
标签:Hash tree proot pnode 二叉树 哈希 data 节点

由n个节点组成的有限集。有一个根节点;其他节点只有一个前驱节点,但可以有多个后继节点。

  • 叶子节点(终端结点):只有前驱结点没有后继结点
  • 结点度:子节点的个数称之为度
  • 树的(广)度:树中各节点度的最大值 
  • 深度:从根节点到最底层节点的层数

森林:n个互不相交的树的集合

二叉树:任意一个节点的子节点个数不能超过2个(树的度为2),且子节点的位置不可更改。

满二叉树:在不增加树的层数的前提下,无法再增加一个节点的二叉树       

 满二叉树第K层有2^(k-1)个节点        K层满二叉树总共有2^k-1个节点  

完全二叉树:只是删除了满二叉树最底层最右边的连续若干个节点,形成了完全二叉树    

满二叉树 ==> 完全二叉树
完全二叉树 =/=> 满二叉树

二叉树的遍历:

(1)前序遍历:根    左    右

void pre_order(TNode_t *proot)
{
    if(NULL == proot)
    {
        return;
    }
    printf("%c", proot->data);
    pre_order(proot->pl);
    pre_order(proot->pr);
}

(2)中序遍历:左    根    右

void mid_order(TNode_t *proot)
{
    if(NULL == proot)
    {
        return;
    }
    mid_order(proot->pl);
    printf("%c", proot->data);
    mid_order(proot->pr);
}

(3)后续遍历:左    右    根

void pos_order(TNode_t *proot)
{
    if(NULL == proot)
    {
        return;
    }
    pos_order(proot->pl);
    pos_order(proot->pr);
    printf("%c", proot->data);
}

(4)层序遍历:逐层向下遍历

void layer_order(TNode_t *proot)
{
    QDataType outdata;
    Queue_t *pqueue = create_queue();
    if(NULL == pqueue)
    {
        printf("fail create_queue");
        return ;
    }

    push_queue(pqueue, proot);

    while(!is_empty_queue(pqueue))
    {
        pop_queue(pqueue, &outdata);
        printf("%c", outdata->data);
        if(outdata->pl != NULL)
        {
            push_queue(pqueue, outdata->pl);
        }
        if(outdata->pr != NULL)
        {
            push_queue(pqueue, outdata->pr);
        }
    }
    destroy_queue(pqueue);
}

二叉树的遍历特性:

  • 已知前序遍历序列和中序遍历序列,可以唯一确定一棵二叉树;
  • 已知后序遍历序列和中序遍历序列,可以唯一确定一棵二叉树;

哈希算法:

在记录的存储位置和它的关键字之间建立一种去特定的对应关系,使得每个关键字key对应一个存储位置;查找时,根据确定的对应关系,找到给定的key的映射。
    记录的存储位置 = f(关键字)我们把这种关系f称为哈希函数(散列函数);
    采用这种散列技术将记录存储在一块连续的存储空间,这块连续存储开空间称为哈希表或散列表。

  • 存储时,通过散列函数计算出记录的散列地址;
  • 查找时,根据同样的散列函数计算记录的散列地址,并按此散列地址访问记录。
//插入
int insert_hashtable(HSDataType data)
{
    int addr = hash_function(data.name[0]);

    HSNode_t *pnode = (HSNode_t *)malloc(sizeof(HSNode_t)); 
    if(NULL == pnode)
    {
        perror("fail malloc");
        return -1;
    }
    pnode->data = data;
    pnode->pnext = NULL;

    pnode->pnext = hashtable[addr];
    hashtable[addr] = pnode;
    
    return 0;
}

//遍历
void traverse_hashtable()
{
    for (int i = 0; i < HASH_SIZE; i++)
    {
        HSNode_t *pnode = hashtable[i];
        while (pnode)
        {
            printf("Name: %s, Tel: %s\n", pnode->data.name, pnode->data.tel);
            pnode = pnode->pnext;
        }
    }
}

//查找
HSNode_t *find_hashtable(char *name)
{
    int addr = hash_function(name[0]);
    HSNode_t *pnode = hashtable[addr];
    while(pnode)
    {
        if(!strcmp(pnode->data.name, name))
        {
            return pnode;
        }
        pnode = pnode->pnext;
    }
    return NULL;
}

//销毁
void destroy_hashtable()
{
    for(int i = 0; i < HASH_SIZE; i++)
    {
        HSNode_t *pnode = hashtable[i];
        while(pnode)
        {

哈希冲突的解决方法

  1. 开放定址法(Open Addressing):当发生冲突时,按照某种规则在哈希表中寻找另一个空的位置来存放该元素。常见的开放定址法有线性探测法、二次探测法和双重哈希法等。

    • 线性探测法:从发生冲突的位置开始,依次向后探测,直到找到一个空的位置为止。
    • 二次探测法:在发生冲突时,以冲突位置为基础,依次加上或减去一个平方数,直到找到一个空的位置。
    • 双重哈希法:使用两个哈希函数,当发生冲突时,使用第二个哈希函数计算的结果来调整探测的位置。
  2. 链地址法(Chaining):将哈希表中的每个位置看作一个链表的头节点,当发生冲突时,将元素存储在对应的链表中。这种方法可以有效地避免冲突的发生,但会增加存储开销。

  3. 再哈希法(Rehashing):准备多个哈希函数,当发生冲突时,使用另一个哈希函数重新计算位置,直到找到一个空的位置。

  4. 建立公共溢出区:将所有发生冲突的元素都存储在一个公共的溢出区中。

算法:

算法的设计

  1. 正确性,语法正确;合法的输入能得到合理的结果。对非法的输入,给出满足要求的规格说明对精心选择,甚至刁难的测试都能正常运行,结果正确
  2. 可读性,便于交流,阅读,理解    高内聚 低耦合
  3. 健壮性,输入非法数据,能进行相应的处理,而不是产生异常
  4. 高效率(时间复杂度)
  5. 低存储(空间复杂度)

算法时间复杂度

        执行这个算法所花时间的度量
        将数据量增长和时间增长用函数表示出来,这个函数就叫做时间复杂度。
        一般用大O表示法:O(n)-----时间复杂度是关于数据n的一个函数。随着n的增加,时间复杂度增长较慢的算法时间复杂度低

时间复杂度的计算规则

  1. 用常数1 取代运行时间中的所有加法常数
  2. 在修改后的运行函数中,只保留最高阶项。
  3. 如果最高阶存在且系数不是1,则去除这个项相乘的常数。

标签:Hash,tree,proot,pnode,二叉树,哈希,data,节点
From: https://blog.csdn.net/qq_69639971/article/details/142067167

相关文章

  • TreeMap源码详解—彻底搞懂红黑树的平衡操作
    介绍TreeSet和TreeMap在Java里有着相同的实现,前者仅仅是对后者做了一层包装,也就是说TreeSet里面有一个TreeMap(适配器模式)。JavaTreeMap实现了SortedMap接口,也就是说会按照key的大小顺序对Map中的元素进行排序,key大小的评判可以通过其本身的自然顺序(naturalordering),也可以......
  • [ABC250Ex] Trespassing Takahashi
    感觉是很厉害的结论题。题意给你一个带权无向连通简单图\(G=(V,E),|V|=n,|E|=m\)。钦定编号\(1\simk\)的点为关键点。给定\(q\)次询问,每次询问给出\(x,y,t\),表示你需要回答是否存在一条路径,使得从\(x\)出发到\(y\)的路径上相邻两个关键点的距离都不超过\(t\)。保证......
  • [Java并发]Concurrenthashmap的size()
    1.一致性定义关于一致性的定义,大概如下:一致性(Consistency)是指多副本(Replications)问题中的数据一致性。可以分为强一致性、顺序一致性与弱一致性。1.1强一致性(StrictConsistency)强一致性也被可以被称做:原子一致性(AtomicConsistency)线性一致性(LinearizableConsistency)要......
  • HashSet和HashMap
    HashSet源码解析publicHashSet(){map=newHashMap<>();}privatestaticfinalObjectPRESENT=newObject();//这是一个空对象,在HashSet中用来占位,但本质上仍然是HashMappublicbooleanadd(Ee){returnmap.put(e,PRESENT)==null;}......
  • 哈希表
    模拟散列表把一个较大范围内的数转化为较小范围的数的集合。模上一个数(x%N+N)%N防止下标出现负数数据结构用一个数组表示要插入的槽,如果哈希产生了冲突,则把数插入到槽中(单链表)。数组+模拟链表拉链法实现代码:#include<cstring>#include<iostream>usingnamespacestd;......
  • 浙大数据结构慕课课后题(03-树3 Tree Traversals Again)
    题目翻译:题解:         #include<bits/stdc++.h>usingnamespacestd;voidCreatTree();voidsolve(intpreL,intinL,intpostL,intn);intPre[35],In[35],Post[35];int N;intmain(){ cin>>N; getchar(); CreatTree(); solve(0,0,0,N); for......
  • 12-LinkedHashSet
    LinkedHashSetHashSet得到的数据是无序的--->能不能得到的数据是有序的,嫩不能按照输入原序输出?---->LinkedHashSet特点唯一有序(按照输入顺序输出)多了一个总链表,按装入顺序串在一起原理其实就是在HashSet的基础上,多了一个总的链表,这个总链表将放入的元素串在一起,方便有......
  • 哈希表、算法
    哈希表hash:在编程和数据结构中,"hash"通常指的是哈希函数,它是一种算法,用于将数据(通常是字符串)映射到一个固定大小的数字(哈希值)。哈希函数在哈希表中尤为重要,哈希表是一种通过哈希函数将键映射到表中位置的数据结构,以实现快速的数据插入和检索。哈希表(HashTable):也称为散......
  • 【Redis】redis5种数据类型(哈希)
    目录基本介绍命令HSETHGETHEXISTSHKEYSHVALSHGETALLHMGETHLENHSETNXHINCRBYHINCRBYFLOATHSTRLEN内部编码原生字符串类型、哈希类型、序列化字符串json作缓存的区别基本介绍哈希类型中的映射关系是field-value,用于区分redis整体的键值对(key-value)命令H......
  • 【算法笔记】树状数组/Binary Indexed Tree/Fenwick Tree
    前言树状数组,即树形存储的数组,又称BinaryIndexedTree或FenwickTree。抛开它树形的存储结构,这种神奇的数据结构的应用看起来与「树」没什么关系:有一个序列\(A=(A_1,A_2,\dots,A_N)\),在不超过\(\mathcalO(\logN)\)的时间复杂度内完成下列操作:\(\to~\)求\([L,R]\)区间内所......