list使用与模拟实现

news2024/12/24 21:56:21

目录

list使用

reverse

sort

 unique

splice

list模拟实现

类与成员函数声明

节点类型的定义

非const迭代器的实现

list成员函数

构造函数

尾插

头插

头删

尾删

任意位置插入

 任意位置删除

清空数据

析构函数

拷贝构造函数

赋值重载函数

const迭代器的设计

终极版迭代器的实现

迭代器扩充小知识


list使用

list的诸多使用与前面博客讲解的string仍然类似,我们此处只讲解比较特殊的接口函数

list的底层是带头双向循环链表,在我的数据结构专栏博客 带头双向循环链表_CSDN博客 已经讲解过了,重点是体会带头双向循环链表与顺序表的不同,尤其是某个位置插入与删除数据的效率!

reverse

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

	for (auto e : lt)
	{
		cout << e << " "; //1 2 3 4 
	}
	cout << endl;

	lt.reverse(); //逆置链表

	for (auto e : lt)
	{
		cout << e << " "; //4 3 2 1 
	}
	cout << endl;
}

sort

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

	for (auto e : lt)
	{
		cout << e << " "; //2 3 4 1 
	}
	cout << endl;

	//默认是升序 < less
	//lt.sort(); 

	//降序: > greater
	greater<int> gt;
	lt.sort(gt);

	lt.sort(greater<int>()); //匿名对象

	for (auto e : lt)
	{
		cout << e << " "; //4 3 2 1
	}
	cout << endl;
}

注意: list的排序无法使用算法库中的sort,主要原因是list不支持随机访问的迭代器

迭代器类型按性质或者底层实现分为三种:

1.单向:只支持++, 单链表/哈希表
2.双向:++与--都支持,双向链表/红黑树(map和set)
3.随机:++/--/+/- vector/string/deque

注意: 2是兼容1的,3是兼容2的(本质是继承关系)

 unique

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

	for (auto e : lt)
	{
		cout << e << " "; //4 1 1 2 5 5 3
	}
	cout << endl;

	lt.sort();
	lt.unique(); //把相邻的重复去掉, 配合sort可以达到去重的功能

	for (auto e : lt)
	{
		cout << e << " "; //1 2 3 4 5
	}
	cout << endl;
}

splice

void test_list5()
{
	list<int> lt1;
	lt1.push_back(1);
	lt1.push_back(2);
	lt1.push_back(3);
	lt1.push_back(4);

	list<int> lt2;
	lt2.push_back(10);
	lt2.push_back(20);
	lt2.push_back(30);
	lt2.push_back(40);

	list<int>::iterator it = lt1.begin();
	++it;
	lt1.splice(it, lt2); //将lt2嫁接到lt1第2个位置之后, lt2就为空了!
	for (auto e : lt1)
	{
		cout << e << " "; //1 10 20 30 40 2 3 4
	}
	cout << endl;

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

	list<int> lt2;
	lt2.push_back(10);
	lt2.push_back(20);
	lt2.push_back(30);
	lt2.push_back(40);

	lt1.splice(lt1.begin(), lt2, lt2.begin()); //将lt2的第一个节点接到lt1开始
	
	for (auto e : lt1)
	{
		cout << e << " "; //10 1 2 3 4 
	}
	cout << endl;

	for (auto e : lt2)
	{
		cout << e << " "; //20 30 40
	}
	cout << endl;
}
void test_list5()
{
	list<int> lt1;
	lt1.push_back(1);
	lt1.push_back(2);
	lt1.push_back(3);
	lt1.push_back(4);

	list<int> lt2;
	lt2.push_back(10);
	lt2.push_back(20);
	lt2.push_back(30);
	lt2.push_back(40);

	lt1.splice(lt1.begin(), lt2, lt2.begin(), lt2.end()); //将lt2的全部接到lt1开始

	for (auto e : lt1)
	{
		cout << e << " "; //10 20 30 40 1 2 3 4
	}
	cout << endl;

	for (auto e : lt2)
	{
		cout << e << " "; //空
	}
	cout << endl;
}

list模拟实现

关于带头双向链表的结构与实现可以直接看我之前的博客: 带头双向循环链表-CSDN博客

类与成员函数声明

