从C语言到C++_19(容器适配器+stack和queue模拟实现+优先级队列priority_queue)

news2024/11/24 7:02:03

目录

1. 容器适配器

1.1 什么是适配器

1.2 STL标准库中stack和queue的底层结构

2. stack和queue的模拟实现

2.1 stack模拟实现

2.2 queue的模拟实现

3. deque的介绍(了解)

3.1 deque的实现原理

3.2 deque的缺陷和使用场景

4. 优先级队列 priority_queue

4.1 priority_queue的介绍

4.2 priority_queue的使用

4.3 priority_queue解决TopK问题

剑指 Offer II 076. 数组中的第 k 大的数字 - 力扣(LeetCode)

215. 数组中的第K个最大元素 - 力扣(LeetCode)

本章完。


1. 容器适配器

1.1 什么是适配器

想了解这里的 "适配器",我们先去看看电源适配器:

 【百度百科】电源适配器又叫外置电源,是小型便携式电子设备及电子电器的供电电压变换设备,常见于手机、液晶显示器和笔记本电脑等小型电子产品上。

电源适配器是进行 "转换" 的,它本质上可以理解为是一个变压器。

标准家庭用电电压为220V,我们设备用电其实并不需要这么高,

而电源适配器可以使较高的交流电压降低到合适于手机电池的直流工作电压。

也就是说,电源适配器是用来 "转换" 的。

再看看容器适配器:

一种用来修饰容器,仿函数或者迭代器的接口的东西。

配接器修改类的接口,使原来不相互匹配的两个类可以相互匹配,进行合作。

1.2 STL标准库中stackqueue的底层结构

前一篇我们提到:虽然stackqueue中也可以存放元素,

但在STL中并没有将其划分在容器的行列,而是将其称为容器适配

这是因为stack和队列只是对其他容器的接口进行了包装,

STLstackqueue默认使用deque,比如:

 deque(双端队列,后面讲)(可以手动换成其它的)

2. stack和queue的模拟实现

2.1 stack模拟实现

我们以前已经用C语言写过了一个数组栈:

数据结构与算法⑧(第三章_上)栈的概念和实现(力扣:20. 有效的括号)_GR C的博客-CSDN博客

数组栈和链式栈

实现栈无非就两种结构:数组结构 和 链式结构,两种结构都可以实现。

数组栈和链式栈哪种结构更好?

相对而言数组的结构实现更优,尾插尾删的效率高,缓存利用率高,它的唯一缺点只是增容,

但是增容1次扩2倍对栈来说本身就比较合理,是无伤大雅的。而链式栈虽然不会空间浪费,

用一个 malloc 申请一个,但是链式栈存在一个致命的缺点:单链表不好出数据,

必须要实现双向链表,否则尾上删除数据将会异常麻烦。

如果硬要使用链式栈:

① 如果用尾做栈顶,尾插尾删,要设计成双向链表,否则删数据效率低。

② 如果用头做栈顶,头插头删,就可以设计成单链表。

在C++我们就可以直接用vector实现数组栈了,体会一下C++的方便,直接放stack.h了:

#pragma once
#include <iostream>
#include <vector>
using namespace std;

namespace rtx
{
	template<class T>
	class stack
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_back();
		}
		T& top()
		{
			return _con.back();
		}
		const T& top() const
		{
			return _con.pop_back();
		}
		bool empty() const
		{
			return _con.empty();
		}
		size_t size() const
		{
			return _con.size();
		}
	private:
		vector<T> _con;
	};
}

测试Test.c:

#include "Stack.h"

void test_stack()
{
    rtx::stack<int> st;
    st.push(1);
    st.push(2);
    st.push(3);
    st.push(4);
    st.push(5);

    cout << "st.size() = " << st.size() << endl;
    while (!st.empty())
    {
        cout << st.top() << " "; // 后进先出
        st.pop();
    }
    cout << endl;
}

int main()
{
    test_stack();

    return 0;
}

 我们这里复用了vector,这是不是适配器呢?

这里并不是,因为底层已经写死了,它就是数组栈,如果我想要一个链式栈呢?

