C++初阶之一篇文章教会你stack(理解使用和模拟实现)

news2024/11/24 3:02:33

在这里插入图片描述

stack(理解使用和模拟实现)

  • 什么是stack
  • stack的使用
    • 1. stack构造函数
    • 2.empty()
    • 3.size()
    • 3.top()
    • 4.push
    • 5.emplace
    • 6.pop()
    • 7.swap
  • 模拟实现stack的准备
    • 1.什么是容器适配器?
    • 2. deque的简单介绍
    • 3. deque的缺陷
    • 4. 为什么STL中stack和queue默认使用deque?
  • 模拟实现stack
  • 结语

什么是stack

在这里插入图片描述

  1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。
  2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定
    的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。
  3. stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下
    操作:

empty:判空操作
back:获取尾部元素操作
push_back:尾部插入元素操作
pop_back:尾部删除元素操作

  1. 标准容器vector、deque、list均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器,默认情况下使用deque

在这里插入图片描述

stack的使用

1. stack构造函数

在这里插入图片描述
这些是C++标准库中std::stack类的构造函数声明。std::stack是一个适配器容器,它可以使用不同的底层容器来实现栈的功能。这些构造函数声明提供了不同的方式来创建和初始化std::stack对象,可以根据需求选择合适的构造函数。

这里的各种构造函数选项包括不同的初始化方式、移动初始化、使用不同的分配器(allocator)以及结合不同的容器类型等。你可以根据需要选择适当的构造函数来创建std::stack对象。

这些构造函数的使用方式与普通类的构造函数相似,你可以使用这些构造函数来实例化std::stack对象,并为其提供合适的参数,比如底层容器、分配器等。

你可以使用以下构造函数之一:

initialize (1):

std::stack<int> myStack1; // 使用默认构造函数,默认底层容器是 std::deque

move-initialize (2):

std::stack<int> sourceStack;
sourceStack.push(1);
sourceStack.push(2);
sourceStack.push(3);

std::stack<int> myStack2(std::move(sourceStack)); // 使用移动构造函数,sourceStack中的元素移动到myStack2

allocator (3):

std::allocator<int> myAllocator;
std::stack<int, std::vector<int, std::allocator<int>>> myStack3(myAllocator); // 使用指定的分配器

init + allocator (4):

std::vector<int> vec4 = {1, 2, 3, 4, 5};
std::allocator<int> myAllocator4;
std::stack<int, std::vector<int, std::allocator<int>>> myStack4(vec4, myAllocator4); // 使用指定的容器和分配器

move-init + allocator (5):

std::vector<int> vec5 = {5, 4, 3, 2, 1};
std::allocator<int> myAllocator5;
std::stack<int, std::vector<int, std::allocator<int>>> myStack5(std::move(vec5), myAllocator5); // 使用移动构造函数,同时指定容器和分配器

copy + allocator (6):

std::stack<int> sourceStack6;
sourceStack6.push(1);
sourceStack6.push(2);
sourceStack6.push(3);

std::allocator<int> myAllocator6;
std::stack<int, std::vector<int, std::allocator<int>>> myStack6(sourceStack6, myAllocator6); // 复制构造函数,同时指定分配器

move + allocator (7):

std::stack<int> sourceStack7;
sourceStack7.push(7);
sourceStack7.push(8);
sourceStack7.push(9);

std::allocator<int> myAllocator7;
std::stack<int, std::vector<int, std::allocator<int>>> myStack7(std::move(sourceStack7), myAllocator7); // 使用移动构造函数,同时指定分配器

这些示例基于不同的构造函数变体,以不同的方式初始化了 std::stack 对象,包括使用不同的容器类型和分配器。具体的使用情景会根据你的代码需求而有所不同。

2.empty()

bool empty() const; 是 C++ 标准库中 std::stack 类的成员函数之一。它用于判断栈是否为空。

返回类型bool,表示栈是否为空,如果栈为空则返回 true,否则返回 false
const 关键字表示这个函数不会修改类的成员变量。

你可以在实际使用中,通过调用这个函数来检查栈是否为空,以便进行相应的操作。以下是一个示例:

#include <iostream>
#include <stack>

int main() {
    std::stack<int> myStack;

    if (myStack.empty()) {
        std::cout << "Stack is empty." << std::endl;
    } else {
        std::cout << "Stack is not empty." << std::endl;
    }

    myStack.push(42);

    if (myStack.empty()) {
        std::cout << "Stack is empty." << std::endl;
    } else {
        std::cout << "Stack is not empty." << std::endl;
    }

    return 0;
}

