C++第六讲:STL--vector的使用及模拟实现

news2024/11/24 21:01:51

C++第六讲:STL--vector的使用及模拟实现

  • 1.vector简介
  • 2.vector的常见接口介绍
    • 2.1constructor -- 构造
    • 2.2destructor -- 析构
    • 2.3begin、end
      • 2.3.1vector和string的区别、vector<string>
    • 2.4rbegin、rend
    • 2.5cbegin、cend
    • 2.6crbegin、crend
    • 2.7size、max_size、resize、capacity、empty、reserve
    • 2.8shrink_to_fit
    • 2.9operator[]、at
    • 2.10front、back
    • 2.11data
    • 2.12assign
    • 2.13push_back、pop_back
    • 2.14insert、erase
    • 2.15swap、clear
    • 2.16vector扩容规则
  • 3.vector在OJ题中的使用
    • 3.1练习1
    • 3.2练习2
  • 4.vector的模拟实现
    • 4.1vector标准库中的源码观察
    • 4.2vector的实现
    • 4.3vector实现注意事项
      • 4.3.1注意事项1
      • 4.3.2注意事项2 -- 迭代器失效问题
        • 4.3.2.1扩容引起的迭代器失效
          • 4.3.2.1.1情况1
          • 4.3.2.1.2情况2
        • 4.3.2.2删除数据,数据位置移动导致的迭代器失效
      • 4.3.3注意事项3 -- 类模板中的函数模板问题
      • 4.3.4注意事项4 -- sting中深浅拷贝问题

1.vector简介

vertor是一个真正的容器,底层实现是一个动态开辟的数组:
在这里插入图片描述
所以说我们可以将vector简单地理解成:
在这里插入图片描述

vector的一些接口的使用和string相同,所以对于那些简单的使用,就一笔带过,本文详细要讲的还是vertor的模拟实现,以及一些其它的科普知识

2.vector的常见接口介绍

尽管不会详细讲述接口的作用,但是还是会讲接口一一列出来

2.1constructor – 构造

构造的使用:

int main()
{
	vector<int> first;//使用vector模板实例化一个对象
	vector<int> second(4, 100);//4个数据,每个数据为100
	vector<int> third(second.begin(), second.end());//迭代器区间初始化
	vector<int> forth(second);//拷贝初始化

	return 0;
}

这些都是一些简单的构造,要着重处理的是:
在这里插入图片描述
使用initializer_list进行初始化:

int main()
{
	vector<int> v = { 10, 20, 30, 40 };//使用数组进行初始化
	vector<int> v1({ 20, 30, 40 });//和上面的功能是一样的
	//使用数组初始化的底层其实是遍历数组,将数组中的元素一个一个地尾插到vector中

	//auto il1 = { 1, 2, 3, 4, 5, 6 };
	//initializer_list<int> il2 = { 1, 2, 3, 4, 5, 6 };//等价于上面的auto
	//int a[] = { 1, 2, 3, 4, 5, 6 };

	return 0;
}

2.2destructor – 析构

2.3begin、end

迭代器,使用起来也十分简单:

int main()
{
	vector<int> v({ 1, 2, 3, 4, 5, 6, 7, 8, 9 });
	//这表明迭代器的范围应该在vector<int>中,这样就可以更加清楚地理解迭代器了
	vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;//1 2 3 4 5 6 7 8 9

	return 0;
}

既然有了迭代器,那么就可以使用范围for:

int main()
{
	vector<int> v({ 1, 2, 3, 4, 5, 6, 7, 8, 9 });
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;//1 2 3 4 5 6 7 8 9

	return 0;
}

2.3.1vector和string的区别、vector

下面还有一种使用范围for时需要注意的地方:

int main()
{
	//看下面两个有什么区别:
	vector<char> v;
	string s1;
	//1.vector中没有关于字符串的概念,只有尾插和尾删,所以并不能直接插入一个字符串,而string中能
	//2.vector中并没有对于字符串特有的操作,比如连接、查找子串、替换子串等
	//3.vector中不仅能存储字符数据,还能够针对于其它任何类型的数据,而string是专门处理字符的类

	return 0;
}
int main()
{
	//但是我们可以这样写:
	vector<string> v;
	//这样就可以使用针对字符串的操作了:
	string s1 = "张三";
	v.push_back(s1);
	v.push_back("李四");

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

	v[0] += 'x';//这里使用的是string中的+=,因为v[0]就是一个string类的对象
	v[0] += "apple";
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	//v[0][0]++;//张 -》 峙
	//C++中,对于汉字的编码,是通过汉字的后一个字节来将相同读音的汉字排在一起的
	v[0][1]++;//张 -》 掌
	v[0][1]++;//掌 -》 涨
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

但是这里会出现问题:
在这里插入图片描述

2.4rbegin、rend

反向迭代器

2.5cbegin、cend

const_iterator

2.6crbegin、crend

const_reverse_iterator

2.7size、max_size、resize、capacity、empty、reserve

2.8shrink_to_fit

这个接口是将capacity改变成适合它的size的函数,但是不建议使用,首先,它只是一个请求,并不是强制的,其次,如果实现决定减少容量,可能会造成内存的重新分配,导致所有的迭代器会失效,迭代器的失效在后边会详细阐述

2.9operator[]、at

访问,[]访问越界时会断言报错,at是抛异常

2.10front、back

放回的是头、尾元素的引用

2.11data

vector的实现底层是一个数组,而data函数的作用就是将底层的数组返回

在这里插入图片描述

2.12assign

将新内容赋给vector,覆盖原来的旧内容

2.13push_back、pop_back

尾插、尾删元素

2.14insert、erase

不同的是,vector中的insert和erase函数传入的位置只能是迭代器:

int main()
{
	vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	v.insert(v.begin(), 20);
	v.insert(v.begin()+2, 10);//20 1 10 2 3 4 5 6 7 8 9
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	v.erase(v.begin() + 2);//20 1 2 3 4 5 6 7 8 9
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

2.15swap、clear

clear函数不改变capacity

2.16vector扩容规则

结论:vector中的扩容是按照1.5倍来进行扩容的

//测试代码:
void TestVectorExpand()
{
	size_t sz;
	vector<int> v;
	sz = v.capacity();
	cout << "making v grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}

在这里插入图片描述

3.vector在OJ题中的使用

3.1练习1

链接: 只出现一次的数字

这道题实现十分简单,只需要异或即可,重点是观察vector的使用:

在这里插入图片描述

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int sum = 0;
        for(auto e : nums)
        {
            sum ^= e;
        }
        return sum;
    }
};

3.2练习2

链接: 杨辉三角OJ
这一题就相当不一样了,我们通过画图来解释一下:
在这里插入图片描述
所以这里我们就看出了C++和C语言的不同,下面我们用代码来实现一下杨辉三角,实现起来也是比较轻松的:

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> vv(numRows);
        for(int i = 0; i<numRows; i++)
        {
            vv[i].resize(i+1, 1);//使用resize能够在开辟空间的同时进行初始化,所以说更好用
        }
        for(int i = 2; i<numRows; i++)
        {
            for(int j = 1; j<vv[i].size()-1; j++)
            {
                vv[i][j] = vv[i-1][j] + vv[i-1][j-1];
            }
        }
        return vv;
    }
};

4.vector的模拟实现

4.1vector标准库中的源码观察

以后我们对于文档的查看会相当频繁,也会十分重要,所以我们现在看一下原码:

源码可能有几百行,也有可能会有几千行,所以当我们看源码时,不能够逐字逐句地去看,这样效率很低,我们首先要做的就是观察这些源码的大致框架,这里我们只看一个stl函数:push_back,所以我们只拿这一个函数举例:

在这里插入图片描述
通过上述分析,我们可以了解该函数的使用了,但是也体会到了源文件的恐怖!了解了上述的源文件之后,我们也可以看着尝试写出自己的vector:

4.2vector的实现

因为对于vector实现时的注意事项在下边会一一点出来,所以这里直接放代码:

//因为模板函数的声明和定义分离可能会造成一些问题,所以我们只使用两个文件:.h和test.cpp
namespace Mine
{
	template<class T>
	class vector
	{
	public:
		typedef	T* iterator;
		typedef	const T* const_iterator;

		//无参构造函数
		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{}
		//析构函数
		~vector()
		{
			if (_start)
			{
				delete[] _start;
			}
			_start = _finish = _endofstorage = nullptr;
		}

		//size、capacity的返回
		size_t size() const
		{
			return _finish - _start;
		}
		size_t capacity() const
		{
			return _endofstorage - _start;
		}

		尾插
		//void push_back(const T& x)
		//{
		//	//既然要插入,那么就要检查空间的大小是否充足
		//	if (_finish == _endofstorage)
		//	{
		//		reserve(capacity() == 0 ? 4 : capacity() * 2);
		//	}
		//	*_finish = x;
		//	_finish++;
		//}
		//reserve -- 空间开辟
		void reserve(size_t n)
		{
			//reserve不一定只在push_back函数中使用,还可能会直接使用
			//所以这里要比较n和空间的大小
			if (n > capacity())
			{
				//为了改变tmp的指向,我们需要知道原来start和tmp差的距离为多少
				size_t oldSize = size();
				//开辟空间的逻辑为:先创建一块空间,再将原来空间的内容复制过来
				T* tmp = new T[n];
				if (_start)
				{
					//memcpy(tmp, _start, sizeof(T) * size());
					for (int i = 0; i < oldSize; i++)
					{
						tmp[i] = _start[i];
					}
					delete[] _start;
				}

				_start = tmp;
				_finish = _start + oldSize;
				_endofstorage = _start + n;
			}
		}

		//访问操作符
		T& operator[](size_t pos)
		{
			assert(pos < size());

			return _start[pos];
		}
		//迭代器实现
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		const_iterator begin() const
		{
			return _start;
		}
		const_iterator end() const
		{
			return _finish;
		}

		//判空
		bool empty()
		{
			return _endofstorage == _finish;
		}

		//删除最后一个元素
		void pop_back()
		{
			assert(!empty);

			_finish--;
		}

		//尾插
		void push_back(const T& x)
		{
			既然要插入,那么就要检查空间的大小是否充足
			//if (_finish == _endofstorage)
			//{
			//	reserve(capacity() == 0 ? 4 : capacity() * 2);
			//}
			//*_finish = x;
			//_finish++;

			insert(_finish, x);
		}
		//插入函数
		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);
			//对于插入数据,仍然需要判断空间的大小
			if (_finish == _endofstorage)
			{
				//和上面的处理相似,需要先知道pos位置到开始位置的距离,然后再修正pos的位置即可
				int len = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + len;
			}
			//将pos之后的数据向后移动一位
			iterator i = _finish -1;
			while (i >= pos)
			{
				*(i + 1) = *i;
				i--;
			}
			*pos = x;
			_finish++;