模板的方便又来了:

#pragma once
#include <iostream>
#include <vector>
using namespace std;

namespace rtx
{
	template<class T, class Container>
	class stack
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_back();
		}
		T& top()
		{
			return _con.back();
		}
		const T& top() const
		{
			return _con.pop_back();
		}
		bool empty() const
		{
			return _con.empty();
		}
		size_t size() const
		{
			return _con.size();
		}
	private:
		//vector<T> _con;
		Container _con;
	};
}
#include "Stack.h"

void test_stack()
{
    rtx::stack<int, vector<int>> st;
    st.push(1);
    st.push(2);
    st.push(3);
    st.push(4);
    st.push(5);

    cout << "st.size() = " << st.size() << endl;
    while (!st.empty())
    {
        cout << st.top() << " "; // 后进先出
        st.pop();
    }
    cout << endl;
}

int main()
{
    test_stack();

    return 0;
}

 如果我们要链式栈:把显示传的vector换成list(包一下头文件):

前面说到,STL里面stack和queue的默认适配器是deque:

 

把其它头文件移到Test.c ,Stack.h的最终就是这样的:

#pragma once

#include <deque>

namespace rtx
{
	template<class T, class Container = deque<T>>
	class stack
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_back();
		}
		T& top()
		{
			return _con.back();
		}
		const T& top() const
		{
			return _con.pop_back();
		}
		bool empty() const
		{
			return _con.empty();
		}
		size_t size() const
		{
			return _con.size();
		}
	private:
		Container _con;
	};
}

2.2 queue的模拟实现

deque等下讲,这里先放queue的模拟实现,经过前面的学习,直接放了:

Queue.h:

#pragma once

#include <deque>

namespace rtx
{
	template<class T, class Container = deque<T>>
	class queue
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_front();
		}
		T& back()
		{
			return _con.back();
		}
		T& front()
		{
			return _con.front();
		}
		const T& back() const
		{
			return _con.back();
		}
		const T& front() const
		{
			return _con.front();
		}
		bool empty()  const
		{
			return _con.empty();
		}
		size_t size() const
		{
			return _con.size();
		}
	private:
		Container _con;
	};
}

Test.c:

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

#include "Stack.h"
#include "Queue.h"

void test_stack()
{
    rtx::stack<int> st;
    st.push(1);
    st.push(2);
    st.push(3);
    st.push(4);
    st.push(5);

    cout << "st.size() = " << st.size() << endl;
    while (!st.empty())
    {
        cout << st.top() << " "; // 后进先出
        st.pop();
    }
    cout << endl;
}
void test_queue()
{
    rtx::queue<int> q;
    q.push(1);
    q.push(2);
    q.push(3);
    q.push(4);
    q.push(5);

    cout << "q.size() = " << q.size() << endl;
    while (!q.empty())
    {
        cout << q.front() << " "; // 先进先出
        q.pop();
    }
    cout << endl;
}
int main()
{
    test_stack();
    test_queue();

    return 0;
}

值得注意的是这里的queue不能显示地传vector,因为vector没有头删。

3. deque的介绍(了解)

deque :双端队列 - double ended queue

可以发现它的接口很多,有[ ] 也有头删。 

deque 是一种双开口的 "连续" 空间的数据结构,

deque 可以在头尾两端进行插入和删除操作。且时间复杂度为O(1),

与 vector 相比,头插效率高,不需要搬移元素,与 list 相比,deque 的空间利用率更高。

3.1 deque的实现原理

deque 并不是真正连续的空间,而是由一段段连续的小空间拼接而成的。

实际的 deque 类似于一个动态的二维数组,其底层结构如下所示:

 双端队列底层是一个假想的连续空间,实际是分段连续的,

为了维护其 "整体连续" 、以及随机访问的假象,其重任落在了 deque 的迭代器身上。

因此 deque 的迭代器设计就尤为复杂,如下图所示:

 那 deque 是如何借助其他迭代器维护其假想连续的结构的呢?

3.2 deque的缺陷和使用场景