在上述示例中,我们先创建一个空的栈 myStack,然后通过 empty() 函数来检查栈是否为空。在栈为空时输出 "Stack is empty.",否则输出 "Stack is not empty."。之后,我们将一个元素压入栈中,并再次检查栈的状态。输出应该是 "Stack is not empty."

3.size()

size_type size() const; 是 C++ 标准库中 std::stack 类的成员函数之一。它用于返回当前栈中元素的数量(大小)。

返回类型size_type,通常是一个无符号整数类型,表示栈中元素的数量。
const 关键字表示这个函数不会修改类的成员变量。

你可以在实际使用中,通过调用这个函数来获取栈中元素的数量。以下是一个示例:

#include <iostream>
#include <stack>

int main() {
    std::stack<int> myStack;

    std::cout << "Initial size: " << myStack.size() << std::endl;

    myStack.push(42);
    myStack.push(15);
    myStack.push(7);

    std::cout << "Size after pushing elements: " << myStack.size() << std::endl;

    myStack.pop();

    std::cout << "Size after popping an element: " << myStack.size() << std::endl;

    return 0;
}

在上述示例中,我们首先创建一个空的栈 myStack,然后使用 size() 函数获取栈的大小。之后,我们将三个元素压入栈中,再次使用 size() 函数获取栈的大小。接着,我们弹出一个元素,并再次使用 size() 函数获取栈的大小。输出应该是栈的大小在不同操作后的变化。

3.top()

reference top();const_reference top() const; 是 C++ 标准库中 std::stack 类的成员函数之一。它们用于获取栈顶元素的引用。

reference top();:返回栈顶元素的引用。如果需要修改栈顶元素,可以使用这个版本。
const_reference top() const;:返回栈顶元素的常量引用。如果你不需要修改栈顶元素,而只是需要读取它,可以使用这个版本。
在这两个版本中,const 关键字表示在函数内部不会修改类的成员变量,确保在使用 top() 函数的过程中不会发生意外的修改。

以下是一个示例:

#include <iostream>
#include <stack>

int main() {
    std::stack<int> myStack;

    myStack.push(42);
    myStack.push(15);

    // 使用 top() 获取栈顶元素
    int topElement = myStack.top();
    std::cout << "Top element: " << topElement << std::endl;

    // 修改栈顶元素
    myStack.top() = 99;
    std::cout << "New top element: " << myStack.top() << std::endl;

    return 0;
}

在上述示例中,我们首先将两个元素压入栈中,然后使用 top() 函数获取栈顶元素,并输出它。接着,我们使用 top() 函数修改了栈顶元素的值,然后再次使用 top() 函数获取新的栈顶元素,并输出它。注意,为了修改栈顶元素,我们使用了 top() 函数的第一个版本。

4.push

void push(const value_type& val);void push(value_type&& val); 是 C++ 标准库中 std::stack 类的成员函数之一。它们用于将一个新的元素压入栈中。

void push(const value_type& val);:将传入的值的常量引用const value_type&压入栈中。这个版本用于传递一个常量引用的值,不会修改传入的值。
void push(value_type&& val);:将传入的值的右值引用value_type&&压入栈中。这个版本用于传递一个右值引用的值,通常用于移动语义,可能会修改传入的值。

这两个版本的 push 函数允许你在栈顶添加新的元素。如果需要保持传入值的不变性,可以使用第一个版本;如果你想利用移动语义来避免不必要的复制,可以使用第二个版本。

以下是一个示例:

#include <iostream>
#include <stack>

int main() {
    std::stack<int> myStack;

    myStack.push(42); // 使用右值,将 42 压入栈中
    myStack.push(15);

    int newElement = 99;
    myStack.push(newElement); // 使用常量引用,将 newElement 压入栈中

    std::cout << "Stack size: " << myStack.size() << std::endl;
    while (!myStack.empty()) {
        std::cout << myStack.top() << " "; // 输出栈顶元素
        myStack.pop(); // 弹出栈顶元素
    }

    return 0;
}

在上述示例中,我们使用不同版本的 push 函数将元素压入栈中,包括使用右值42和常量引用newElement。然后,我们循环输出栈中的元素,并弹出栈顶元素,以清空栈。最终输出的应该是栈中元素的值。

5.emplace