namespace dck
{
	//每个节点的类型
	template <class T>
	struct list_node
	{
		T _data; //数据域
		list_node<T>* _next; //前驱指针
		list_node<T>* _prev; //后继指针
		list_node(const T& x = T()); //构造函数
	};

	//非const迭代器
	template <class T>
	struct __list_iterator //前加_表示内部的实现
	{
		typedef list_node<T> Node;
		Node* _node;

		//构造函数
		__list_iterator(Node* node);

		//迭代器++(前置++)
		typedef __list_iterator<T> self;
		self& operator++();
		//迭代器--(前置--)
		self& operator--();
		//迭代器++(后置++)
		self operator++(int);
		//迭代器--(后置--)
		self operator--(int);

		//迭代器解引用
		T& operator*();
		T* operator->();

		//两个迭代器进行比较
		bool operator!=(const self& s);
		bool operator ==(const self& s);
	};

	//list的类型
	template <class T>
	class list
	{
		typedef list_node<T> Node;
	public:
		void empty_init(); //空初始化
		list(); //构造函数
		void push_back(const T& x); //尾插
		void push_front(const T& x); //头插
		void pop_front(); //头删
		void pop_back(); //尾删
		iterator insert(iterator pos, const T& x); //任意位置插入
		iterator erase(iterator pos); //任意位置删除
		iterator begin(); //起始位置迭代器
		iterator end(); //结束位置迭代器
		void clear(); //清空数据
		~list(); //析构函数
		list(const list<T>& lt); //拷贝构造函数
		list<T>& operator=(const list<T>& lt); //赋值重载函数传统写法
		void swap(list<T>& lt); //交换两个list, 赋值重载函数现代写法要调用swap函数
		list<T>& operator=(list<T> lt); //赋值重载函数现代写法

	private:
		Node* _head;
        size_t size; //记录链表中节点的个数,降低时间复杂度
	};
}

节点类型的定义

//每个节点的类型
template <class T>
struct list_node
{
	T _data;
	list_node<T>* _next;
	list_node<T>* _prev;

	list_node(const T& x = T()) 
		:_data(x)
		,_next(nullptr)
		,_prev(nullptr)
	{}
};

非const迭代器的实现

之前讲解的string与vector的迭代器都是原生指针,而list的迭代器不是原生指针,主要原因是因为list的底层是双向链表,如果用原生指针++,是无法到下一个节点的;直接解引用拿到的也不是具体的数据,而是整个节点对象;而迭代器的访问与遍历方式都是类似的,都是++, 解引用,判断!=, 所以我们只需要把list的迭代器设计成类,在类中对原生指针做封装

//迭代器的实现 --- 封装屏蔽了底层差异和细节,提供了统一的访问遍历修改方式!
template <class T>
struct __list_iterator //前加_表示内部的实现
{
	typedef list_node<T> Node;
	Node* _node;

	//构造函数
	__list_iterator(Node* node)
		:_node(node)
	{}

	//迭代器++(前置++)
	typedef __list_iterator<T> self;
	self& operator++()
	{
		_node = _node->_next;
		return *this;
	}

	//迭代器--(前置--)
	self& operator--()
	{
		_node = _node->_prev;
		return *this;
	}

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

	//迭代器--(后置--)
	self operator--(int)
	{
		self tmp(*this);
		_node = _node->_prev;
		return tmp;
	}

	//迭代器解引用
	T& operator*()
	{
		return _node->_data;
	}

	T* operator->()
	{
		return &_node->_data;
	}

	//两个迭代器进行比较
	bool operator!=(const self& s)
	{
		return _node != s._node;
	}

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

注意: 当list中存放的是自定义类型的对象时,使用->解引用时,写法如下:

class AA
{
public:
	AA(int aa1 = 1, int aa2 = 1)
		:_a1(aa1)
		,_a2(aa2)
	{}
		