deque 有点像 vector 和 list ,我们把 vector 和 list 也拉出来进行优缺点的对比再合适不过了:

 那什么场景适合用 deque 呢?

虽然不够极致但是还是有用武之地的:大量头尾插入删除,偶尔随机访问的情况可以使用 deque。

前面说到:在 stack 和 queue 的实现上,是选择 deque 作为底层默认容器的。

为什么选择 deque 作为 stack 和 queue 的底层默认容器?

① stack 是一种后进先出的特殊线性数据结构,因此只要具有 push_back() 和 pop_back() 操作的线性结构,都可以作为 stack 的底层容器,比如 vector 和 list 都可以。

② queue 是先进先出的特殊线性数据结构,只要具有 push_back() 和 pop_front() 操作的线性结构,都可以作为 queue 的底层容器,比如 list 。

但 STL 最终选择用 deque 作为 stack 和 queue 的底层容器,其主要原因是如下:

stack 和 queue 不需要遍历(因此 stack 和 queue 没有迭代器),

只需要在固定的一端或者两端进行操作。
在 stack 中元素增长时,deque 比 vector 的效率高(扩容时不需要搬移大量数据);

queue  中的元素增长时,deque 不仅效率高,而且内存使用率高。

结合了 deque 的优点,而完美的避开了其缺陷。

4. 优先级队列 priority_queue

4.1 priority_queue的介绍

priority_queue的底层就是以前数据结构学的堆:

数据结构与算法⑪(第四章_中)堆的分步构建_GR C的博客-CSDN博客

https://cplusplus.com/reference/queue/priority_queue/

 优先队列是一种容器适配器,根据严格的弱排序标准,

它的第一个元素总是它所包含的元素中最大的。
此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素

(优先队列中位于顶部的元素)。
优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,

queue提供一组特 定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,

其称为优先队列的顶部。
标准容器类 vector 和 deque 满足这些需求。默认情况下,

如果没有为特定的 priority_queue 类实例化指 定容器类,则使用 vector。
需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数 make_heap、push_heap 和 pop_heap 来自动完成此操作。
底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。

容器应该可以通过随机访问迭代器访问,并支持以下操作:

empty():检测容器是否为空
size():返回容器中有效元素个数
front():返回容器中第一个元素的引用
push_back():在容器尾部插入元素
pop_back():删除容器尾部元素

4.2 priority_queue的使用

优先级队列默认使用 vector 作为其底层存储数据的容器,

在 vector 上又使用了堆算法将 vector 中元素构造成堆的结构,因为 priority_queue 就是堆。

所有需要用到堆的地方,都可以考虑使用 priority_queue。

值得注意的是,priority_queue 默认为大根堆。注意下面是反过来的:

优先级队列默认大的优先级高,传的是 less 仿函数,底层是一个大堆;

如果想控制小的优先级高,需手动传 greater 仿函数,其底层是一个小堆。

(仿函数后面讲,实现优先级队列时详细讲解,现在只需要知道如何使用即可)

看看文档使用:

 常用接口函数:

 代码使用:(包的是queue的头文件)

#include <iostream>
#include <queue>
using namespace std;

void test_priority_queue()
{
    priority_queue<int> pq;//默认大堆优先级高

    pq.push(3);
    pq.push(1);
    pq.push(2);
    pq.push(5);
    pq.push(0);
    pq.push(8);
    pq.push(1);

    while (!pq.empty())
    {
        cout << pq.top() << " ";
        pq.pop();
    }
    cout << endl;

    // 迭代器区间初始化:原生指针也是迭代器
    int arr[] = { 3, 2, 7, 6, 0, 4, 5, 9, 8, 1 };
    priority_queue<int> heap(arr, arr+sizeof(arr)/sizeof(arr[0]));

    while (!heap.empty())
    {
        cout << heap.top() << " ";
        heap.pop();
    }
    cout << endl;
}
int main()
{
    //test_stack();
    //test_queue();
    test_priority_queue();

    return 0;
}

 默认是用 vector 存储的,注意这里没有明确指定 less 还是 greater,所以默认为 less。