template <class... Args> void emplace(Args&&... args); 是 C++ 标准库中 std::stack 类的成员函数之一。它用于在栈顶处构造一个新的元素,使用传递的参数来进行构造。

Args:可变模板参数,用于传递构造元素所需的参数列表。
args:完美转发(perfect forwarding)的参数包,用于构造元素。
这个函数利用了完美转发,可以将传入的参数包 args 在构造新元素时进行适当的转发,从而可以使用不同的构造函数来创建元素。

以下是一个示例:

#include <iostream>
#include <stack>

class MyClass {
public:
    int value;

    MyClass(int v) : value(v) {
        std::cout << "Constructor with int: " << value << std::endl;
    }
};

int main() {
    std::stack<MyClass> myStack;

    myStack.emplace(42); // 使用传入的参数构造 MyClass 对象
    myStack.emplace(15);

    std::cout << "Stack size: " << myStack.size() << std::endl;
    while (!myStack.empty()) {
        std::cout << myStack.top().value << " "; // 输出栈顶元素的 value
        myStack.pop(); // 弹出栈顶元素
    }

    return 0;
}

在上述示例中,我们首先定义了一个名为 MyClass 的类,该类具有一个带有整数参数的构造函数。然后,我们使用 emplace 函数将不同的整数值作为参数传递给构造函数,以构造 MyClass 对象。最终,我们输出栈中元素的 value 成员,并弹出栈顶元素,以清空栈。

6.pop()

void pop(); 是 C++ 标准库中 std::stack 类的成员函数之一。它用于将栈顶元素弹出(删除)。

这个函数没有返回值,它只是从栈中移除栈顶元素。在调用 pop() 函数之前,需要确保栈不为空,否则会导致未定义行为。

以下是一个示例:

#include <iostream>
#include <stack>

int main() {
    std::stack<int> myStack;

    myStack.push(42);
    myStack.push(15);
    myStack.push(7);

    std::cout << "Stack size before popping: " << myStack.size() << std::endl;

    myStack.pop(); // 弹出栈顶元素

    std::cout << "Stack size after popping: " << myStack.size() << std::endl;

    return 0;
}

在上述示例中,我们首先将三个元素压入栈中,然后输出栈的大小。接着,我们调用 pop() 函数弹出一个栈顶元素,并再次输出栈的大小。输出应该是弹出元素后的栈大小。

7.swap

void swap(stack& x) noexcept(/*see below*/); 是 C++ 标准库中 std::stack 类的成员函数之一。它用于交换两个栈的内容,使得两个栈中的元素互换。

x:另一个栈对象的引用,与当前栈对象交换内容。
这个函数没有返回值,它会交换当前栈对象和传入的栈对象 x 的内容。需要注意的是,交换操作并不会改变栈的容器类型或分配器,只是交换两个栈中的元素。

关于 noexceptnoexcept 是异常规范说明符,用于表示函数不会抛出异常。在这个函数的声明中,noexcept 后面可能会有一些条件,表示函数是否在某些情况下可能会抛出异常。如果没有特定的条件,可以简单地写成 noexcept,表示该函数不会抛出异常。

以下是一个示例:

#include <iostream>
#include <stack>

int main() {
    std::stack<int> stack1;
    std::stack<int> stack2;

    stack1.push(1);
    stack1.push(2);
    stack1.push(3);

    stack2.push(4);
    stack2.push(5);

    std::cout << "Before swapping:" << std::endl;
    std::cout << "Stack 1: ";
    while (!stack1.empty()) {
        std::cout << stack1.top() << " ";
        stack1.pop();
    }
    std::cout << std::endl;

    std::cout << "Stack 2: ";
    while (!stack2.empty()) {
        std::cout << stack2.top() << " ";
        stack2.pop();
    }
    std::cout << std::endl;

    stack1.push(6);
    stack1.push(7);

    stack1.swap(stack2); // 交换栈的内容

    std::cout << "After swapping:" << std::endl;
    std::cout << "Stack 1: ";
    while (!stack1.empty()) {
        std::cout << stack1.top() << " ";
        stack1.pop();
    }
    std::cout << std::endl;

    std::cout << "Stack 2: ";
    while (!stack2.empty()) {
        std::cout << stack2.top() << " ";
        stack2.pop();
    }
    std::cout << std::endl;

    return 0;
}

在上述示例中,我们首先创建了两个栈对象 stack1stack2,然后向它们分别添加一些元素。然后,我们使用 swap 函数交换了这两个栈的内容。在交换后,输出应该显示交换前后栈中元素的变化。

