ソートアルゴリズムとLRUキャッシュアルゴリズム

leetcode 912 配列の並べ替え

1 つ与えられた場合は整数数组nums、配列を設定してください升序排列

方法 1: 最も簡単な小顶堆解決策

class Solution {
    
    
public:
    vector<int> sortArray(vector<int>& nums) {
    
    
        vector<int>res;
        priority_queue<int,vector<int>,greater<int>>q;//小顶堆
        for(auto num:nums)
        {
    
    
            q.push(num);//所有的元素入队后 自动调整顺序 队首元素是最小的元素
        }
        while(!q.empty())
        {
    
    
            res.push_back(q.top());//依次接收队首元素就是从小到大的顺序
            q.pop();
        }
        return res;
    }
};

方法 2: 最適化されたクイックソート方法
注:未优化之前的代码是提交不成功的;



//快排用三数取中进行优化
//之所以用三数取中的方法进行优化是因为当给定的待排序数组是有有序的或者基本有序 
//那么快排算法的效率会严重降低---会退化成冒泡排序---
//因此要对及基准元素的选取进行优化--三数取中优化(不再是取左边界元素为基准元素了)-----
//快速排序
class Solution
{
    
    
public:
    //三数取中进行优化
    void GetMid(vector<int>& nums, int left, int right) {
    
    
        int mid = left + (right - left) / 2; //中间元素下标
        if (nums[left] > nums[right]) //交换后使得left<right
        {
    
    
            swap(nums[left], nums[right]);
        }
        if (nums[mid] > nums[right]) //交换后使得mid<right
        {
    
    
            swap(nums[mid], nums[right]);
        }
        if (nums[mid] > nums[left]) //交换后使得mid<left<right
        {
    
    
            swap(nums[mid], nums[left]);
        }
    }
    //分割 分治
    int Patition(vector<int>&nums, int left, int right)
    {
    
    
        //执行三数取中优化
        GetMid(nums, left,right);
        //选取枢轴值
        int key = nums[left];//基准元素 通常选取左边界元素为基准元素
        while (left < right)
        {
    
    
            while (left < right && nums[right] >= key)right--;//右边界元素继续左移 直到遇到比基准元素小的元素
            if (left < right)nums[left++] = nums[right];//将比基准小的元素对左元素进行覆盖,将较小的元素移动到基准元素左边
            while (left < right && nums[left] <= key)left++;//左边界元素继续右移 直到遇到比基准元素大的元素
            if (left < right)nums[right--] = nums[left];//将比基准大的元素对右元素进行覆盖,将较大的元素移动到基准元素右边
        }
        nums[left] = key;//将基准元素放到两区间的中间位置,最终left的位置就是中间位置
        return left;//返回存放基准元素的最终位置
    }
    
//快速排序
    void Quicksort(vector<int>&nums, int left, int right)
    {
    
    
        if (left < right)
        {
    
    
            int mid = Patition(nums, left, right);//划分区间 mid表示基准元素的最终位置
            Quicksort(nums, left, mid - 1);//递归的对左区间进行快排
            Quicksort(nums, mid + 1, right);//递归的对右区间进行快排
        }
    }
    
//进行数组的排序
    vector<int> sortArray(vector<int>& nums) {
    
    
        Quicksort(nums, 0, nums.size() - 1);
        return nums;
    }

};

//-------------冒泡排序------------------------

//冒泡排序
//从左向右 每两个元素进行一次比较 元素较大的那个移动到后面的位置 最后 最大的那个元素移动到最后的位置;
//对于待排序的n个元素 则需要比较n-1次才可以确定所有元素的顺序
//外层for:控制比较轮次  每一轮比较都会确定一个元素的位置 n个元素 需要比较n-1次 
//内层for:控制两个挨着的元素进行调整次序 n-i-1是需要进行调整的两个元素的对数;每进行一次外层的循环 需要调整的对数就减一
class Solution
{
    
    
public:
	void bubblesort(vector<int>& nums)
	{
    
    
		int n = nums.size();
		for (int i = 0; i < n-1; i++)
		{
    
    
			for (int j = 0; j < n - i-1; j++)
			{
    
    
				if (nums[j] > nums[j + 1])
				{
    
    
					int temp = nums[j];
					nums[j] = nums[j + 1];
					nums[j + 1] = temp;
				}
			}
		}
	}
};

方法 3: ビッグトップヒープ方法