令该优先级队列以小的优先级高:在定义优先级队列时主动去传 greater<int>

(包一下头文件functional)因为传 greater<int> 是在第三个参数接收的,

如果你想传第三个模板参数,你必须得先传第二个(下面是定义,仔细观察缺省值部分)

代码演示小的优先级高: 

#include <iostream>
#include <queue>
#include <vector> 
#include <functional> // greater和less的头文件
using namespace std;

void test_priority_queue()
{
    priority_queue<int, vector<int>, greater<int>> pq;

    pq.push(3);
    pq.push(1);
    pq.push(2);
    pq.push(5);
    pq.push(0);
    pq.push(8);
    pq.push(1);

    while (!pq.empty())
    {
        cout << pq.top() << " ";
        pq.pop();
    }
    cout << endl;

    // 迭代器区间初始化:原生指针也是迭代器
    int arr[] = { 3, 2, 7, 6, 0, 4, 5, 9, 8, 1 };
    priority_queue<int, vector<int>, greater<int>> heap(arr, arr+sizeof(arr)/sizeof(arr[0]));

    while (!heap.empty())
    {
        cout << heap.top() << " ";
        heap.pop();
    }
    cout << endl;
}
int main()
{
    //test_stack();
    //test_queue();
    test_priority_queue();

    return 0;
}

值得注意的是如果在priority_queue中放自定义类型的数据,

用户需要在自定义类型中提供> 或者< 的重载。(像日期类一样)

4.3 priority_queue解决TopK问题

剑指 Offer II 076. 数组中的第 k 大的数字 - 力扣(LeetCode)

215. 数组中的第K个最大元素 - 力扣(LeetCode)

(这两题是一样的,我们在讲TopK问题的时候也用C语言写过:)

数据结构与算法⑬(第四章_中_续二)堆解决Topk问题+堆的概念选择题_GR C的博客-CSDN博客

难度中等

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

输入:

[3,2,1,5,6,4],

k = 2
输出: 5

示例 2:

输入:

[3,2,3,1,2,4,5,5,6],

k = 4
输出: 4

提示:

1 <= k <= nums.length <= 10^5

-10^4 <= nums[i] <= 10^4

int findKthLargest(int* nums, int numsSize, int k){

}

解析代码:(sort一下也能过,但是时间是O(N*logN))

和以前一样:这里我们需要把整个数组建成一个大堆,然后pop(k-1)次堆顶的元素后堆顶的元素

就是第k大的数。而且我们不用自己写大堆下调算法了,建堆也可以直接用priority_queue:

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        //把整个数组建成一个大堆,(O(N))
        priority_queue<int> MaxHeap(nums.begin(),nums.end());

        while(--k)//然后pop(k-1)次堆顶的元素(log(N*K))
        {
            MaxHeap.pop();
        }
        return MaxHeap.top();//堆顶的元素就是第k大的数
    }
};

看下C语言写的:(调整算法后面模拟实现priority_queue还会用,面试可能也要写)

void Swap(int* px, int* py)
{
    int tmp = *px;
    *px = *py;
    *py = tmp;
}

void justDown(int* arr, int n, int root)//大堆下调
{
    int father = root;
    int child = father * 2 + 1;//默认左孩子大
    while (child < n)
    {
        if (child + 1 < n && arr[child] < arr[child + 1])
        {  // 如果右孩子存在且右孩子比左孩子大
            child++;
        }
        if (arr[father] < arr[child])
        {
            Swap(&arr[father], &arr[child]);

            father = child;
            child = father * 2 + 1;
        }
        else
        {
            break;
        }
    }
}

int findKthLargest(int* nums, int numsSize, int k) {
    for (int i = (numsSize - 1 - 1) / 2;i >= 0;i--) //建堆的for写法
    {
        justDown(nums, numsSize, i);
    }
    // 删除数据
    for (int i = 1;i <= k - 1;i++)
    {
        Swap(&nums[0], &nums[numsSize - i]);
        justDown(nums, numsSize - i, 0);//删除多少个numsize-多少个
    }
    return nums[0];
}

本章完。