std::stackswap 函数可以在不同的容器类型之间进行交换,但是有一些限制需要注意。

std::stackswap 函数内部会调用其底层容器的 swap 函数来实现元素的交换。因此,如果底层容器类型不同,它们的 swap函数也必须是兼容的。通常情况下,C++ 标准库中的容器都会提供支持不同容器类型间交换的 swap 函数,但在使用自定义容器或第三方容器库时需要注意。

总之,在标准情况下,如果你使用的是标准库中的容器(如 std::vector、std::deque、std::list 等),那么在不同容器类型之间调用 std::stackswap 函数是安全的。但是,如果使用自定义的容器类型,需要确保这些容器的 swap 函数支持交换到其他容器类型。

模拟实现stack的准备

1.什么是容器适配器?

虽然stackqueue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stack和队列只是对其他容器的接口进行了包装,STLstackqueue默认使用deque

容器适配器(Container Adapters)是 C++ 标准库提供的一种数据结构,它们基于现有的容器类型,提供了特定的接口和功能,以便更方便地实现某些特定的数据结构和算法容器适配器本质上是对底层容器的封装,提供了不同的数据访问方式,使它们适用于特定的用途。

标准库中提供了三种常用的容器适配器:

stack:栈适配器,基于底层容器提供了栈数据结构的操作,如压入(push)、弹出(pop)、查看栈顶元素等。默认底层容器是 std::deque,但也可以使用其他支持 back()push_back() 操作的容器。
queue:队列适配器,基于底层容器提供了队列数据结构的操作,如入队(push)、出队(pop)、查看队首元素等。默认底层容器是 std::deque,但也可以使用其他支持 back()push_back() 操作的容器。
priority_queue:优先队列适配器,基于底层容器提供了优先队列数据结构的操作,支持在插入元素时根据优先级进行排序。默认底层容器是 std::vector,但也可以使用其他支持随机访问和插入操作的容器。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. deque的简单介绍

deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。
在这里插入图片描述
deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,其底层结构如下图所示:
在这里插入图片描述
双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque的迭代器身上,因此deque的迭代器设计就比较复杂,如下图所示:
在这里插入图片描述
那deque是如何借助其迭代器维护其假想连续的结构呢?
在这里插入图片描述

3. deque的缺陷

与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率是必vector高的。

与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段。但是,deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑vectorlistdeque的应用并不多,而目前能看到的一个应用就是,STL用其作为stackqueue的底层数据结构。

4. 为什么STL中stack和queue默认使用deque?

STL(标准模板库)中的 stackqueue 默认使用 std::deque 作为底层容器的原因是出于性能和功能的考虑。

std::deque(双端队列)是一个双向开口的动态数组,支持在队首和队尾进行高效的插入和删除操作。它的内部实现使得在队首和队尾的操作都能达到接近常数时间复杂度,这使得 std::deque 在作为底层容器时能够提供较好的性能。

对于 stackqueue,它们通常需要在栈顶或队尾进行元素的插入和删除操作,而 std::deque 提供了这种高效的能力。此外,std::deque 也支持在常数时间内对栈顶或队首元素进行访问,这在实现栈和队列的常见操作时非常有用。

虽然 stackqueue 默认使用 std::deque,但你也可以选择通过指定其他容器类型作为底层容器来实现不同的性能和行为。这是通过模板参数来实现的。例如,你可以使用 std::vector 作为底层容器来实现 stackqueue,但需要注意 std::vector 在头部插入元素时可能导致较大的时间复杂度。

总之,std::deque 作为 stackqueue 的默认底层容器,具备良好的性能和功能,结合了deque的优点,而完美的避开了其缺陷,能够满足大多数情况下的需求。如果你有特定的需求,可以选择其他底层容器来进行定制。

模拟实现stack

#pragma once
#include <deque>

namespace xzq
{
	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.back();
		}

		bool empty()  const
		{
			return _con.empty();
		}

		size_t size() const
		{
			return _con.size();
		}
	private:
		Container _con;
	};
}

以下是这个模拟栈的代码实现过程的分析:

头文件包含:代码首先包含了头文件 <deque>,这是为了使用底层容器 std::deque

命名空间定义:代码将 stack 类放置在了命名空间 xzq 下,这是为了避免命名冲突和提供代码的组织结构。

stack 类模板定义stack 类是一个模板类,有两个模板参数:T 表示栈中存储的元素类型,Container 表示底层容器的类型,默认为 std::deque<T>

