常用手撕非算法题

一. 带定时器和锁的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;
    }
};

四. 工厂模式

#include <iostream>
#include <memory>  // for std::unique_ptr

// 产品基类
class Product {
public:
    virtual void show() const = 0;
    virtual ~Product() = default;
};

// 具体产品A
class ProductA : public Product {
public:
    void show() const override {
        std::cout << "This is Product A." << std::endl;
    }
};

// 具体产品B
class ProductB : public Product {
public:
    void show() const override {
        std::cout << "This is Product B." << std::endl;
    }
};

// 工厂类
class Factory {
public:
    std::unique_ptr<Product> createProduct(const std::string& type) {
        if (type == "A") {
            return std::make_unique<ProductA>();
        } else if (type == "B") {
            return std::make_unique<ProductB>();
        } else {
            return nullptr;
        }
    }
};

int main() {
    Factory factory;
    
    // 创建产品 A
    std::unique_ptr<Product> productA = factory.createProduct("A");
    if (productA) productA->show();
    
    // 创建产品 B
    std::unique_ptr<Product> productB = factory.createProduct("B");
    if (productB) productB->show();
    
    return 0;
}

五. 观察者模式

#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>

// 观察者接口
class Observer {
public:
    virtual void update(const std::string& message) = 0;
    virtual ~Observer() = default;
};

// 具体观察者1
class ConcreteObserver1 : public Observer {
public:
    void update(const std::string& message) override {
        std::cout << "ConcreteObserver1 received: " << message << std::endl;
    }
};

// 具体观察者2
class ConcreteObserver2 : public Observer {
public:
    void update(const std::string& message) override {
        std::cout << "ConcreteObserver2 received: " << message << std::endl;
    }
};

// 被观察者(发布者)
class Subject {
public:
    void attach(std::shared_ptr<Observer> observer) {
        observers.push_back(observer);
    }

    void detach(std::shared_ptr<Observer> observer) {
        observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
    }

    void notify(const std::string& message) {
        for (const auto& observer : observers) {
            observer->update(message);
        }
    }

private:
    std::vector<std::shared_ptr<Observer>> observers;
};

int main() {
    Subject subject;

    std::shared_ptr<Observer> observer1 = std::make_shared<ConcreteObserver1>();
    std::shared_ptr<Observer> observer2 = std::make_shared<ConcreteObserver2>();

    // 添加观察者
    subject.attach(observer1);
    subject.attach(observer2);

    // 被观察者状态发生变化,通知所有观察者
    subject.notify("State has changed!");

    // 移除观察者1
    subject.detach(observer1);

    // 再次通知,只有 observer2 会收到消息
    subject.notify("Another update!");

    return 0;
}


六. 智能指针

#include <iostream>
#include <mutex>

template <typename T>
class SafeUniquePtr {
public:
    // 构造函数:接受一个原始指针
    explicit SafeUniquePtr(T* ptr = nullptr) : pointer(ptr) {}

    // 禁用拷贝构造和拷贝赋值
    SafeUniquePtr(const SafeUniquePtr&) = delete;
    SafeUniquePtr& operator=(const SafeUniquePtr&) = delete;

    // 移动构造函数
    SafeUniquePtr(SafeUniquePtr&& other) {
        std::lock_guard<std::mutex> lock(other.mtx);
        pointer = other.pointer;
        other.pointer = nullptr;
    }

    // 移动赋值操作符
    SafeUniquePtr& operator=(SafeUniquePtr&& other) {
        if (this != &other) {
            std::lock_guard<std::mutex> lock1(mtx);
            std::lock_guard<std::mutex> lock2(other.mtx);
            delete pointer;
            pointer = other.pointer;
            other.pointer = nullptr;
        }
        return *this;
    }

    // 解引用操作符
    T& operator*() {
        std::lock_guard<std::mutex> lock(mtx);
        return *pointer;
    }

    // 指针访问操作符
    T* operator->() {
        std::lock_guard<std::mutex> lock(mtx);
        return pointer;
    }

    // 释放资源
    ~SafeUniquePtr() {
        std::lock_guard<std::mutex> lock(mtx);
        delete pointer;
    }

private:
    T* pointer;  // 原始指针
    mutable std::mutex mtx;  // 用于保护指针的互斥锁
};

七. 事务和分布式事务

BEGIN; -- 开启事务

-- 检查 A 表中的余额是否足够
UPDATE A 
SET balance = balance - 100 
WHERE user_id = 1 
  AND balance >= 100;

-- 检查余额更新是否成功(即 A 表的余额是否足够)
IF ROW_COUNT() = 0 THEN
    -- 如果没有行受到影响,说明余额不足,回滚事务
    ROLLBACK;
    -- 余额不足处理
    SELECT '余额不足';
ELSE
    -- 如果余额足够,继续进行 B 表的更新
    UPDATE B 
    SET balance = balance + 100 
    WHERE user_id = 2;

    -- 提交事务
    COMMIT;
END IF;




-- 数据库 1:检查余额并准备扣款
START TRANSACTION;
UPDATE A 
SET balance = balance - 100 
WHERE user_id = 1 
  AND balance >= 100;

-- 检查是否扣款成功
IF ROW_COUNT() = 0 THEN
    -- 余额不足,回滚事务
    ROLLBACK;
    -- 向协调者报告失败
    REPORT FAILURE TO COORDINATOR;
ELSE
    -- 准备事务但不提交
    PREPARE TRANSACTION 'txn1';
    -- 向协调者报告准备完成
    REPORT SUCCESS TO COORDINATOR;
END IF;

-- 数据库 2:准备增加余额
START TRANSACTION;
UPDATE B 
SET balance = balance + 100 
WHERE user_id = 2;
PREPARE TRANSACTION 'txn2';

-- 如果协调者收到两个数据库的成功报告,则提交事务
COMMIT PREPARED 'txn1';
COMMIT PREPARED 'txn2';
posted @ 2024-10-17 15:51  失控D大白兔  阅读(2)  评论(0编辑  收藏  举报