下一部分:模拟实现 priority_queue,过程中讲STL六大组件之一的仿函数,然后是反向迭代器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/648623.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

编码规范、Git分支整理

代码命名规范 包命名规范 采用反域名命名规则&#xff0c;全部使用小写字母。一级包名为com&#xff0c;二级包名kl&#xff08;为公司名称&#xff0c;可以简写&#xff09;&#xff0c;三级包名pos&#xff08;根据应用进行命名&#xff09;&#xff0c;四级包名activity或…

芳禾数据CTO李明:数据分类分级与治理驱动下的应用革命丨数据猿专访

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 我们进入数字化时代&#xff0c;数据已经变得比任何时候都更加关键。每天&#xff0c;我们都在生成、处理和存储海量的数据&#xff0c;这些数据在企业决策、市场研究、产品开发等方面扮演着重要的角色。然而&#xff0c;数…

Qt编写精美输入法(历时十年迭代/可换肤/支持Qt4/5/6/win/linux/mac/嵌入式等)

一、前言 大概是从2012年就开始研究用Qt写输入法&#xff0c;因为项目需要&#xff0c;嵌入式板子上&#xff0c;没有对应的输入法&#xff0c;当初使用过很多NVR&#xff0c;里面也是鼠标按下弹出输入法面板进行输入&#xff0c;可以切换数字和字母及中文&#xff0c;于是借鉴…

5大趋势与10大应用场景!未来的智能工厂要这么建...

在经济下行压力、人口红利消失、消费结构升级、疫情冲击等多种因素推动下&#xff0c;制造企业加快转型步伐&#xff0c;工厂正向高效化、智能化、绿色化方向跃迁升级&#xff0c;不断涌现出技术创新、应用领先、成效显著的智能工厂。 近日&#xff0c;中国信息通信研究院发布…

常见的台账在线、可视化数据看板工具

目前已知和常见的一些在线可视化数据看板工具&#xff1a; Trello&#xff1a;Trello 是一种流行且直观的看板工具&#xff0c;可让创建看板、列表和卡片来管理任务和项目。它提供了一个可视化界面&#xff0c;可以在其中跨工作流程的不同阶段拖放卡片。还可以添加截止日期、标…

cesium调用celestrak接口获取卫星数据