	int _a1;
	int _a2;
};

void test_list()
{
	list<AA> lt1;
	lt1.push_back(AA(1, 2));
	lt1.push_back(AA(3, 4));
	lt1.push_back(AA(5, 6));
	list<AA>::iterator it = lt1.begin();
	while (it != lt1.end())
	{
		//显式应该这么写,因为operator->()拿到的是原生指针,还要再次->解引用拿到数据
		cout << it.operator->()->_a1 << " " << it.operator->()->_a2 << endl;
		//本来应该 it->->_a1, 但是可读性不好,因此编译器特殊处理, 省略了一个->
		cout << it->_a1 << " " << it->_a2 << endl;
		++it;
	}
	cout << endl;
}

list成员函数

构造函数
//空初始化, 后续代码可能会用到,因此单独写出来
void empty_init()
{
	_head = new Node;
	_head->_next = _head;
	_head->_prev = _head;
	_size = 0;
}

//构造函数
list()
{
	empty_init();
}
尾插
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;
	//_size++;

    //调用insert函数
	insert(end(), x); 
}
头插
//头插
void push_front(const T& x)
{
	insert(begin(), x);
}
头删
//头删
void pop_front()
{
	erase(begin());
}
尾删
//尾删
void pop_back()
{
	erase(--end());
}
任意位置插入
//insert
//在pos位置之前插入
//list的迭代器不存在失效的问题,因为不涉及扩容
//参考库的实现,还是给insert带上返回值
iterator insert(iterator pos, const T& x)
{
	Node* cur = pos._node; //当前节点指针
	Node* prev = cur->_prev; //前一个节点指针
	Node* newnode = new Node(x); //开辟新节点

	//链接
	prev->_next = newnode;
	newnode->_prev = prev;
	newnode->_next = cur;
	cur->_prev = newnode;

	++_size;
	return iterator(newnode); //返回新插入节点位置的迭代器
}
 任意位置删除
//erase之后,迭代器pos失效,因为当前节点已经被释放了!
//因此我们给erase带上返回值
iterator erase(iterator pos)
{
	Node* cur = pos._node; //当前节点指针
	Node* prev = cur->_prev; //前一个节点指针
	Node* next = cur->_next; //后一个节点指针

	delete cur; //释放当前节点

	//链接前一个节点和后一个节点
	prev->_next = next; 
	next->_prev = prev;

	--_size;
	return iterator(next); //返回释放节点的下一个位置
}

迭代器接口

iterator begin()
{
	//return iterator(_head->_next);
	return _head->_next;  //单参数的构造函数支持隐式类型转化
}

iterator end()
{
	//return iterator(_head);
	return _head;  //单参数的构造函数支持隐式类型转化
}
清空数据
//清空数据(不清除带哨兵位的头节点)
void clear()
{
	iterator it = begin();
	while (it != end())
	{
		it = erase(it);
	}
}
析构函数
//析构函数
~list()
{
	clear();
	delete _head;
	_head = nullptr;
}
拷贝构造函数
//拷贝构造
list(list<T>& lt)
{
	empty_init();
	for (auto e : lt)
	{
		push_back(e);
	}
}
赋值重载函数

传统写法

//赋值重载传统写法
list<T>& operator=(const list<T>& lt)
{
	if (this != &lt)
	{
		clear(); 
		for (auto e : lt)
		{
			push_back(e);
		}
	}
	return *this;
}

现代写法

//赋值重载现代写法
void swap(list<T>& lt)
{
	std::swap(_head, lt._head);
	std::swap(_size, lt._size);
}

list<T>& operator=(list<T> lt)
{
	swap(lt);
	return *this;
}

const迭代器的设计

上述代码实现了非const迭代器,本质就是封装了一个类,提供了对应的接口,而const迭代器本质就是迭代器指向的内容不可修改,因此不可以直接写const iterator,  这个const修饰的是迭代器本身不能被修改,那迭代器如何++访问数据呢?? 因此非const迭代器应该是一个独立的类

//非const迭代器
template <class T>
struct __list_const_iterator //前加_表示内部的实现
{
	typedef list_node<T> Node;
	Node* _node;

	//构造函数
	__list_const_iterator(Node* node)
		:_node(node)
	{}

	//迭代器++(前置++)
	typedef __list_const_iterator<T> self;
	self& operator++()
	{
		_node = _node->_next;
		return *this;
	}

	//迭代器--(前置--)
	self& operator--()
	{
		_node = _node->_prev;
		return *this;
	}

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

	//迭代器--(后置--)
	self operator--(int)
	{
		self tmp(*this);
		_node = _node->_prev;
		return tmp;
	}