公共成员函数

push(const T& x):将传入的元素值 x 添加到底层容器的末尾,实现了入栈操作。
pop():从底层容器的末尾删除一个元素,实现了出栈操作。
T& top()const T& top() const:分别返回底层容器的末尾元素的引用(允许修改)和常量引用(只读),实现了查看栈顶元素操作。
bool empty() const:返回底层容器是否为空。
size_t size() const:返回底层容器中元素的数量。
私有成员变量 _con:这是一个模板类的私有成员变量,用于存储实际的栈元素。其类型是根据模板参数 Container 确定的,在实例化时会被替换为具体的容器类型。

结语

有兴趣的小伙伴可以关注作者,如果觉得内容不错,请给个一键三连吧,蟹蟹你哟!!!
制作不易,如有不正之处敬请指出
感谢大家的来访,UU们的观看是我坚持下去的动力
在时间的催化剂下,让我们彼此都成为更优秀的人吧!!!

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

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

相关文章

抢红包系统---(java)

需求&#xff1a;直播抽奖活动&#xff0c;分别有【2,588,888,1000,10000】五个奖金&#xff0c;模拟抽奖。打印每个奖项&#xff0c;奖项的出现顺序随机但不重复。package demo;import java.util.Random;/* * 案例;抢红包 * 需求&#xff1a;直播抽奖活动&#xff0c;分别有【…

shell脚本循环语句

shell脚本循环语句 一.echo命令二.查看当前系统的时间--date命令三.循环语句for四.while循环语句结构五.while循环语句结构&#xff08;迭代&#xff09;六.continue和break 一.echo命令 echo -n 表示不换行输出 echo -e输出转义符&#xff0c;将转义后的内容输出到屏幕上 常…

抖音小程序排名代发需要提供什么资料

抖音小程序排名代发需要提供什么资料 抖音小程序如何做搜索排名&#xff0c;排名提升方法#小程序搭建#小程序建设#小程序排名# 营业执照&#xff0c;注册抖音的手机号&#xff0c;对公账户&#xff0c;关键词以及对应的图片 提供以上资料就可以 小程序包括两大功能&#xff0…

springboot 数据库版本升级管理常用解决方案

目录 一、前言 1.1 单独执行初始化sql 1.2 程序自动执行 二、数据库版本升级管理问题 三、spring 框架sql自动管理机制 3.1 jdbcTemplate 方式 3.1.1 创建数据库 3.1.2 创建 springboot 工程 3.1.3 初始化sql脚本 3.1.4 核心配置类 3.1.5 执行sql初始化 3.2 配置文…

Spark 学习记录

基础 SparkContext是什么&#xff1f;有什么作用&#xff1f; https://blog.csdn.net/Shockang/article/details/118344357 SparkContext 是什么&#xff1f; SparkContext 是通往 Spark 集群的唯一入口&#xff0c;可以用来在 Spark 集群中创建 RDDs 、累加和广播变量( Br…

股票指数——RSI指数

RSI指数的计算非常简单&#xff0c;就是使用一段时间内的平均上涨除以平均上涨加平均下跌&#xff08;取正值&#xff09;。也就意味着RSI指数的取值是[0,100]之间&#xff0c;其中0表示周期内没有上涨的&#xff0c;100表示周期内没有下跌的。RSI的直观意义是它表示了一段周期…

[保研/考研机试] KY43 全排列 北京大学复试上机题 C++实现

题目链接&#xff1a; 全排列https://www.nowcoder.com/share/jump/437195121692001512368 描述 给定一个由不同的小写字母组成的字符串&#xff0c;输出这个字符串的所有全排列。 我们假设对于小写字母有a < b < ... < y < z&#xff0c;而且给定的字符串中的字…

Vulnhub: MoneyBox: 1靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.194 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.194 ftp匿名登录发现trytofind.jpg 目录爆破发现blogs目录 gobuster dir -u http://192.168.111.194 -w /usr/share/word…

【MongoDB基础】

目录 一、概述 1.概念 2.相关 2.1 实例 2.2 库 2.3 集合 2.4 文档 2.5 主键 3.特性 4&#xff0c;应用场景 二、安装 1.RPM安装 2.启动数据库 三、目录结构 1.rpm -ql mongodb-org-server 2.rpm -ql mongodb-org-shell 3.rpm -ql mongodb-org-tools 四、默…

CSS 写个清除浮动,怎么还蹦出个 hasLayout? *zoom?

