首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C++效率掌握之STL库:list底层剖析及迭代器万字详解

C++效率掌握之STL库:list底层剖析及迭代器万字详解

作者头像
DARLING Zero two
发布于 2025-02-25 06:38:13
发布于 2025-02-25 06:38:13
22101
代码可运行
举报
文章被收录于专栏:C语言C语言
运行总次数:1
代码可运行
list 的函数用法与 STL 库中其他的大差不差,本文章难度有些上升,将针对前面忽略的迭代器和模版进行深度解析,真正了解到底什么是迭代器,和迭代器的实现原理

1.学习list底层的重要性

list 底层是双向带头循环链表,在链表的任意位置进行插入和删除操作的时间复杂度都是 O(1)。这是因为链表插入或删除节点只需要修改相邻节点的指针。例如,在实现一个任务调度系统时,任务可能会随时被添加或移除,如果使用 std::list 来存储任务,就可以高效地处理这些操作

为了与库里的 list 进行区分,所有的类和函数都放在自定义的命名空间 bit 进行区分

2.节点模版

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template<class T>
struct list_node
{
	list_node<T>* _next;
	list_node<T>* _prev;
	T _val;

	list_node(const T& val = T())
		:_next(nullptr)
		, _prev(nullptr)
		, _val(val)
	{}
};

经过数据结构的学习我们知道,每个节点都是一个结构体,因为是双向循环链表,所以有 prevnext,使用初始化列表进行常规的初始化

🔥值得注意的是:

  1. 这里使用 struct 而不是 class,是因为 struct 的默认访问权限是 publicclass 的默认访问权限是 private ,虽然用 class+友元 的方式也是可行的,但不如用 struct 来的方便
  2. 构造函数参数部分为 const T& val = T() ,而不是常写的 0 ,是因为 T 无法确定是自定义类型还是内置类型,所以当没有参数传入时就调用各自类型的默认构造函数进行传参

3.迭代器模版及实现

迭代器就是一个桥梁,让容器能通过迭代器实现算法

容器 <–> 迭代器 <–> 算法

根据迭代器的容器底层结构决定的性质,可以大致分为三类:

  1. 单向迭代器(forward iterator):支持运算符重载 ++,常用容器为 forward_listunordered_mapunordered_set
  2. 双向迭代器(bidirectional iterator):支持运算符重载 ++--,常用容器为 listmapset
  3. 随机迭代器(random access iterator):支持运算符重载 ++--+-,常用容器为vectorstringdeque

从下往上为依次包含的关系,比如 list 迭代器为双向,那么既可以用双向也可以用单向不能用随机。通常 std 库里的是随机迭代器

因此这也解释了为什么 vector 迭代器可以使用 std::iterator,也可以使用 vector<T>::iterator。但是 list 迭代器不可以使用 std::iterator,一般使用 list<T>::iterator

3.1 初步实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	void test_list1()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);

		list<int>::iterator it = lt.begin();
		while (it != lt.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
	}

剖析底层代码先从功能入手,通常我们实现迭代器如代码所示

3.1.1 迭代器模版

那么要先实现基本的迭代器模版

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template<class T>
struct _list_iterator
{
	typedef list_node<T> Node;
	Node* _node;

	_list_iterator(Node* node)
		:_node(node)
	{}
};

实现基本的构造函数,_node 是一个指向 Node 类型对象的指针,它用于存储当前迭代器所指向的链表节点

实现 push_back 往链表中放置数据,实现方式还是和双线链表中一样,可以去数据结构专题中回顾

3.1.2 push_back

传送门:【初阶数据结构】逆流的回环链桥:双链表

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void push_back(const T& x)
{
	Node* tail = _head->_prev;
	Node* newnode = new Node(x);
	tail->_next = newnode;
	newnode->_prev = tail;
	newnode->_next = _head;
	_head->_prev = newnode;
	//insert(end(), x);
}
3.1.3 begin和end

接下来实现 begin()end() ,还是比较简单的,这里直接展示放在 list 模版中的效果,后续就只单独列出实现功能的代码了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template<class T>
class list
{
	typedef list_node<T> Node;
public:
	typedef _list_iterator<T> iterator;
	iterator begin() const
	{
		return _head->_next;
	}

	iterator end() const
	{
		return _head;
	}

