首页 > 编程语言 >常用手撕非算法题

常用手撕非算法题

时间:2024-10-17 15:44:29浏览次数:9  
标签:Node pre 常用 撕非 cur int next 算法 key

一. 带定时器和锁的LRU缓存

#include <iostream>
#include <unordered_map>
#include <chrono>
#include <mutex>
#include <thread>

using namespace std;

class LRUCache {
public:
    typedef struct Node {//双向链表节点
        int key; // 在哈希中的键值,用于删除哈希
        int data;
        Node* pre;
        Node* next;
        chrono::steady_clock::time_point timestamp; // 时间戳,用于生存时间
        Node() :  key(0), data(0), pre(nullptr), next(nullptr), timestamp(chrono::steady_clock::now()) {}
        Node(int key, int val) : key(key), data(val), pre(nullptr), next(nullptr), timestamp(chrono::steady_clock::now()) {}
    }Node, *pNode;

    int capacity;
    unordered_map<int, pNode> m;
    Node* listpre = new Node();
    Node* listtail = new Node();
    mutex mtx; // 并发访问锁
    const chrono::seconds ttl = chrono::seconds(5); // 生存时间:5秒

    LRUCache(int capacity) {
        this->capacity = capacity;
        listpre->next  = listtail;
        listtail->pre = listpre;

        // 后台线程定期清理过期缓存
        thread(&LRUCache::cleanUpExpired, this).detach();
    }

    void remove(Node* cur) {
        Node* pre = cur->pre;
        Node* next = cur->next;
        pre->next = next;
        next->pre = pre;
    }

    void update(Node* cur) {
        remove(cur);
        insert(cur);
        cur->timestamp = chrono::steady_clock::now(); // 更新时间戳
    }

    void insert(Node* cur) {
        listtail->pre->next = cur;
        cur->pre = listtail->pre;
        cur->next = listtail;
        listtail->pre = cur;
    }

    void release() {
        Node* cur = listpre->next;
        m.erase(cur->key); // 删除哈希表中的键
        remove(cur);
        delete cur; // 释放内存
    }

    // 清理过期的缓存项
    void cleanUpExpired() {
        while (true) {
            this_thread::sleep_for(chrono::seconds(1)); // 每1秒检查一次
            lock_guard<mutex> lock(mtx); // 锁定访问
            auto now = chrono::steady_clock::now();
            Node* cur = listpre->next;

            while (cur != listtail) {
                if (chrono::duration_cast<chrono::seconds>(now - cur->timestamp) >= ttl) {
                    Node* next = cur->next;
                    m.erase(cur->key);
                    remove(cur);
                    delete cur;
                    cur = next;
                } else {
                    cur = cur->next;
                }
            }
        }
    }

    int get(int key) {
        lock_guard<mutex> lock(mtx); // 加锁
        if (m.count(key) == 0) return -1;
        Node* cur = m[key];
        if (chrono::duration_cast<chrono::seconds>(chrono::steady_clock::now() - cur->timestamp) >= ttl) {
            // 缓存已过期,删除
            m.erase(key);
            remove(cur);
            delete cur;
            return -1;
        }
        update(cur); // 更新优先级
        return cur->data;
    }

    void put(int key, int value) {
        lock_guard<mutex> lock(mtx); // 加锁
        if (m.count(key)) {
            Node* cur = m[key];
            cur->data = value;
            update(cur);
            return;
        }
        if (m.size() == capacity) release(); // 超出容量,释放最久未使用的节点
        Node* cur = new Node(key, value);
        m[key] = cur;
        insert(cur);
    }
};

二. 循环打印123

package main

import (
	"fmt"
	"sync"
)

func main() {
	ch1 := make(chan bool)
	ch2 := make(chan bool)
	ch3 := make(chan bool)

	bufferSize := 5
	ch := make(chan int, bufferSize) // 创建一个带缓冲的通道
	ch <- 1

	var wg sync.WaitGroup
	var mutex sync.Mutex
	mutex.Lock()
	defer mutex.Unlock()
	wg.Add(3) // 每个 Goroutine 负责三次打印

	// Goroutine 打印 1
	go func() {
		defer wg.Done()          // 完成后标记 Done
		for i := 0; i < 3; i++ { // 打印 3 次
			<-ch1
			fmt.Println(1)
			ch2 <- true // 通知第二个 Goroutine
		}
	}()

	// Goroutine 打印 2
	go func() {
		defer wg.Done()          // 完成后标记 Done
		for i := 0; i < 3; i++ { // 打印 3 次
			<-ch2
			fmt.Println(2)
			ch3 <- true // 通知第三个 Goroutine
		}
	}()

	// Goroutine 打印 3
	go func() {
		defer wg.Done()          // 完成后标记 Done
		for i := 0; i < 3; i++ { // 打印 3 次
			<-ch3
			fmt.Println(3)
			if i < 2 { // 在前两次时继续循环
				ch1 <- true // 通知第一个 Goroutine
			}
		}
	}()

	// 启动第一个 Goroutine
	ch1 <- true

	// 等待所有 Goroutine 完成
	wg.Wait()
}

三. 单例模式

#include <iostream>
#include <mutex>

// 懒汉式单例模式 (Lazy Singleton)
class LazySingleton {
private:
    static LazySingleton* instance;  // 指向单例对象的指针
    static std::mutex mtx;  // 用于保证线程安全的互斥锁

    // 私有化构造函数,禁止外部实例化
    LazySingleton() {
        std::cout << "LazySingleton Constructor Called" << std::endl;
    }

public:
    // 禁止拷贝构造函数和赋值操作符
    LazySingleton(const LazySingleton&) = delete;
    LazySingleton& operator=(const LazySingleton&) = delete;