			return pos;
		}

		//erase -- 删除函数的实现
		iterator erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);
			//要删除pos位置的数据,我们将pos位置之后的数据向前移动就行了
			iterator it = pos + 1;
			while (it < _finish)
			{
				*(it - 1) = *it;
				it++;
			}

			_finish--;
			return pos;
		}

		//resize -- 重新分配空间
		void resize(T& n, T& val = T())//因为传入的不一定是什么类型,所以T()就表示调用T类型对象的构造函数
			//默认构造其实是没有默认构造的,而有了模板之后,C++对默认构造进行了升级,那么就可以使用默认构造了
		{
			if (n <= size())
			{
				//当要缩容时,直接改变_finish的指向即可
				_finish = _start + n;
			}
			else
			{
				//需要扩容时,扩容,而且将扩容的空间进行初始化
				reserve(n);

				while (_finish < _start + n)
				{
					*_finish = val;
					_finish++;
				}
			}
		}
		
		//拷贝构造函数
		vector(const vector<T>& v)
		{
			reserve(v.capacity());
			//这里我们可以按照传统的写法:开空间,拷贝,也可以这样:
			for (auto& e : v)
			{
				push_back(e);
			}
		}
		//交换函数
		void swap(vector<T>& v)
		{
			swap(_start, v._start);
			swap(_finish, v._finish);
			swap(_endofstorage, v._endofstorage);
		}
		//赋值运算符重载
		vector<T>& operator= (vector<T> v)
		{
			swap(*this, v);

			return *this;
		}

		//迭代区间构造
		template <class InputIterator>
		//写成函数模板的优点为:扩大了传入参数的范围,可以是int形,甚至可以是string形
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}

		//n个val进行的构造
		vector(size_t n, const T& val = T())
		{
			//先写reserve是为了避免一直开辟空间的问题
			reserve(n);

			for (size_t i = 0; i < n; i++)
			{
				push_back(val);
			}
		}
		vector(int n, const T& val = T())
		{
			reserve(n);

			for (int i = 0; i < n; i++)
			{
				push_back(val);
			}
		}

		//使用数组进行初始化
		vector(initializer_list<T> il)
		{
			reserve(il.size());

			for (auto& e : il)
			{
				push_back(e);
			}
		}

	private:
		iterator _start;
		iterator _finish;
		iterator _endofstorage;
	};
}

4.3vector实现注意事项

4.3.1注意事项1

在这里插入图片描述

4.3.2注意事项2 – 迭代器失效问题

4.3.2.1扩容引起的迭代器失效

这次引起的迭代器失效本质是野指针问题,但是迭代器并不就是指针,VS所实现的迭代器就不仅仅是一个指针,而是一个复杂的类,其中除了对于指针的封装,而且还增加了对于迭代器的一些检查,我们可以通过指令来看到:

在这里插入图片描述

4.3.2.1.1情况1

在这里插入图片描述

4.3.2.1.2情况2

在vector类和string类的标准库实现中,并没有find接口的实现,但是,在标准库中,有find函数,所以我们可以直接使用标准库中的find函数

在这里插入图片描述

4.3.2.2删除数据,数据位置移动导致的迭代器失效

在这里插入图片描述

4.3.3注意事项3 – 类模板中的函数模板问题

模板类的成员函数,也可以时函数模板:

//迭代区间构造
template <class InputIterator>
//写成函数模板的优点为:扩大了传入参数的范围,可以是int形,甚至可以是string形
vector(InputIterator first, InputIterator last)
{
	while (first != last)
	{
		push_back(*first);
		first++;
	}
}