	//迭代器解引用
	const T& operator*() const
	{
		return _node->_data;
	}

	const T* operator->() const
	{
		return &_node->_data;
	}

	//两个迭代器进行比较
	bool operator!=(const self& s)
	{
		return _node != s._node;
	}

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

list类中提供const迭代器的begin和end接口即可:

//list的类型
template <class T>
class list
{
	typedef list_node<T> Node;
public:
	//提供迭代器
	typedef __list_iterator<T> iterator;
	typedef __list_const_iterator<T> const_iterator;

	const_iterator begin() const
	{
		//return iterator(_head->_next);
		return _head->_next;  //单参数的构造函数支持隐式类型转化
	}

	const_iterator end() const
	{
		//return iterator(_head);
		return _head;  //单参数的构造函数支持隐式类型转化
	}
};

但是上面的写法太冗余了,非const迭代器和const迭代器都是封装了类,类中的实现大同小异,参考了STL库中的实现以后,其实只需要一个类+增加模板参数即可,  实现如下:

终极版迭代器的实现

//迭代器
template <class T, class Ref, class Ptr>
struct __list_iterator //前加_表示内部的实现
{
	typedef list_node<T> Node;
	Node* _node;

	typedef __list_iterator<T, Ref, Ptr> self;

	//构造函数
	__list_iterator(Node* node)
		:_node(node)
	{}

	//迭代器++(前置++)
	self& operator++()
	{
		_node = _node->_next;
		return *this;
	}

	//迭代器--(前置--)
	self& operator--()
	{
		_node = _node->_prev;
		return *this;
	}

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

	//迭代器--(后置--)
	self operator--(int)
	{
		self tmp(*this);
		_node = _node->_prev;
		return tmp;
	}

	//迭代器解引用
	Ref operator*()
	{
		return _node->_data;
	}

	Ptr operator->()
	{
		return &_node->_data;
	}

	//两个迭代器进行比较
	bool operator!=(const self& s)
	{
		return _node != s._node;
	}

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

list类:

template <class T>
//list的类型
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;

	iterator begin()
	{
		return iterator(_head->_next);
		return _head->_next;  //单参数的构造函数支持隐式类型转化
	}

	iterator end()
	{
		return iterator(_head);
		return _head;  //单参数的构造函数支持隐式类型转化
	}

	const_iterator begin() const
	{
		//return iterator(_head->_next);
		return _head->_next;  //单参数的构造函数支持隐式类型转化
	}