	list()
	{
		_head = new Node;
		_head->_prev = _head;
		_head->_next = _head;
	}

private:
	Node* _head;
};

list 模版有一个头节点,作为哨兵位,实现了双链表的构造函数,看似简单的代码,实则隐藏了很多的细节

🔥值得注意的是:

  1. begin()end() 返回的是 iterator 类型,C++ 标准库提供了大量基于迭代器的通用算法(如 std::findstd::sortstd::for_each 等)。当自定义容器的 begin() 函数返回迭代器时,这些通用算法可以直接应用到自定义容器上,实现代码的复用
  2. iterator_list_iterator<T> 模版的重命名,更符合使用习惯
  3. begin()end() 返回的值看似是 Node* 类型,实际上单参数的函数支持隐式转换Node* 隐式转换为 iterator 类型,return _head->_next 其实是 return iterator(_head->_next)
  4. begin()end() 函数都用 const 修饰,使函数更具普遍性,包括 const 变量的情况,普通类型调用也是权限的缩小,两种情况共用一个函数
3.1.4 *解引用运算符重载
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
T& operator*()
{
	return _node->_val;
}

这里 _node 应该是一个指向链表节点的指针,_val 是链表节点中存储的数据成员。该函数返回节点数据 _val

3.1.5 ++运算符重载
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//前置
_list_iterator<T>& operator++()
{
	_node = _node->_next;
	return *this;
}
//后置
_list_iterator<T> operator++(int)
{
	self temp(*this);
	_node = _node->_next;
	return temp;
}

为了区分前置后置,前置 ++ 和后置 ++ 虽然是运算符重载,但是形式上也构成函数重载,后置 ++ 增加这个 int 参数不是为了接受具体的值,仅仅是占位,跟前置 ++ 构成重载, int 这个位置传任何值都可以,实际调用的时候前置 ++ 和后置 ++ 可能分别为 operator++()operator++(0) ,括号内的值是随机的

🔥值得注意的是: 前置 ++ 返回的对象还存在,所以可以用引用,而后置 ++ 返回的对象是个临时对象,所以不能返回引用

3.1.6 !=运算符重载
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
bool operator!=(const _list_iterator<T>& it) const
{
	return _node != it._node;
}

该函数通过比较当前对象的 _node 成员变量和传入对象 it_node 成员变量来判断两个对象是否不相等。如果 _nodeit._node 不相等,则返回 true,表示两个对象不相等;否则返回 false,表示两个对象相等

🔥值得注意的是: 调用 end() 时传值返回,具有常性,所以 != 重载要参数加 const

以上就已经基本实现了迭代器,能够跑起来实现正常功能,范围 for 的底层也是迭代器,所以也能够使用了,但是还有很多需要完善的

3.2 再完善实现

通常迭代器分为 iteratorconst_iterator

那么我们难道再写一个来实现吗,显然是不符合编程范式的,代码就显得太冗余了

有人或许会想到这么写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef _list_iterator<T> iterator;
typedef const _list_const_iterator<T> const_iterator;

这样看起或许可行,但是我们要思考 const 的使用

举个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const T* ptr1;
T* const ptr2;

这两段代码的含义分别为:不可以修改指向对象的内容不可以修改指向别的对象

显然 typedef const _list_const_iterator<T> const_iterator 是第一种 const 的使用,在 ++ 运算符重载中有 _node = _node->_next ,需要通过这段代码来到下一个节点,按照我们这样加 const 就和这段代码冲突了。我们只是不想修改其内容,而不是无法跳转节点

所以发明 STL库的人真是个天才,想到了巧妙的办法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
迭代器模版
template<class T, class Ref>
......
list模版
typedef _list_iterator<T, T&> iterator;
typedef _list_iterator<T, const T&> const_iterator;

iteratorconst_iterator 的区别就在于 * 运算符重载返回的值是否能够被修改,因此增加一个新的模版参数,当使用对应的迭代器就会调用相应的模版

3.3 最终完善实现

在查看STL库里的list底层代码时,会发现实际上的迭代器代码有三个参数,单纯去看是很难发现为什么要有第三个参数的,必须要结合实际的应用场景

举个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct A
{
	A(int a1 = 0, int a2 = 0)
		:_a1(a1)
		,_a2(a2)
	{}

	int _a1;
	int _a2;
};