celestrak是一家免费开源提供卫星空间数据的非营利性组织 接口调用 import axios from "axios";const BASE_URL "https://celestrak.org";function getTleDataFromExternal(path "") {let uri ${BASE_URL}/NORAD/elements/gp.php?GROUP${…

复习并发编程的基础知识之线程池

并发编程中&#xff0c;线程池是很重要的一块内容。 线程池是一种池化技术&#xff0c;线程池、字符串常量池和数据库链接池都属于池化技术。 使用线程池的好处&#xff1a; 1.提高了线程的利用率&#xff08;想一想&#xff0c;我们不可能每打一个电话&#xff0c;就去买一部手…

Unity编辑器扩展-第三集-添加按钮到组件菜单并且重置组件

第二集链接&#xff1a;Unity编辑器扩展-第二集-按钮排序/分组/放入右键菜单_菌菌巧乐兹的博客-CSDN博客 一、本节目标效果展示 1.把按钮放到组件菜单上 2.做一个类似Reset功能&#xff0c;点一下能改变里面的数据 二、 把按钮放到组件菜单上 如上图&#xff0c;我的的组件名…

echarts 配置相关

echarts更多模板链接 http://chart.majh.top/ 1、echarts.clear()是清空当前实例&#xff0c;会移除实例中所有的组件和图表。 echarts.dispose()是销毁实例&#xff0c;销毁后实例无法再被使用。 this.chart.dispose() this.chart.clear(); // 清空图表2、series虽然是[] 数…

BRC20赛道的刚需基础设施,BrccSwap如何延续新的造富神话?

引言 BRC20代币和去中心化交易所的背景 BRC20代币赛道的刚需SWAP BrccSwap如何延续新的造富神话 结语 引言 随着加密货币市场的不断发展&#xff0c;BRC20代币和去中心化交易所成为了越来越受欢迎的概念。BRC20代币是建立在比特币区块链上的代币&#xff0c;具有高级别的…

一季度亏损47亿,全系降价背后,蔚来能否实现自救?

降价之后&#xff0c;蔚来能否实现自救&#xff1f; 6月12日&#xff0c;蔚来汽车宣布全系车型起售价减 3 万元&#xff1b;新购车首任车主用车权益调整为整车6年或15万公里质保等&#xff1b;免费换电补能不再作为标准用车权益&#xff0c;新用户可灵活选择在家充电或到充换电…

new Vue后整个的流程

文章目录 new Vue后整个的流程Vue.js 创建应用程序流程概述使用 new Vue() 创建Vue 实例流程概述 new Vue后整个的流程 new Vue({el: #app,render: h > h(App),data() {return {message: hello vue}} }).$mount(#app)Vue.js 创建应用程序流程概述 在使用 Vue.js 创建一个应…

Linux:进程管理

进程&#xff1a;为管理程序的运行&#xff0c;操作系统会给每个运行的程序都注册为系统的一个进程&#xff0c;并为每个进程分配一个进程id 查看进程&#xff1a;Linux中可以通过ps命令查看系统中的进程信息&#xff0c;语法&#xff1a; ps [-e -f] -e选项&#xff1a;表示显…

0基础入门---第3章---神经网络(前向传播)

&#x1f31e;欢迎来到深度学习的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f64f;作者水平很有限&#xff0c;如果发现错误&#xff…

退出印度之后,越南制造也有麻烦,苹果摆脱中国制造成幻想

日前媒体报道指苹果在越南的代工厂面临麻烦&#xff0c;由于越南缺乏足够的电力供应&#xff0c;越南的工厂出现断电的问题&#xff0c;工厂生产被迫暂停&#xff0c;最严重的时候连续20天白天无法开工&#xff0c;这对于苹果来说无疑是又一个重大打击。 一、苹果的印度制造计划…

MODNet Background Remover 环境搭建步骤

1、安装 Python 3.8以上 2、安装 CUDA环境 4、下载 MODNet Background Remover 5、解压并进入到 MODNet Background Remover文件夹 6、创建虚拟环境 python -m venv venv7、使用虚拟环境 .\venv\Scripts\activate8、安装依赖包 pip install --upgrade pippip install --upg…

阿里云服务器租用费用_轻量和ECS价格表

2023年阿里云服务器租用费用&#xff0c;阿里云轻量应用服务器2核2G3M带宽轻量服务器一年108元&#xff0c;2核4G4M带宽轻量服务器一年297.98元12个月&#xff0c;阿里云u1服务器2核4G、2核8G、4核8G、8核16G、4核16G、8核64等配置新人3折&#xff0c;云服务器c7、g7和r7均有活…

VMware Horizon 8 运维系列(二)桌面计算机无法访问代理

前言 Horizon 8 在使用即时克隆桌面池,偶尔会出现某个桌面计算机显示“无法访问代理”状态,这时该计算机无法通过客户机来访问。 一、问题描述 1、问题场景 桌面池类型:即时克隆桌面池 2、查看桌面池 查看桌面池,发现有计算机状态为“无法访问代理“,如下图: 二、问题…

回归预测 | MATLAB实现基于BiLSTM-AdaBoost双向长短期记忆网络结合AdaBoost多输入单输出回归预测

回归预测 | MATLAB实现基于BiLSTM-AdaBoost双向长短期记忆网络结合AdaBoost多输入单输出回归预测 目录 回归预测 | MATLAB实现基于BiLSTM-AdaBoost双向长短期记忆网络结合AdaBoost多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现…

全民AI计划:通过langchain给LLM接上落地的大腿

langchain是一个开源项目 github.com/hwchase17/l… 。这个项目在GitHub上已经有45.5K个Star了。此项目由一位叫hwchase17的国外小哥在2022年底发布。 我有理由相信&#xff0c;这个项目是为了对接大语言模型才搞的。 一、企业困境: 如何应用大语言模型 大语言模型(Large La…