	const_iterator end() const
	{
		//return iterator(_head);
		return _head;  //单参数的构造函数支持隐式类型转化
	}
};

迭代器扩充小知识

场景1:想实现一个打印函数,  无论list的节点是什么类型都能打印

template <class T>
void Print(const list<T>& lt)
{
	//list<T>为未实例化的类模板,编译器不能直接去他里面去找
	//编译器无法识别list<T>::const_iterator是内嵌类型还是静态成员变量
	//前面加一个typename就是告诉编译器,这里是一个类型,等list<T>实例化再去类里面去取
	typename list<T>::const_iterator it = lt.begin(); 
	while (it != lt.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
}

void test_list5()
{
	list<int> lt1;
	lt1.push_back(1);
	lt1.push_back(2);
	lt1.push_back(3);
	lt1.push_back(4);
	lt1.push_back(5);
	Print(lt1);

	//list不会存在浅拷贝的问题,因为不涉及扩容
	list<string> lt2;
	lt2.push_back("1111111111111111");
	lt2.push_back("1111111111111111");
	lt2.push_back("1111111111111111");
	lt2.push_back("1111111111111111");
	lt2.push_back("1111111111111111");
	Print(lt2);
}

场景2:想实现一个打印函数, 无论是哪个STL,都能使用同一个打印函数

//模板(泛型编程)本质: 本来应该由我们做的事情交给编译器去做了!
template <typename Container>
void print_container(const Container& con)
{
	typename Container::const_iterator it = con.begin();
	while (it != con.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
}

void test_list5()
{
	list<int> lt1;
	lt1.push_back(1);
	lt1.push_back(2);
	lt1.push_back(3);
	lt1.push_back(4);
	lt1.push_back(5);
	print_container(lt1);

	//list不会存在浅拷贝的问题,因为不涉及扩容
	list<string> lt2;
	lt2.push_back("1111111111111111");
	lt2.push_back("1111111111111111");
	lt2.push_back("1111111111111111");
	lt2.push_back("1111111111111111");
	lt2.push_back("1111111111111111");
	print_container(lt2);

	vector<string> v;
	v.push_back("2222222222222222");
	v.push_back("2222222222222222");
	v.push_back("2222222222222222");
	v.push_back("2222222222222222");
	v.push_back("2222222222222222");
	print_container(v);
}

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

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

相关文章

Unity自定义框架(1)-----------单例模式

前言&#xff1a; Unity作为一款强大的游戏开发引擎&#xff0c;其基础框架的设计对于项目的结构和性能有着重要的影响。其中&#xff0c;单例模式是一种常用的设计模式&#xff0c;用于确保一个类只有一个实例&#xff0c;并提供一个全局访问点。 什么是单例模式&#xff1f…

C++面向对象程序设计 - 构造函数

C提供了构造函数来处理对象的初始化&#xff0c;构造函数是一种特殊的成员函数&#xff0c;与其他成员函数不同&#xff0c;它不需要用户来调用&#xff0c;而是在建立对象时自动执行。构造函数名称必须与类同名&#xff0c;而不能由用户任意命名&#xff0c;以便编译系统能识别…

macbook(m1) ubuntu下载,复制粘贴和国内镜像源配置

ubuntu下载使用 官网下载Ubuntu 22.04.4 LTS (Jammy Jellyfish) Daily Build 打开后根据电脑的架构选择安装包&#xff0c;想要下载其他版本也可在官网中自行搜索。 我安装时舍友说他安装的是22.04这个版本&#xff0c;我也就跟着他安装了 注意&#xff1a;下载的版本最好有…

TCP、UDP协议

TCP与UDP协议的区别 TCP&#xff08;Transmission Control Protocol&#xff09;和UDP&#xff08;User Datagram Protocol&#xff09;是两种常用的传输层协议&#xff0c;它们之间有以下几点区别&#xff1a; 1. 连接性&#xff1a; - TCP是面向连接的协议&#xff0c;通…

PostgreSQL的学习心得和知识总结(一百三十五)|深入理解PostgreSQL数据库之查找 PostgreSQL C 代码中的内存泄漏

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

Flutter混淆方案对应用性能的影响分析与优化

在移动应用开发中&#xff0c;保护应用代码安全至关重要。Flutter 提供了简单易用的混淆工具&#xff0c;帮助开发者在构建 release 版本应用时有效保护代码。本文将介绍如何在 Flutter 应用中使用混淆&#xff0c;并提供了相关的操作步骤和注意事项。 &#x1f4dd; 摘要 本…

练习 17 Web [极客大挑战 2019]PHP

常见的网站源码备份文件名和后缀&#xff0c;反序列化攻击 unserialize()&#xff1a;wakeup绕过&#xff0c;private类以及属性序列化后的%00修改 开靶机 提到”备份“ 那看看有没有backup.php啥的 如果网站存在备份文件&#xff0c;常见的备份文件后缀名有&#xff1a;“.gi…

解读命令:icacls “E:\ShareAll“ /grant “Everyone:(OI)(CI)(F)“

命令 icacls "E:\ShareAll" /grant "Everyone:(OI)(CI)(F)" 是在Windows操作系统中用来修改文件或目录权限的命令行操作。该命令执行以下操作&#xff1a; 路径&#xff1a;"E:\ShareAll" 指定了要更改权限的目录位置&#xff0c;即对E盘下的“S…

UDP实现聊天直播间 chatroom

1.memcmp() 函数 int memcmp(const void *s1, const void *s2, size_t n); memcmp() 函数用于比较两个内存区域前 n 个字节的内容。 它接受三个参数&#xff1a; •const void *s1&#xff1a;指向第一个内存区域的指针。 •const void *s2&#xff1a;指向第二个内存区域的…

Java SpringBoot中优雅地判断一个对象是否为空

在Java中&#xff0c;可以使用以下方法优雅地判断一个对象是否为空&#xff1a; 使用Objects.isNull()方法判断对象是否为空&#xff1a; import java.util.Objects;if (Objects.isNull(obj)) {// obj为空的处理逻辑 }使用Optional类优雅地处理可能为空的对象&#xff1a; impo…

使用Excel连接Azure DevOps自动退出的问题

Azure DevOps Server (原名TFS)是微软公司的软件开发管理平台&#xff0c;也是著名的软件开发过程管理工具&#xff1b;系统中记录了软件开发过程中的需求、问题、缺陷和迭代计划等各种软件开发工作项数据。 对于工作项数据的批量操作(例如新增和编辑)&#xff0c;Excel是一个非…

关于不同AR(增强现实)SDK(软件开发工具包)的汇总和特性描述

以下是每个AR SDK的核心内容概述: ARCore 开发者:Google支持平台:Android(部分设备不支持)功能:运动追踪、平面追踪、点云图、云锚点、光照估计、环境探针、人脸追踪、2D图片追踪、人物遮挡、射线测试。官网链接:ARCoreARKit 开发者:Apple支持平台:iOS(iPhone和iPad)…

【VSCode+Keil5+STM32CubeMX】开发环境配置

一、软件下载 二、软件安装 三、配置环境 四、验证开发环境 五、Keil与VS Code的同步 从0到1搭建VS Code Keil5 STM32CubeMX开发环境 优点 支持标准库HAL库LL库代码编辑更“现代化”&#xff1a;代码提示、函数跳转、更高自由度的定制主题等优点多端同步&#xff0c;VS Code和…

【Linux】在生产环境中,Linux系统排查常用命令

问题排查 文章目录 问题排查top命令CPU&#xff1a;vmstatprocscpu内存&#xff1a;free硬盘&#xff1a;df硬盘IO&#xff1a;iostat网络IO&#xff1a;ifstat 生产环境服务器变慢&#xff0c;诊断思路和性能评估 top命令 查看整机系统新能 使用top命令的话&#xff0c;重点…

大数据分析与内存计算——Spark安装以及Hadoop操作——注意事项

一、Spark安装 1.相关链接 https://dblab.xmu.edu.cn/blog/4322/ 2.安装Spark&#xff08;Local模式&#xff09; 按照文章中的步骤安装即可 遇到问题&#xff1a;xshell以及xftp不能使用 解决办法&#xff1a; 在linux使用镜像网站进行下载&#xff1a;wget https://mi…

视频汇聚/安防监控/视频存储EasyCVR平台EasyPlayer播放器更新:新增【性能面板】

视频汇聚/安防监控/视频存储平台EasyCVR基于云边端架构&#xff0c;可以在复杂的网络环境中快速、灵活部署&#xff0c;平台视频能力丰富&#xff0c;可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云…

ClickHouse集群搭建教程

文章目录 前言一、相关介绍1. 端口介绍 二、部署规划1. 准备centos2. 配置集群免密登录3. 部署规划 三、ckman依赖部署1. prometheus搭建1.1 下载并解压1.2 配置启停服务1.3 promethues配置(可选&#xff0c;不影响ckman核心功能)1.4 prometheus启停命令1.4.1 启动prometheus1.…

安全架构设计理论与实践相关知识总结

一、安全架构概述 常见信息威胁介绍&#xff1a; 1. 信息泄露&#xff1a;信息被泄露或透露给某个非授权实体 2. 破坏信息完整性&#xff1a;数据被非授权地进行增删改查货破坏而受到损失 3. 拒绝服务&#xff1a;对信息会其他资源的合法访问被无条件的组织 4. 非法使用&#x…

vue 加 websocket 聊天

<template><div style="height: 100%; width: 100%; background-color: #fff"><div class="wrap"><!-- 头部 --><div class="titleBox"><imgsrc="@/assets/image/avatar.png"style="argin: 10p…

《数据结构学习笔记---第九篇》---循环队列的实现

文章目录 1.循环队列的定义 2.循环队列的判空判满 3.创建队列并初始化 4.入队和出队 5. 返回队尾队首元素 6.释放循环队列 1.循环队列的定义 定义&#xff1a;存储队列元素的表从逻辑上被视为一个环。 我们此次实现的循环队列&#xff0c;采用顺序表 typedef struct {int…