//我们可以这样进行使用:
int main()
{
	Mine::vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	//1.可以使用vector的迭代区间进行构造
	vector<int> v2(v1.begin(), v1.end());
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;

	//2.可以使用string的迭代区间按进行构造
	string s1("hello");
	vector<int> v3(s1.begin(), s1.end());
	for (auto e : v3)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

vector中还有一个构造:n个val进行的构造:

//n个val进行的构造
vector(size_t n, const T& val = T())
{
	//先写reserve是为了避免一直开辟空间的问题
	reserve(n);

	fot(size_t i = 0; i < n; i++)
	{
		push_back(val);
	}
}

但是当我们这样写时,会发生错误:

int main()
{
	Mine::vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
	
	Mine::vector<int> v2(10, 1);//err
	//vector<double> v2(10, 1.1);
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

因为Mine::vector v2(10, 1);调用的是vector(InputIterator first, InputIterator last)函数,该函数的参数更加匹配,所以我们要再创建一个int类型的构造来解决这个问题:

//n个val进行的构造
vector(size_t n, const T& val = T())
{
	//先写reserve是为了避免一直开辟空间的问题
	reserve(n);

	for (size_t i = 0; i < n; i++)
	{
		push_back(val);
	}
}
vector(int n, const T& val = T())
{
	reserve(n);

	for (int i = 0; i < n; i++)
	{
		push_back(val);
	}
}

4.3.4注意事项4 – sting中深浅拷贝问题

在这里插入图片描述

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

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

相关文章

C++AVL树的介绍和实现

目录 1.AVL树的概念 2.AVL树的实现 2.1AVL树的结构 2.2AVL树的插入 2.2.1AVL树插入一个值的大概过程 2.2.2平衡因子的更新 2.2.3插入节点及更新平衡因子的代码实现(暂未实现旋转逻辑) 2.3旋转 2.3.1旋转的原则 2.3.2右单旋(处理parent->_bf -2 && cur-&g…

简易入门:使用Docke 部署一个tomcat服务

简易入门&#xff1a;使用Docke 部署一个tomcat服务 # 拉取 >docker pull tomcat:9.0# 后台运行容器&#xff0c;端口映射为8080. -p 宿主机端口:容器端口 >docker run -d --name tomcat-c-01 -p 8080:8080 tomcat:9.0# 查看容器id >docker ps CONTAINER ID IMAG…

Qt-系统线程安全(63)

目录 描述 使用 线程不安全 线程安全 释放锁问题 其他的锁 条件变量和信号量 描述 多线程程序太复杂了 在C/C 和 Linux中&#xff0c;我们为了保证线程安全&#xff0c;简单的方式就是加锁 为此 Qt 也封装了自己的一套锁管理 使用 线程不安全 我们先测验一下线程不安…

七、程序流程控制

一、三种执行顺序 执行顺序说明顺序结构自上而下的执行代码分支结构根据条件&#xff0c;选择对应代码执行循环结构控制某段代码重复执行 二、分支结构 1、if 分支 根据条件&#xff08;真或假&#xff09;来决定执行某段代码if 分支有三种形式 //第一种形式 if(条件表达式…

Qt学习(一)——win10系统下Qt安装(Qt5.15.2+QtCreator5.0.3+MSVC2019)

win10平台下&#xff0c;Qt Creator 5.0.3 软件About Qt Creator界面如下&#xff1a; 其基于Qt 5.15.2 MSVC2019&#xff0c;64bit,故在用Qt4 设计师自定义控件所设计的控件能够被Qt Creator加载到&#xff0c;就要安装相应版本的Qt和MSVC。此安装便可支持win10系统下的自定义…

Java项目实战II基于Java+Spring Boot+MySQL的足球青训俱乐部管理后台系统的设计与开发(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 足球作为世…

【hot100-java】排序链表

链表题。 使用归并排序法。 一图解决。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode next) { this.val val; thi…

(刷题记录6)三数之和

三数之和 题目信息&#xff1a;题目思路(环境来自力扣OJ的C)&#xff1a;暴力枚举&#xff1a;双指针&#xff1a;在三数之和上&#xff1a;转化成的两数之和&#xff1a;两数之和小优化&#xff1a; 复杂度&#xff1a;代码和解释&#xff1a;暴力枚举&#xff1a;双指针&…

【C语言】深入理解指针(三)(上)

本篇博客将讲解以下知识&#xff1a; 1、字符指针变量 2、数组指针变量 1、字符指针变量 在指针的类型中&#xff0c;有一种指针类型为字符指针&#xff1a;char* 一般使用&#xff1a; 注意&#xff1a;%s打印字符串的时候&#xff0c;需要提供字符串首元素的起始地址。 易错…

tensorflow + pygame 手写数字识别的小游戏

起因&#xff0c; 目的: 很久之前&#xff0c;一个客户的作业&#xff0c;我帮忙写的。 今天删项目&#xff0c;觉得比较简洁&#xff0c;发出来给大家看看。 效果图: 1. 训练模型的代码 import sys import tensorflow as tf# Use MNIST handwriting dataset mnist tf.kera…

C# 中循环的应用说明

一循环的概念说明 在C#编程中&#xff0c;循环结构是一种非常重要的控制流语句&#xff0c;它允许我们重复执行一段代码&#xff0c;直到满足某个特定条件为止。C#提供了几种不同类型的循环结构&#xff0c;包括for循环、while循环、do-while循环和foreach循环。 循环语句允许…

树莓派应用--AI项目实战篇来啦-7.OpenCV脸部和眼睛检测

1. 介绍 在深度学习时代&#xff0c;人脸识别一般是利用卷积神经网络进行监督式学习&#xff0c;也就是通过让算法&#xff08;神经网络&#xff09;自己去发现规律的方式&#xff0c;创造出有用的卷积核&#xff0c;然后利用其进行寻找图片和视频中的人脸&#xff0c;而在这之…

【Mac苹果电脑安装】DBeaverEE for Mac 数据库管理工具软件教程【保姆级教程】

Mac分享吧 文章目录 DBeaverEE 数据库管理工具 软件安装完成&#xff0c;打开效果图片Mac电脑 DBeaverEE 数据库管理工具 软件安装——v24.21️⃣&#xff1a;下载软件2️⃣&#xff1a;安装JDK&#xff0c;根据下图操作步骤提示完成安装3️⃣&#xff1a;安装DBeaverEE&#…

【ESP32】ESP-IDF开发 | LED PWM控制器+呼吸灯例程

1. 简介 LED PWM控制器&#xff0c;简称LEDC&#xff0c;主要用于控制LED的亮度和颜色&#xff0c;当然也可以当作普通的PWM进行使用。 LEDC有16路通道&#xff0c;8路高速通道和8路低速通道&#xff0c;16路通道都能够产生独立的数字波形来驱动LED设备。高速和低速通道分别有8…

C++:模拟stack、queue

目录 容器适配器 定义 特点 deque deque的优势与缺点 选择deque作为stack和queue的底层默认容器的原因 模拟实现stack 模拟实现queue 容器适配器 定义 在C标准模板库&#xff08;STL&#xff09;中&#xff0c;容器适配器&#xff08;Container Adapters&#xff09;是…

Harmony开发基础

背景介绍 鸿蒙系统的开发一来是为了打破国外垄断&#xff0c;实现操作系统的国产化&#xff0c;另一方面是针对目前市场上出现大量新的移动设备&#xff0c;手表&#xff0c;折叠屏等&#xff0c;移动端程序要适配不同设备&#xff0c;需要维护一套代码下的多个版本&#xff0…

U盘直接拔掉之后数据丢失怎么恢复 U盘数据丢失了怎么恢复

U盘作为一种存储设备&#xff0c;可以帮助人们存储很多资料文件&#xff0c;无论是办公文件&#xff0c;亦或是生活中的照片&#xff0c;所以在存储数据文件时&#xff0c;人们是比较依赖U盘。不过&#xff0c;U盘也存在很多的不确定性&#xff0c;比如数据容易丢失、或者损坏。…

NirCmd-sendkeysendkeypress

引入script [Script File] This command allows you to execute a sequence of commands stored inside the file specified in [Script File] parameter. Example: script "c:\temp\msg.ncl" Example for a script:infobox "Hello !" "This is the …

微知-如何查看服务器CPU当前运行主频?(cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq)

关键命令 cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq背景 首先lscpu可以查看到有多个cpu&#xff0c;里面也会显示cpu的频率&#xff0c;但是这里显示仅仅是规格&#xff0c;不是实际值。为了查看实际值&#xff0c;需要到/sys文件系统中查看&#xff0c;也…

大数据-167 ELK Elasticsearch 详细介绍 特点 分片 查询

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…