&#x1f9d1;‍&#x1f4bc; 个人简介&#xff1a;一个不甘平庸的平凡人&#x1f36c; &#x1f5a5;️ Node专栏&#xff1a;Node.js从入门到精通 &#x1f5a5;️ TS知识总结&#xff1a;十万字TS知识点总结 &#x1f449; 你的一键三连是我更新的最大动力❤️&#xff01;…

【LeetCode】《LeetCode 101》第十一章:妙用数据结构

文章目录 11.1 C STL11.2 数组448. 找到所有数组中消失的数字&#xff08;简单&#xff09;48. 旋转图像&#xff08;中等&#xff09;74. 搜索二维矩阵&#xff08;中等&#xff09;240. 搜索二维矩阵 II&#xff08;中等&#xff09;769. 最多能完成排序的块&#xff08;中等…

使用IDA查看汇编代码,结合安卓系统生成的Tombstone文件,分析安卓app程序崩溃问题

目录 1、IDA工具介绍 2、产品及问题场景描述 3、查看Tombstone文件 4、使用IDA打开.so动态库文件&#xff0c;查看汇编代码的上下文&#xff0c;到C源码中定位发生崩溃的那行代码 4.1、使用IDA打开.so动态库文件 4.2、切换到Text View文本视图模式 4.3、根据相对于函数的…

【Linux进程篇】环境变量

【Linux进程篇】环境变量 目录 【Linux进程篇】环境变量基本概念常见环境变量查看环境变量方法测试PATH测试HOME测试SHELL和环境变量相关的命令环境变量的组织方式通过代码如何获取环境变量命令行参数命令行第三个参数通过第三方变量environ获取 本地变量通过系统调用获取或设置…

【Sklearn】基于K邻近算法的数据分类预测(Excel可直接替换数据)

【Sklearn】基于K邻近算法的数据分类预测&#xff08;Excel可直接替换数据&#xff09; 1.模型原理模型原理&#xff1a;数学模型&#xff1a; 2.模型参数3.文件结构4.Excel数据5.下载地址6.完整代码7.运行结果 1.模型原理 K最近邻&#xff08;K-Nearest Neighbors&#xff0c…

C++入门篇8---vector

vecctor是动态顺序表 一、了解vector的相关接口及其功能 1.构造函数相关接口 函数声明功能介绍vector()无参构造vector(size_type n,const value_type& valvalue_type())构造并初始化n个valvector(const value& x)拷贝构造vector(InputIterator first, InputIterato…

ad+硬件每日学习十个知识点(33)23.8.13 (导出gerber)

文章目录 1.第一次制造输出2.第二次制造输出3.第三次制造输出 1.第一次制造输出 答&#xff1a; 2.第二次制造输出 答&#xff1a; 3.第三次制造输出 答&#xff1a;

企业计算机服务器中了Devos勒索病毒怎么办,勒索病毒解密

社会在发展&#xff0c;科技在进步&#xff0c;企业的生产也得到了很大改善&#xff0c;但是随着网络技术的不断发展&#xff0c;越来越多的企业遭到的网络安全威胁开始增多&#xff0c;其中较为明显的就是勒索病毒攻击。预防勒索病毒攻击成为日常生活中不可或缺的一部分工作。…

Python—行命令搭建HTTP服务器并外网访问本地SQL Server数据库【无公网IP内网穿透】

在强者的眼中&#xff0c;没有最好&#xff0c;只有更好。我们是移动开发领域的优质创作者&#xff0c;同时也是阿里云专家博主。 ✨ 关注我们的主页&#xff0c;探索iOS开发的无限可能&#xff01; &#x1f525;我们与您分享最新的技术洞察和实战经验&#xff0c;助您在移动…

MySQL中事务特性以及隔离机制

目录 一、什么是事务 二、事务特性——即ACID特性 三、事务的隔离级别 1、脏读 2、不可重复读 3、幻读 Read uncommitted&#xff1a; Read committed: Repeatable read: Serializable&#xff1a; 一、什么是事务 事务&#xff08;Transaction&#xff09;——一个最…

小程序用户隐私新规,微信小程序开发者需满足新要求

微信公众平台运营中心最新公告指出&#xff0c;从2023年9月15日开始&#xff0c;涉及处理用户个人信息的小程序开发者需要满足新要求。开发者须主动同步用户同意并遵守小程序的隐私保护指引和其他信息处理规则&#xff0c;方可调用微信提供的隐私接口。 并且&#xff0c;在确认…