    // 静态方法,用于获取单例实例
    static LazySingleton* getInstance() {
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lock(mtx);  // 线程安全锁
            if (instance == nullptr) {  // 双重检查锁定
                instance = new LazySingleton();
            }
        }
        return instance;
    }
};



// 饿汉式单例模式 (Eager Singleton)
class EagerSingleton {
private:
    // 静态实例在程序启动时立即创建
    static EagerSingleton instance;

    // 私有化构造函数,禁止外部实例化
    EagerSingleton() {
        std::cout << "EagerSingleton Constructor Called" << std::endl;
    }

public:
    // 禁止拷贝构造函数和赋值操作符
    EagerSingleton(const EagerSingleton&) = delete;
    EagerSingleton& operator=(const EagerSingleton&) = delete;

    // 静态方法,用于获取单例实例
    static EagerSingleton& getInstance() {
        return instance;
    }
};




// 懒汉式单例模式 - 使用 C++11 静态局部变量的线程安全初始化
class LazySingleton {
private:
    // 私有化构造函数,防止外部创建实例
    LazySingleton() {
        std::cout << "LazySingleton Constructor Called" << std::endl;
    }

public:
    // 禁止拷贝构造函数和赋值操作符
    LazySingleton(const LazySingleton&) = delete;
    LazySingleton& operator=(const LazySingleton&) = delete;

    // 提供静态方法获取单例实例
    static LazySingleton& getInstance() {
        static LazySingleton instance;  // 静态局部变量,C++11后线程安全
        return instance;
    }
};

标签:Node,pre,常用,撕非,cur,int,next,算法,key
From: https://www.cnblogs.com/929code/p/18472460

相关文章

  • 翻转链表常用写法
    翻转链表常用写法循环写法classSolution{public:ListNode*reverseList(ListNode*head){ListNode*prev=nullptr,*next=nullptr,*now=head;while(now){next=now->next;now->next=prev;prev=......
  • 代码随想录算法训练营第二天|209长度最小的子数组、59螺旋矩阵
    1leetcode209长度最小的子数组题目链接:209.长度最小的子数组文章链接:代码随想录(programmercarl.com)视频链接:拿下滑动窗口!|LeetCode209长度最小的子数组思路:没有思路,看到这道题有一种想立马退出的感觉,无从下手1.1暴力搜索1.1.1python版本这个版本的新知识就是定义......
  • 【QT】常用控件(二)
    个人主页~常用控件(一)~常用控件三、按钮类控件1、PushButtonwidget.hwidget.cpp2、RadioButton3、CheckBox四、显示类控件1、label三、按钮类控件1、PushButtonQPushButton继承自QAbstractButton,它是所有按钮的父类我们从这个按钮的属性表中可以看到,QPus......
  • JVM系列(九) -垃圾对象的回收算法介绍
    一、摘要在之前的文章中,我们介绍了JVM内部布局、对象的创建过程以及运行期的相关优化手段。今天通过这篇文章,我们一起来了解一下对象回收的判定方式以及垃圾对象的回收算法等相关知识。二、对象回收判定方式当一个对象被创建时,虚拟机会优先分配到堆空间中,当对象不再被......
  • 工装识别算法 工服穿戴检测系统
    工装识别算法工服穿戴检测系统特点包括:工装识别算法工服穿戴检测系统利用图像识别技术,系统可以准确地识别工人是否穿戴了正确的工装,包括工作服、安全帽等。一旦检测到未穿戴的情况,系统将立即发出警报,并提示相关人员进行整改。工装识别算法工服穿戴检测系统对于电力作业场景,系统......
  • 常见的缓存淘汰算法
    应用场景:缓存淘汰算法可以广泛应用于任何有缓存淘汰需求的场景,并不仅限于某个特定的插件或工具。许多软件和系统,如数据库(Redis、Memcached)、Web服务器(Nginx、Varnish)、内容分发网络(CDN)、浏览器缓存、甚至操作系统的内存管理,都会使用这些算法来决定在缓存空间满时该移除哪些数据......
  • 算法->二分查找
    二分查找找>=target的第一个位置找<=target的最后一个位置classSolution{public://找>=target的第一个位置intbinarySearchLeft(vector<int>&nums,inttarget){intleft=0,right=nums.size()-1;while(left<=right){......
  • 前端常用6种数据加密方式的使用(最详解)
    原文链接:https://blog.csdn.net/2401_82471222/article/details/140538952前端常用的六种数据加密方式包括Base64编码、MD5加密、SHA-1加密、SHA-256加密、AES加密和RSA加密。每种加密方式都有其特定的使用场景和优缺点。以下是这些加密方式的详细使用说明:1.Base64编码定义与特......
  • 算法(第4版)练习题 3.3.20 的一种解法
    本文给出了对于《算法(第4版)》(以下简称原书或书)中的练习题3.3.20的一种解法。◆要求原书中的练习题3.3.20要求计算一棵大小为N且完美平衡的二叉查找树的内部路径长度,其中N为2的幂减1。◆解答N为2的幂减1的一颗完美平衡的二叉查找树是一棵满二叉树。在这样的......
  • 时间复杂度为 O(n^2) 的排序算法
    作者:京东保险王奕龙对于小规模数据,我们可以选用时间复杂度为O(n2)的排序算法。因为时间复杂度并不代表实际代码的执行时间,它省去了低阶、系数和常数,仅代表的增长趋势,所以在小规模数据情况下,O(n2)的排序算法可能会比O(nlogn)的排序算法执行效率高。不过随着数据规模增大,......