void test_list2()
{
	list<A> lt;
	lt.push_back(A(1, 1));
	lt.push_back(A(2, 2));
	lt.push_back(A(3, 3));
	lt.push_back(A(4, 4));
	list<A>::iterator it = lt.begin();
	while (it != lt.end())
	{
		/*cout << (*it)._a1 << " " << (*it)._a2 << endl;*/
		cout << it->_a1 << " " << it->_a2 << endl;
		++it;
	}
	cout << endl;
}

假设有个类A,需要遍历输出,通常我们会写成 cout << (*it)._a1 << " " << (*it)._a2 << endl ,但是这并不符合编程范式

可是为什么写成 cout << it->_a1 << " " << it->_a2 << endl 也能通过?

严格来说,应该写成 it->->_a2,才符合语法,因为运算符重载要求可读性,所以编译器特殊处理,省略一个 ->

3.3.1 ->运算符重载

所以我们可以写出 -> 运算符重载

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Ptr operator->()
{
	return &(_node->_val);
}

同样的道理,为了实现iteratorconst_iterator两种迭代器,再增加一个模版参数,同时因为模版参数有点过多,导致类型太长了,对类型也进行重命名

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
迭代器模版
template<class T, class Ref, class Ptr>;
typedef _list_iterator<T, Ref, Ptr> self;
......
list模版
typedef _list_iterator<T, T&, T*> iterator;
typedef _list_iterator<T, const T&, const T*> const_iterator;

4.其余list函数功能实现

4.1 析构函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
~list()
{
	clear();
	delete _head;
	_head = nullptr;
}

4.2 拷贝构造函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
list(const list<T>& lt)
{
	_head = new Node;
	_head->_prev = _head;
	_head->_next = _head;
	//万一拷贝的是string、vector等代价就大了,所以用&
	for (auto& x : lt)
	{
		push_back(x);
	}
}

4.3 =运算符重载

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
list<T>& operator=(list<T> lt)
{
	swap(lt);
	return *this;
}

4.4 swap

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void swap(list<T>& lt)
{
	std::swap(_head, lt._head);
}

4.5 clear

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void clear()
{
	iterator it = begin();
	while (it != end())
	{
		it = erase(it);
	}
}

4.6 insert

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
iterator insert(iterator pos, const T& x)
{
	Node* cur = pos._node;
	Node* prev = cur->_prev;
	Node* newnode = new Node(x);

	prev->_next = newnode;
	newnode->_next = cur;
	cur->_prev = newnode;
	newnode->_prev = prev;

	return newnode;
}

4.7 erase

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
iterator erase(iterator pos)
{
	assert(pos != end());

	Node* cur = pos._node;
	Node* prev = cur->_prev;
	Node* next = cur->_next;

	prev->_next = next;
	next->_prev = prev;

	delete cur;
	return next;
}

4.8 push_front、pop_back、pop_front

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void push_front(const T& x)
{
	insert(begin(), x);
}

void pop_back()
{
	erase(--end());
}

void pop_front()
{
	erase(begin());
}

4.9 size

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
size_t size()
{
	size_t sz = 0;
	iterator it = begin();
	while (it != end())
	{
		++sz;
		++it;
	}
	return sz;
}

4.10 --运算符重载

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//前置
self& operator--()
{
	_node = _node->_prev;
	return *this;
}

//后置
self operator--(int)
{
	self temp(*this);
	_node = _node->_prev;
	return temp;
}

4.11 ==运算符重载

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
bool operator==(const self& it) const
{
	return _node == it._node;
}

5.list模拟实现代码及测试代码展示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma once
#include <iostream>
using namespace std;
#include <assert.h>

namespace bit
{
	//节点模版
	template<class T>
	struct list_node
	{
		list_node<T>* _next;
		list_node<T>* _prev;
		T _val;

		list_node(const T& val = T())
			:_next(nullptr)
			, _prev(nullptr)
			, _val(val)
		{}
	};
	//迭代器模版
	template<class T, class Ref, class Ptr>
	struct _list_iterator
	{
		typedef list_node<T> Node;
		typedef _list_iterator<T, Ref, Ptr> self;
		Node* _node;

		_list_iterator(Node* node)
			:_node(node)
		{}

		//const T& operator*()就可以实现const_iterator
		Ref& operator*()
		{
			return _node->_val;
		}
		
