【算法通关村第五关——队列和Hash基础知识】

Hash和队列

Hash在实际开发中大量使用,在许多复杂的算法问题中也经常使用,但是再算法里只能作为第二选项,因为复杂的算法问题用Hash很容易就能解决。至于队列,直接考队列的算法题几乎没有,大部分场景是作为高级算法的一个工具。



一、Hash的概念和基本特征

Hash(哈希)是将任意长度的输入通过散列算法,转变为固定长度的输出的过程。Hash函数是这个算法的核心,它可以接受不同大小的输入,但在输出上始终具有固定的长度。

二、Hash碰撞处理方法

1.开放寻址法(Open Addressing)

开放寻址法是将哈希表的每个槽直接存储键值对。当发生哈希冲突时,寻找下一个可用的槽来存储冲突的键值对,而不是使用额外的数据结构。具体的寻址方法包括线性探测、二次探测、双重哈希等。

线性探测:当发生冲突时,顺序地查找下一个空槽,直到找到可用的槽。
二次探测:通过二次探测函数找到下一个可用的槽,探测序列为: h(k)+1^2, h(k)-1^2, h(k)+2^2, h(k)-2^2, …,其中h(k)为键的哈希值。
双重哈希:通过两个不同的哈希函数来计算下一个可用的槽。
优点:开放寻址法不需要用链表等额外的数据结构存储冲突的键值对,可以在较小的内存空间中存储较多的键值对,并且在槽位较少的情况下,可以利用CPU缓存的特性提高查找效率。

缺点:开放寻址法可能会导致聚集现象,即冲突的键值对在相邻的槽中聚集,影响了查找效率。此外,删除操作需要通过特定标记来标记已删除的槽,也会增加开销。

2.拉链法(Chaining)

拉链法是通过在哈希表的每个槽中维护一个链表或者其他数据结构来解决哈希冲突。当发生冲突时,发生冲突的键值对会被放在同一个槽中的链表中。这样,如果多个键值对的哈希值相同,它们会以链表的形式存储在同一个槽中。当需要查找、插入或删除某个键值对时,首先根据哈希函数找到对应的槽,然后在链表中进行操作。

优点:拉链法实现简单,适用于处理哈希冲突的链表长度较长的情况,可以在相对较小的内存空间中存储较多的键值对。

缺点:需要额外的存储空间来维护链表,且在链表长度较长时,会影响查找效率。


队列的概念和基本特征

队列(Queue)是一种常见的数据结构,遵循先进先出(FIFO)原则。队列中的元素按照插入的顺序排列,并且只允许在队列的一端(称为队尾)插入元素,在另一端(称为队头)删除元素。

基本特征:

  1. 先进先出:队列中的元素按照插入的顺序排列,最先插入的元素将最先被删除。
  2. 插入和删除操作:队列允许在队尾插入新元素,同时允许在队头删除元素。插入操作称为入队(enqueuing),删除操作称为出队(dequeuing)。
  3. 有界和无界:队列可以是有界的(即有固定的容量)或者无界的(容量不限制)。
  4. 空队列和满队列:队列为空时,没有任何元素可以删除。队列已满时,无法插入新的元素。
  5. 阻塞和非阻塞:在某些情况下,队列的插入(入队)和删除(出队)操作可能会被阻塞。阻塞意味着操作会一直等待,直到满足某个条件。非阻塞操作则会立即返回结果。
  6. 队列的应用:队列被广泛应用在许多场景,如任务调度、消息传递、缓冲区等。例如,在多线程编程中,使用队列可以实现线程之间的协调与通信。

队列的设计和实现方式可以有很多种,包括数组实现、链表实现、循环队列等。每种实现方式都有其优势和限制。根据具体的需求和场景,在选择和使用队列时需要考虑其特性和适用性。

实现队列

public class LinkQueue {
    private Node front;
    private Node rear;
    private int size;

    public LinkQueue() {
        this.front = new Node(0);
        this.rear = new Node(0);
    }

    /**
     * 入队
     */
    public void push(int value) {
        Node newNode = new Node(value);
        Node temp = front;
        while (temp.next != null) {
            temp = temp.next;
        }
        temp.next = newNode;
        rear = newNode;
        size++;
    }

    /**
     * 出队
     */
    public int pull() {
        if (front.next == null) {
            System.out.println("队列已空");
        }
        Node firstNode = front.next;
        front.next = firstNode.next;
        size--;
        return firstNode.data;
    }

    /**
     * 遍历队列
     */
    public void traverse() {
        Node temp = front.next;
        while (temp != null) {
            System.out.print(temp.data + "\t");
            temp = temp.next;
        }
    }

    static class Node {
        public int data;
        public Node next;

        public Node(int data) {
            this.data = data;
        }
    }
}

总结

`

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值