class Solution
{
    
    
public:
    //调整最大堆
    void adjustHeap(vector<int>&nums, int i, int len)
    {
    
    
        int largest = i;
        int l = 2 * i + 1, r = 2 * i + 2;
        if (l<len && nums[l]>nums[largest])largest = l;
        if (r<len && nums[r]>nums[largest])largest = r;
        if (largest != i)
        {
    
    
            swap(nums[largest], nums[i]);
            adjustHeap(nums, largest, len);//这里交换之后 可能导致后续的子树不再满足最大堆的条件 因此需要对后续子树进行更新
        }
    }
    //建立最大堆
    void makeHeap(vector<int>&nums, int len)
    {
    
    
        for (int i = len / 2 - 1; i >= 0; i--)//从完全二叉树的最后一个节点开始建堆
        {
    
    
            adjustHeap(nums, i, len);//建立最大堆的过程中需要调用最大堆的函数
        }
    }
    //实现堆排序
    void heapSort(vector<int>&nums, int len)
    {
    
    
        makeHeap(nums, len);
        for (int i = len - 1; i > 0; i--)
        {
    
    
            swap(nums[i], nums[0]);//交换堆顶的最大的元素a[0]和待排序数组的最后一个元素a[i]
            adjustHeap(nums, 0, i);//交换之后 最大堆被破坏 需要重新对剩余的元素建立最大堆
        }
    }
    vector<int>sortArray(vector<int>& nums)
    {
    
    
        heapSort(nums,nums.size());
        return nums;
    }
};


Leetcode 146 LRU キャッシュ構造の実装

LRU アルゴリズム:最近最久未使用
このデータ構造を実現するための核となるのは、次の組み合わせ哈希链表です。双向链表list和哈希表map

アルゴリズム設計:
1. キャッシュ内の要素には、最近使用したデータと最近使用しなかったデータを区別するタイミングが必要であり、容量がいっぱいになった場合は、最近使用しなかったデータを削除する必要があります。
キャッシュがアクセスされる キーは、この要素を最も最近使用された要素にする必要があります、つまり、キャッシュは任意の位置での要素の高速な挿入と削除をサポートする必要があります; 3. 毎回リンクされたリストの末尾から要素を追加すると仮定します
。 、末尾に近い要素は最後に使用された要素、先頭に近いほど長い間使用されていない要素です; 4. キーの場合、ハッシュを通じてリンクされたリスト内のノードを素早く見つけることができます
。テーブルを使用して、対応する val
5 を取得します。哈希表中存的数据结构是key-val 链表中的数据结构存的也是key-val

ここに画像の説明を挿入

put メソッドの論理構造は次のとおりです。
ここに画像の説明を挿入

コード:

#include<iostream>
using namespace std;
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<unordered_map>
#include<list>

///设计LRU缓存结构
//关于C++的list 是一个双向链表容器 可以进行高效的插入和删除操作;list不支持随机存取元素 不支持at函数与operator[]操作符
class LRUCache
{
    
    
private:
	int cap;//最大容量             pair的第一个int 就是map中的键 第二个int是值
	list<pair<int, int>>cache;//双向链表/缓存结构 可以理解为一个队列 左边是队头 右边是队列.最近使用的排在队头 最久未使用的排在队尾;
	unordered_map<int, list<pair<int, int>>::iterator>map;//list<pair<int,int>>::iterator是通过list<pair<int,int>>定义的一个迭代器类型
   //哈希链表中 键是一个整数 值是一个双向链表容器,容器中的值通过迭代器得到
public:
	LRUCache(int capacity):cap(capacity){
    
    } //以正整数作为容量capacity初始化LRU缓存
	int get(int key) //如果关键字key存在于缓存中 则返回关键字的值 否则返回-1
	{
    
    
		if (map.find(key) == map.end())return -1;//key不存在 
		auto key_value = *map[key];//map[key]是一个迭代器 用*得到迭代器指向的对象的值 这里key_value是一个pair类型
		cache.erase(map[key]);//先从链表中删除这个使用过的节点
		cache.push_front(key_value);//将要用到的值放入容器头部 表示最近访问了
		map[key] = cache.begin();//
		return key_value.second;//返回pair的第二个int值 就是我们要得到的值
	}
	void put(int key, int value)//如果关键字key已经存在 则变更其数据值value 如果不存在 则向缓存中插入该组key-value  如果插入操作导致关键之数量超过cap 则应该逐出最近最久未使用的关键字
	{
    
    
		if (map.find(key) == map.end())//Key不存在
		{
    
    
			if (cache.size() == cap)//超过容量 开始删除
			{
    
    
				map.erase(cache.back().first);//删除哈希链表中的键
				cache.pop_back();//删除list容器最后一个元素(容器中最后一个元素就是最近最久未使用的元素)
			}
		}
		else//Key已经存在 
		{
    
    
			cache.erase(map[key]);//删除旧值
		}
		cache.push_front({
    
     key,value });//将最近访问过的键提前至队首 表示最近访问了
		map[key] = cache.begin();///更新新值
	}

};

int main()
{
    
    
	system("pause");
	return 0;
}

おすすめ

転載: blog.csdn.net/weixin_48433164/article/details/123730318