		Ptr operator->()
		{
			return &(_node->_val);
		}
		//前置
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}

		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		//后置
		self operator++(int)
		{
			self temp(*this);
			_node = _node->_next;
			return temp;
		}

		self operator--(int)
		{
			self temp(*this);
			_node = _node->_prev;
			return temp;
		}

		bool operator!=(const self& it) const
		{
			return _node != it._node;
		}

		bool operator==(const self& it) const
		{
			return _node == it._node;
		}
	};
	//list类模版
	template<class T>
	class list
	{
		typedef list_node<T> Node;
	public:
		typedef _list_iterator<T, T&, T*> iterator;
		typedef _list_iterator<T, const T&, const T*> const_iterator;
		//typedef const _list_const_iterator<T> const_iterator;
		//不能这样写,因为++没法next,就没法遍历了
		iterator begin() const
		{
			return iterator(_head->_next);
			//单参数的函数支持隐式转换
		}

		iterator end() const
		{
			return _head;
		}
		
		list()
		{
			_head = new Node;
			_head->_prev = _head;
			_head->_next = _head;
		}

		list(const list<T>& lt)
		{
			_head = new Node;
			_head->_prev = _head;
			_head->_next = _head;
			//万一拷贝的是string、vector等代价就大了,所以用&
			for (auto& x : lt)
			{
				push_back(x);
			}
		}

		void swap(list<T>& lt)
		{
			std::swap(_head, lt._head);
		}

		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}
		
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}

		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}

		void push_back(const T& x)
		{
			/*Node* tail = _head->_prev;
			Node* newnode = new Node(x);
			tail->_next = newnode;
			newnode->_prev = tail;
			newnode->_next = _head;
			_head->_prev = newnode;*/
			insert(end(), x);
		}

		void push_front(const T& x)
		{
			insert(begin(), x);
		}

		void pop_back()
		{
			erase(--end());
		}

		void pop_front()
		{
			erase(begin());
		}

		iterator insert(iterator pos, const T& x)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* newnode = new Node(x);

			prev->_next = newnode;
			newnode->_next = cur;
			cur->_prev = newnode;
			newnode->_prev = prev;

			return newnode;
		}

		iterator erase(iterator pos)
		{
			assert(pos != end());

			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;

			prev->_next = next;
			next->_prev = prev;

			delete cur;
			return next;
		}

		size_t size()
		{
			size_t sz = 0;
			iterator it = begin();
			while (it != end())
			{
				++sz;
				++it;
			}
			return sz;
		}
	private:
		Node* _head;
	};

	void test_list1()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);

		list<int>::iterator it = lt.begin();
		//调用end的函数时传值返回,具有常性,所以!=重载要参数加const
		while (it != lt.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	struct A
	{
		A(int a1 = 0, int a2 = 0)
			:_a1(a1)
			,_a2(a2)
		{}

		int _a1;
		int _a2;
	};

	void test_list2()
	{
		list<A> lt;
		lt.push_back(A(1, 1));
		lt.push_back(A(2, 2));
		lt.push_back(A(3, 3));
		lt.push_back(A(4, 4));
		//严格来说,应该写成it->->_a2,才符合语法
		//因为运算符重载要求可读性,所以编译器特殊处理,省略一个->
		list<A>::iterator it = lt.begin();
		while (it != lt.end())
		{
			/*cout << (*it)._a1 << " " << (*it)._a2 << endl;*/
			cout << it->_a1 << " " << it->_a2 << endl;
			++it;
		}
		cout << endl;
	}

	void test_list3()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_front(5);
		lt.push_front(6);
		lt.push_front(7);
		lt.push_front(8);

		lt.pop_front();
		lt.pop_back();

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
		
		lt.clear();
		lt.push_back(10);
		lt.push_back(20);
		lt.push_back(30);
		lt.push_back(40);
		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
		cout << lt.size() << endl;
	}

	void test_list4()
	{
		list<int> lt1;
		lt1.push_back(1);
		lt1.push_back(2);
		lt1.push_back(3);
		lt1.push_back(4);
		for (auto e : lt1)
		{
			cout << e << " ";
		}
		cout << endl;
		list<int> lt2;
		lt2 = lt1;
		for (auto e : lt2)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}

希望读者们多多三连支持

小编会继续更新

你们的鼓励就是我前进的动力!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-02-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
R语言BUGS/JAGS贝叶斯分析: 马尔科夫链蒙特卡洛方法(MCMC)采样
在许多情况下,我们没有足够的计算能力评估空间中所有n维像素的后验概率 。在这些情况下,我们倾向于利用称为Markov-Chain Monte Carlo 算法的程序 。此方法使用参数空间中的随机跳跃来(最终)确定后验分布。MCMC的关键如下:
拓端
2020/11/30
2.3K0
R语言BUGS/JAGS贝叶斯分析: 马尔科夫链蒙特卡洛方法(MCMC)采样
R语言BUGS/JAGS贝叶斯分析: 马尔科夫链蒙特卡洛方法(MCMC)采样|附代码数据
在许多情况下,我们没有足够的计算能力评估空间中所有n维像素的后验概率 。在这些情况下,我们倾向于利用称为Markov-Chain Monte Carlo 算法的程序 。此方法使用参数空间中的随机跳跃来(最终)确定后验分布(点击文末“阅读原文”获取完整代码数据)。
拓端
2022/10/28
1.7K0
R语言Gibbs抽样的贝叶斯简单线性回归仿真分析|附代码数据
最近我们被客户要求撰写关于Gibbs抽样的研究报告,包括一些图形和统计输出。 贝叶斯分析的许多介绍都使用了相对简单的教学实例(例如,根据伯努利数据给出成功概率的推理)。虽然这很好地介绍了贝叶斯原理,但是这些原则的扩展并不是直截了当的
拓端
2022/12/21
1K0
R语言MCMC:Metropolis-Hastings采样用于回归的贝叶斯估计
如果需要计算有复杂后验pdf p(θ| y)的随机变量θ的函数f(θ)的平均值或期望值。
拓端
2021/01/29
1.3K0
R语言MCMC:Metropolis-Hastings采样用于回归的贝叶斯估计
贝叶斯推断:Metropolis-Hastings 采样
前面一篇文章贝叶斯统计:初学指南介绍了最简单的 Metropolis 采样方法,本文将介绍另一种采样 Metropolis-Hastings ,并且会对前文介绍的例子给出证明,为什么 Metropolis 采样work。
zhuanxu
2018/09/07
1.3K0
MCMC原理解析(马尔科夫链蒙特卡洛方法)
马尔科夫链蒙特卡洛方法(Markov Chain Monte Carlo),简称MCMC,MCMC算法的核心思想是我们已知一个概率密度函数,需要从这个概率分布中采样,来分析这个分布的一些统计特性,然而这个这个函数非常之复杂,怎么去采样?这时,就可以借助MCMC的思想。
种花家的奋斗兔
2020/11/13
2.9K0
MCMC原理解析(马尔科夫链蒙特卡洛方法)
简单易学的机器学习算法——马尔可夫链蒙特卡罗方法MCMC
对于一般的分布的采样,在很多的编程语言中都有实现,如最基本的满足均匀分布的随机数,但是对于复杂的分布,要想对其采样,却没有实现好的函数,在这里,可以使用马尔可夫链蒙特卡罗(Markov Chain Monte Carlo, MCMC)方法,其中Metropolis-Hastings采样和Gibbs采样是MCMC中使用较为广泛的两种形式。 MCMC的基础理论为马尔可夫过程,在MCMC算法中,为了在一个指定的分布上采样,根据马尔可夫过程,首先从任一状态出发,模拟马尔可夫过程,不断进行状态转移,最终收敛到平稳分布
felixzhao
2018/03/20
1.8K0
简单易学的机器学习算法——马尔可夫链蒙特卡罗方法MCMC
R语言蒙特卡洛方法:方差分量的Metropolis Hastings(M-H)、吉布斯Gibbs采样比较分析
蒙特卡洛方法利用随机数从概率分布P(x)中生成样本,并从该分布中评估期望值,该期望值通常很复杂,不能用精确方法评估。在贝叶斯推理中,P(x)通常是定义在一组随机变量上的联合后验分布。然而,从这个分布中获得独立样本并不容易,这取决于取样空间的维度。因此,我们需要借助更复杂的蒙特卡洛方法来帮助简化这个问题;例如,重要性抽样、拒绝抽样、吉布斯抽样和Metropolis Hastings抽样。这些方法通常涉及从建议密度Q(x)中取样,以代替P(x)。
拓端
2021/07/16
1.2K0
R语言蒙特卡洛方法:方差分量的Metropolis Hastings(M-H)、吉布斯Gibbs采样比较分析
R语言JAGS贝叶斯回归模型分析博士生延期毕业完成论文时间|附代码数据
本文为读者提供了如何进行贝叶斯回归的基本教程。包括完成导入数据文件、探索汇总统计和回归分析
拓端
2022/12/23
9360
R语言使用Metropolis-Hastings采样算法自适应贝叶斯估计与可视化
1)定义模型(即概率先验)。在此示例中,让我们构建一个简单的线性回归模型(对数)。
拓端
2023/09/25
3370
R语言使用Metropolis-Hastings采样算法自适应贝叶斯估计与可视化
【深度干货】专知主题链路知识推荐#7-机器学习中似懂非懂的马尔科夫链蒙特卡洛采样(MCMC)入门教程02
【导读】主题链路知识是我们专知的核心功能之一,为用户提供AI领域系统性的知识学习服务,一站式学习人工智能的知识,包含人工智能( 机器学习、自然语言处理、计算机视觉等)、大数据、编程语言、系统架构。使用请访问专知 进行主题搜索查看 - 桌面电脑访问www.zhuanzhi.ai, 手机端访问www.zhuanzhi.ai 或关注微信公众号后台回复" 专知"进入专知,搜索主题查看。今天给大家继续介绍我们独家整理的机器学习——马尔科夫链蒙特卡洛采样(MCMC)方法。 上一次我们详细介绍了机器学习中似懂非懂的马尔
WZEARW
2018/04/08
4.1K1
【深度干货】专知主题链路知识推荐#7-机器学习中似懂非懂的马尔科夫链蒙特卡洛采样(MCMC)入门教程02
R语言贝叶斯Metropolis-Hastings采样 MCMC算法理解和应用可视化案例
例如,使用的rstan包采用了一个Hamiltonian Monte Carlo算法。用于贝叶斯建模的另一个rjags包采用了Gibbs sampling算法。尽管细节有所不同,但这两种算法都是基于基本的Metropolis-Hastings算法的变体。
拓端
2023/12/14
3200
R语言贝叶斯Metropolis-Hastings采样 MCMC算法理解和应用可视化案例
R语言MCMC:Metropolis-Hastings采样用于回归的贝叶斯估计|附代码数据
如果需要计算有复杂后验pdf p(θ| y)的随机变量θ的函数f(θ)的平均值或期望值。
拓端
2023/04/28
4080
R语言实现MCMC中的Metropolis–Hastings算法与吉布斯采样
作为第一步,我们创建一些测试数据,用于拟合我们的模型。让我们假设预测变量和响应变量之间存在线性关系,因此我们采用线性模型并添加一些噪声。
拓端
2020/11/30
1.6K0
R语言实现MCMC中的Metropolis–Hastings算法与吉布斯采样
R语言MCMC:Metropolis-Hastings采样用于回归的贝叶斯估计|附代码数据
如果需要计算有复杂后验pdf p(θ| y)的随机变量θ的函数f(θ)的平均值或期望值。
拓端
2022/10/27
8350
马尔可夫链蒙特卡洛(MCMC)算法
在之前的推送中我们了解到什么是马尔可夫链(Markov Chain)。下面我们来介绍一下马尔可夫链蒙特卡洛算法(Markov Chain Monte Carlo), 在此之前,我们需要回顾一下马尔可夫
量化投资与机器学习微信公众号
2018/01/29
3.4K0
R语言实现MCMC中的Metropolis–Hastings算法与吉布斯采样|附代码数据
第一步,我们创建一些测试数据,用来拟合我们的模型。我们假设预测变量和因变量之间存在线性关系,所以我们用线性模型并添加一些噪音。
拓端
2023/08/15
3690
MATLAB随机波动率SV、GARCH用MCMC马尔可夫链蒙特卡罗方法分析汇率时间序列|附代码数据
最近我们被客户要求撰写关于波动率的研究报告。 波动率是一个重要的概念,在金融和交易中有许多应用。它是期权定价的基础。波动率还可以让您确定资产配置并计算投资组合的风险价值 (VaR)。
拓端
2022/11/16
7610
R语言coda贝叶斯MCMC Metropolis-Hastings采样链分析和收敛诊断可视化|附代码数据
最近我们被客户要求撰写关于MCMC Metropolis-Hastings采样的研究报告,包括一些图形和统计输出。
拓端
2023/09/06
4700
R语言用贝叶斯线性回归、贝叶斯模型平均 (BMA)来预测工人工资|附代码数据
在本文中,贝叶斯模型提供了变量选择技术,确保变量选择的可靠性。对社会经济因素如何影响收入和工资的研究为应用这些技术提供了充分的机会,同时也为从性别歧视到高等教育的好处等主题提供了洞察力
拓端
2023/02/21
8610
推荐阅读
R语言BUGS/JAGS贝叶斯分析: 马尔科夫链蒙特卡洛方法(MCMC)采样
2.3K0
R语言BUGS/JAGS贝叶斯分析: 马尔科夫链蒙特卡洛方法(MCMC)采样|附代码数据
1.7K0
R语言Gibbs抽样的贝叶斯简单线性回归仿真分析|附代码数据
1K0
R语言MCMC:Metropolis-Hastings采样用于回归的贝叶斯估计
1.3K0
贝叶斯推断:Metropolis-Hastings 采样
1.3K0
MCMC原理解析(马尔科夫链蒙特卡洛方法)
2.9K0
简单易学的机器学习算法——马尔可夫链蒙特卡罗方法MCMC
1.8K0
R语言蒙特卡洛方法:方差分量的Metropolis Hastings(M-H)、吉布斯Gibbs采样比较分析
1.2K0
R语言JAGS贝叶斯回归模型分析博士生延期毕业完成论文时间|附代码数据
9360
R语言使用Metropolis-Hastings采样算法自适应贝叶斯估计与可视化
3370
【深度干货】专知主题链路知识推荐#7-机器学习中似懂非懂的马尔科夫链蒙特卡洛采样(MCMC)入门教程02
4.1K1
R语言贝叶斯Metropolis-Hastings采样 MCMC算法理解和应用可视化案例
3200
R语言MCMC:Metropolis-Hastings采样用于回归的贝叶斯估计|附代码数据
4080
R语言实现MCMC中的Metropolis–Hastings算法与吉布斯采样
1.6K0
R语言MCMC:Metropolis-Hastings采样用于回归的贝叶斯估计|附代码数据
8350
马尔可夫链蒙特卡洛(MCMC)算法
3.4K0
R语言实现MCMC中的Metropolis–Hastings算法与吉布斯采样|附代码数据
3690
MATLAB随机波动率SV、GARCH用MCMC马尔可夫链蒙特卡罗方法分析汇率时间序列|附代码数据
7610
R语言coda贝叶斯MCMC Metropolis-Hastings采样链分析和收敛诊断可视化|附代码数据
4700
R语言用贝叶斯线性回归、贝叶斯模型平均 (BMA)来预测工人工资|附代码数据
8610
相关推荐
R语言BUGS/JAGS贝叶斯分析: 马尔科夫链蒙特卡洛方法(MCMC)采样
更多 >
LV.0
这个人很懒,什么都没有留下~
目录
  • list 的函数用法与 STL 库中其他的大差不差,本文章难度有些上升,将针对前面忽略的迭代器和模版进行深度解析,真正了解到底什么是迭代器,和迭代器的实现原理
  • 1.学习list底层的重要性
  • 2.节点模版
  • 3.迭代器模版及实现
    • 3.1 初步实现
      • 3.1.1 迭代器模版
      • 3.1.2 push_back
      • 3.1.3 begin和end
      • 3.1.4 *解引用运算符重载
      • 3.1.5 ++运算符重载
      • 3.1.6 !=运算符重载
    • 3.2 再完善实现
    • 3.3 最终完善实现
      • 3.3.1 ->运算符重载
  • 4.其余list函数功能实现
    • 4.1 析构函数
    • 4.2 拷贝构造函数
    • 4.3 =运算符重载
    • 4.4 swap
    • 4.5 clear
    • 4.6 insert
    • 4.7 erase
    • 4.8 push_front、pop_back、pop_front
    • 4.9 size
    • 4.10 --运算符重载
    • 4.11 ==运算符重载
  • 5.list模拟实现代码及测试代码展示
  • 希望读者们多多三连支持
  • 小编会继续更新
  • 你们的鼓励就是我前进的动力!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档