《数据结构、算法与应用C++语言描述》-优先级队列-大根堆的C++实现

优先级队列

完整可编译运行代码见:Github::Data-Structures-Algorithms-and-Applications/_25Priority queue

定义

优先级队列(priority queue)是0个或多个元素的集合,每个元素都有一个优先权或值,对优先级队列执行的操作有1)查找一个元素;2)插入一个新元素;3)删除一个元素。与这些操作分别对应的函数是top、push和pop。在最小优先级队列(min priority queue)中,查找和删除的元素都是优先级最小的元素;在最大优先级队列(max priority queue)中,查找和删除的元素都是优先级最大的元素。优先级队列的元素可以有相同的优先级,对这样的元素,查找与删除可以按任意顺序处理。

抽象数据类型

最大优先级队列的抽象数据类型说明如ADT 12-1所示,最小优先级队列的抽象数据类型说明与之类似,只是top的pop函数不同,查找和删除的都是优先级最小的元素。

在这里插入图片描述

定义

定义 12-1 一棵大根树(小根树)是这样一棵树,其中每个节点的值都大于(小于)或等于其子节点(如果有子节点的话)的值。

定义 12-2 一个大根堆(小根堆)既是大根树(小根树)也是完全二叉树。

在大根树或小根树中,节点的子节点个数可以任意,不一定是二叉树。

必须满足是大(小)根树同时是完全二叉树才能称为大(小)根堆。

堆是完全二叉树,具有n个元素的堆的高度为 ⌈ l o g 2 ( n + 1 ) ⌉ \lceil log_2(n+1)\rceil log2n+1。因此,如果能够在 O ( h e i g h t ) O(height) O(height)时间内完成插入和删除操作,那么这些操作的复杂性为 O ( l o g n ) O(logn) O(logn)

大(小)根堆使用数组存储。以层序遍历的顺序存储元素。

大根堆的插入

由于大根堆是完全二叉树,所以在插入元素时,一定会在完全二叉树的最后一层的最后一个元素后添加一个节点。插入元素的步骤是新元素插入新节点,然后沿着从新节点到根节点的路径,执行一趟起泡操作,将新元素与其父节点的元素比较交换,直到后者大于或等于前者为止。如下图所示,如果插入元素1,可以将其直接作为节点2的左孩子。但是如果插入元素5,就需要执行起泡操作。

在这里插入图片描述

大根堆的删除

在大根堆中删除一个元素,就是删除根节点的元素。

大根堆使用数组存储,以层序遍历的顺序存储,因此数组存储的第一个节点就是最大元素。删除操作顺序为,首先找到数组存储的最后一个元素,将该元素使用temp变量暂存起来,并删除最后一个元素。然后尝试将temp放到第一个元素,这样不满足大根堆的定义,因此把根元素的左右元素的大者移到根节点。移动后形成一个空位,尝试将temp放到该空位,如果满足该节点元素大于等于其孩子节点元素,那么放置成功,删除操作完成;否则,继续选择空位的左右孩子的大者移动到空位,以此类推,直到找到合适的位置放置temp,删除操作完成。

如图12-4删除图12-3 d)的根节点。

在这里插入图片描述

大根堆的初始化

初始时,要向堆中插入n(n>0)个元素。插入操作所需的总时间为 O ( n l o g n ) O(nlogn) O(nlogn)。也可以用不同的策略在 O ( n ) O(n) O(n)时间内完成堆的初始化。

首先是拿到一个数组,数组的元素按任意顺序。该数组可以转化为一个完全二叉树,需要做的是将完全二叉树转化为大根堆。从最后一个具有孩子的节点开始,如果以这个元素为根的子树是大根堆,则不做操作;如果以这个元素为根的子树不是大根堆,则需要将这个子树调整为大根堆。然后一次检查倒数第二个、倒数第三个子树,直到检查到第一个元素为根的树为止。

代码

template<class T>
void maxHeap<T>::initialize(T *theHeap, int theSize)
{
    delete [] heap;
    heap = theHeap;// 数组已经指定了
    heapSize = theSize;
    // 从最后一个有孩子节点的节点开始
    for (int root = heapSize / 2; root >= 1; root--)
    {
        T rootElement = heap[root];

        int child = 2 * root; // 当前节点的左孩子节点
        while (child <= heapSize)
        {
            // 找到孩子节点中的较大者
            if (child < heapSize && heap[child] < heap[child + 1])
                child++;

            // 如果rootElement大于等于孩子节点的较大者,那么就终止循环
            if (rootElement >= heap[child])
                break;

            // 如果rootElement小于孩子节点的较大者,就在父亲节点放置孩子节点
            heap[child / 2] = heap[child];
            child *= 2;// 找到较大孩子节点的孩子节点
        }
        // 如果孩子节点的较大者小于rootElement,就将rootElement作为孩子节点的父亲
        heap[child / 2] = rootElement;
    }
}

复杂性

在大根堆的初始化程序 initialize函数中,如果元素个数为 n(即theSize=n),那么for 循环的每次迭代所需时间为 O ( l o g n ) O(logn) O(logn),迭代次数为 n / 2 n/2 n/2,因此initialize函数的复杂性为 O ( n l o g n ) O(nlogn) O(nlogn)。注意,O表示法提供算法复杂性的上限。实际应用中,initialize的复杂性要比上限 O ( n l o g n ) O(nlogn) O(nlogn)好一些。经过更仔细的分析,我们得出真正的复杂性为 Θ ( n ) Θ(n) Θ(n)

在 initialize 函数中,while 循环的每一次迭代所需时间为 O ( h i ) O(h_i) O(hi),其中 h i h_i hi是以位置i 为根节点的子树的高度。完全二叉树heap[1:n]的高度为 h = ⌈ l o g 2 ( n + 1 ) ⌉ h=\lceil log_2(n+1)\rceil h=log2(n+1)⌉。在树的第j层,最多有 2 j − 1 2^{j-1} 2j1个节点。因此最多有 2 j − 1 2^{j-1} 2j1个节点具有相同的高度 h i = h − j + 1 h_i=h-j+1 hi=hj+1。于是大根堆的初始化时间为:

在这里插入图片描述

因为for循环执行n/2次迭代,所以复杂性为2(n)。将两者综合考虑,得到initialize的复杂性为 Θ ( n ) Θ(n) Θ(n)

堆与STL

STL的类 priority_queue利用了基于向量的堆来实现大根堆,它允许用户自己制定优先级的比较函数,因此,这个类也可以用于实现小根堆。

代码

main.cpp

/*
Project name :			_25Priority_queue
Last modified Date:		2023年11月29日21点08分
Last Version:			V1.0
Descriptions:			优先级队列——大根堆main函数
*/
#include "maxHeap.h"
int main() {
    maxHeapTest();
    return 0;
}

maxHeap.h

/*
Project name :			_25Priority_queue
Last modified Date:		2023年11月29日21点08分
Last Version:			V1.0
Descriptions:			优先级队列——大根堆模板头文件
*/
/*[[nodiscard]]标记符可以用于提示程序员在调用有返回值的函数时不要忘记接收改函数的返回值*/

#ifndef _25PRIORITY_QUEUE_MAXHEAP_H
#define _25PRIORITY_QUEUE_MAXHEAP_H
#include "maxPriorityQueue.h"
#include "_1myExceptions.h"
#include "_2myFunctions.h"
#include <iostream>
#include <sstream>
#include <algorithm>
#include <memory>

using namespace std;
int maxHeapTest();
template<class T>
class maxHeap : public maxPriorityQueue<T>
{
public:
    explicit maxHeap(int initialCapacity = 10);
    ~maxHeap() {heap = nullptr;}
    [[nodiscard]] bool empty() const {return heapSize == 0;}
    [[nodiscard]] int size() const {return heapSize;}
    const T& top()
    {// 返回最大元素,也就是堆顶的值
        if (heapSize == 0)
            throw queueEmpty();
        return heap[1];
    }
    void pop();// 向堆中弹出元素
    void push(const T&);// 向堆中插入元素
    void initialize(T *, int);// 初始化堆
    void deactivateArray()// 禁用数组,这个还没搞清楚怎么用
    {heap = nullptr; arrayLength = heapSize = 0;}
    void output(ostream& out) const;// 输出大根堆的所有元素
private:
    int heapSize;       // 存储大根堆中有多少元素
    int arrayLength;    // 存储大根堆的容量大小
    T* heap;            // 存储大根堆元素的数组
};

template<class T>
maxHeap<T>::maxHeap(int initialCapacity)
{// 构造函数,容量必须>=1
    if (initialCapacity < 1)
    {
        ostringstream s;
        s << "Initial capacity = " << initialCapacity << " Must be > 0";
        throw illegalParameterValue(s.str());
    }
    arrayLength = initialCapacity + 1;
    heap = new T(arrayLength);
    heapSize = 0;
}

// 向大顶堆中插入元素
template<class T>
void maxHeap<T>::push(const T& theElement)
{
    // 如果容量不够的话需要增加容量
    if (heapSize == arrayLength - 1)
    {
        changeLength1D(heap, arrayLength, 2 * arrayLength);
        arrayLength *= 2;
    }

    // 从叶子节点开始起泡,将元素插入
    int currentNode = ++heapSize;
    // 如果编号i不是根节点,则其父节点的编号为[i/2](向下取整)
    while (currentNode != 1 && heap[currentNode / 2] < theElement)
    {
        // 父节点小于子节点,不能将元素放到此处
        heap[currentNode] = heap[currentNode / 2]; // 将父节点放到currentNode出
        currentNode /= 2;                          // 当前节点的index转移到父节点
    }
    // 直到父节点大于等于theElement,将theElement放到当前位置
    heap[currentNode] = theElement;
}

// 删除大顶堆的最大元素
// 在大根堆是二叉树时可以这样弄
template<class T>
void maxHeap<T>::pop()
{
    // 如果大顶堆元素个数为0,那么抛出queueEmpty异常
    if (heapSize == 0)
        throw queueEmpty();

    // 删除数组中第一个元素,也就是根节点的元素
    heap[1].~T();

    // 找到大顶堆的最后一排的最后一个元素
    T lastElement = heap[heapSize--];
    // 当前节点与其孩子节点的index
    int currentNode = 1,
            child = 2;
    while (child <= heapSize)
    {
        // 找到孩子节点中的较大者
        if (child < heapSize && heap[child] < heap[child + 1]) // 这里只考虑了两个孩子,因此大根堆是二叉树
            child++;
        // 如果lastElement大于等于孩子节点的较大者,就终止循环,说明找到了lastElement可以放置的位置
        if (lastElement >= heap[child])
            break;

        // 如果没找到放置lastElement的位置,就在currentNode放置孩子节点中的较大者
        heap[currentNode] = heap[child];
        currentNode = child;// 现在空位就变成了刚刚移动的孩子节点
        child *= 2;// 其孩子的index就是2倍的child
    }
    heap[currentNode] = lastElement;// 如果找到位置了就直接将最后一个元素放置到找到的位置上
}

template<class T>
void maxHeap<T>::initialize(T *theHeap, int theSize)
{
    delete [] heap;// 数组已经指定了
    heap = theHeap;
    heapSize = theSize;
    // 从最后一个有孩子节点的节点开始
    for (int root = heapSize / 2; root >= 1; root--)
    {
        T rootElement = heap[root];

        int child = 2 * root; // 当前节点的左孩子节点
        while (child <= heapSize)
        {
            // 找到孩子节点中的较大者
            if (child < heapSize && heap[child] < heap[child + 1])
                child++;

            // 如果rootElement大于等于孩子节点的较大者,那么就终止循环
            if (rootElement >= heap[child])
                break;

            // 如果rootElement小于孩子节点的较大者,就在父亲节点放置孩子节点
            heap[child / 2] = heap[child];
            child *= 2;// 找到较大孩子节点的孩子节点
        }
        // 如果孩子节点的较大者小于rootElement,就将rootElement作为孩子节点的父亲
        heap[child / 2] = rootElement;
    }
}

template<class T>
void maxHeap<T>::output(ostream& out) const
{// 输出大顶堆中的所有元素
    for(T* i = heap + 1; i < heap + heapSize + 1; i++)
        cout << *i << " ";
    cout << endl;
}

// 重载输出操作符 <<
template <class T>
ostream& operator<<(ostream& out, const maxHeap<T>& x)
{x.output(out); return out;}

#endif //_25PRIORITY_QUEUE_MAXHEAP_H

maxHeap.cpp

/*
Project name :			_25Priority_queue
Last modified Date:		2023年11月29日21点08分
Last Version:			V1.0
Descriptions:			优先级队列——大根堆模板源文件
*/
#include "maxHeap.h"

using namespace std;

int maxHeapTest()
{
    // test constructor and push
    maxHeap<int> h(3);
    h.push(10);
    h.push(20);
    h.push(5);

    cout << "Heap size is " << h.size() << endl;
    cout << "Elements in array order are" << endl;
    cout << h << endl;

    h.push(15);
    h.push(30);

    cout << "Heap size is " << h.size() << endl;
    cout << "Elements in array order are" << endl;
    cout << h << endl;

    // test top and pop
    cout << "The max element is " << h.top() << endl;
    h.pop();
    cout << "The max element is " << h.top() << endl;
    h.pop();
    cout << "The max element is " << h.top() << endl;
    h.pop();
    cout << "Heap size is " << h.size() << endl;
    cout << "Elements in array order are" << endl;
    cout << h << endl;

    // test initialize
    int z[10];
    for (int i = 1; i < 10; i++)
        z[i] = i;
    h.initialize(z, 9);
    cout << "Elements in array order are" << endl;
    cout << h << endl;
    return 0;
}

maxPriorityQueue.h

/*
Project name :			_25Priority_queue
Last modified Date:		2023年11月29日21点08分
Last Version:			V1.0
Descriptions:			优先级队列——大根堆抽象数据类型
*/

#ifndef _25PRIORITY_QUEUE_MAXPRIORITYQUEUE_H
#define _25PRIORITY_QUEUE_MAXPRIORITYQUEUE_H

template<class T>
class maxPriorityQueue
{
public:
    virtual ~maxPriorityQueue() = default;
    [[nodiscard]] virtual bool empty() const = 0;
    // return true iff queue is empty
    [[nodiscard]] virtual int size() const = 0;
    // return number of elements in queue
    virtual const T& top() = 0;
    // return reference to the max element
    virtual void pop() = 0;
    // remove the top element
    virtual void push(const T& theElement) = 0;
    // add theElement to the queue
};
#endif //_25PRIORITY_QUEUE_MAXPRIORITYQUEUE_H

_1myExceptions.h

/*
Project name :			allAlgorithmsTest
Last modified Date:		2022年8月13日17点38分
Last Version:			V1.0
Descriptions:			综合各种异常
*/
#pragma once
#ifndef _MYEXCEPTIONS_H_
#define _MYEXCEPTIONS_H_
#include <string>
#include<iostream>
#include <utility>

using namespace std;

// illegal parameter value
class illegalParameterValue : public std::exception
{
public:
    explicit illegalParameterValue(string theMessage = "Illegal parameter value")
    {message = std::move(theMessage);}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// illegal input data
class illegalInputData : public std::exception
{
public:
    explicit illegalInputData(string theMessage = "Illegal data input")
    {message = std::move(theMessage);}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// illegal index
class illegalIndex : public std::exception
{
public:
    explicit illegalIndex(string theMessage = "Illegal index")
    {message = std::move(theMessage);}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// matrix index out of bounds
class matrixIndexOutOfBounds : public std::exception
{
public:
    explicit matrixIndexOutOfBounds
            (string theMessage = "Matrix index out of bounds")
    {message = std::move(theMessage);}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// matrix size mismatch
class matrixSizeMismatch : public std::exception
{
public:
    explicit matrixSizeMismatch(string theMessage =
    "The size of the two matrics doesn't match")
    {message = std::move(theMessage);}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// stack is empty
class stackEmpty : public std::exception
{
public:
    explicit stackEmpty(string theMessage =
    "Invalid operation on empty stack")
    {message = std::move(theMessage);}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// queue is empty
class queueEmpty : public std::exception
{
public:
    explicit queueEmpty(string theMessage =
    "Invalid operation on empty queue")
    {message = std::move(theMessage);}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// hash table is full
class hashTableFull : public std::exception
{
public:
    explicit hashTableFull(string theMessage =
    "The hash table is full")
    {message = std::move(theMessage);}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// edge weight undefined
class undefinedEdgeWeight : public std::exception
{
public:
    explicit undefinedEdgeWeight(string theMessage =
    "No edge weights defined")
    {message = std::move(theMessage);}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// method undefined
class undefinedMethod : public std::exception
{
public:
    explicit undefinedMethod(string theMessage =
    "This method is undefined")
    {message = std::move(theMessage);}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};
#endif

_2myFunctions.h

/*
Project name :			allAlgorithmsTest
Last modified Date:		2022年8月13日17点38分
Last Version:			V1.0
Descriptions:			综合各种非成员函数
*/
#pragma once
#ifndef _MYFUNCTIONS_H_
#define _MYFUNCTIONS_H_
#include<iostream>
#include "_1myExceptions.h"
#include<cmath>
#include <exception>
#include <memory>

using std::min;
using std::endl;
using std::cout;
using std::bad_alloc;
/*交换两数据*/
template<class V>
void Swap(V& a, V& b)
{
    V temp = a;
    a = b;
    b = temp;
}
/*
作用:将数组的长度加倍
输入:指针a指向需要改变长度的数组,oldLength表示数组原来的长度,newLength表示需要改变的新长度
结果:将数组扩容/缩容 为newLength
*/
template<class T>
void changeLength(T*& a, int oldLength, int newLength)
{
    if (newLength < 0)
        throw illegalParameterValue("new length must be >= 0");
    T* temp = new T[newLength];
    int number = min(oldLength, newLength);
    copy(a, a + number, temp);
    delete[] a;
    a = temp;
}
/*遍历一维数组*/
template<class T>
void traverse1dArray(T* x, int length)
{
    for (int i = 0; i < length; i++)
        cout << x[i] << " ";
    cout << endl;
}
/*创建二维数组*/
template <class T>
bool make2dArray(T**& x, int numberOfRows, int numberOfColumns)
{
    try {
        //行指针
        x = new T * [numberOfRows];
        //为每一行分配内存
        for (int i = 0; i < numberOfRows; i++)
            x[i] = new int[numberOfColumns];
        return true;
    }
    catch (bad_alloc) { return false; }
}

/*遍历二维数组*/
template<class T>
void traverse2dArray(T**& x, int numberOfRows, int numberOfColumns)
{
    for (int i = 0; i < numberOfRows; i++)
    {
        for (int j = 0; j < numberOfColumns; j++)
        {
            cout.width(4);
            cout << x[i][j] << "  ";
        }
        cout << endl;
    }
}
template<class T>
void changeLength1D(T*& a, int oldLength, int newLength)
{
    if (newLength < 0)
        throw illegalParameterValue("new length must be >= 0");

    T* temp = new T[newLength];              // new array
    int number = min(oldLength, newLength);  // number to copy
    copy(a, a + number, temp);
    a = temp;
}
#endif

运行结果

"C:\Users\15495\Documents\Jasmine\prj\_Algorithm\Data Structures, Algorithms and Applications in C++\_25Priority queue\cmake-build-debug\_25Priority_queue.exe"
Heap size is 3
Elements in array order are
20 10 5

Heap size is 5
Elements in array order are
30 20 5 10 15

The max element is 30
The max element is 20
The max element is 15
Heap size is 2
Elements in array order are
10 5

Elements in array order are
9 8 7 4 5 6 3 2 1


Process finished with exit code 0

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智能监控平台/视频共享融合系统EasyCVR接入RTSP协议视频流无法播放原因是什么?

视频集中存储/云存储/视频监控管理平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、智能分析等。AI智能/大数据视频分析EasyCVR平台已经广泛应用在工地、工厂、园区、楼…

华天动力-OA8000 MyHttpServlet 文件上传漏洞复现

0x01 产品简介 华天动力OA是一款将先进的管理思想、 管理模式和软件技术、网络技术相结合&#xff0c;为用户提供了低成本、 高效能的协同办公和管理平台。 0x02 漏洞概述 华天动力OA MyHttpServlet 存在任意文件上传漏洞&#xff0c;未经身份认证的攻击者可上传恶意的raq文件…

【前端系列】前端存档术之keep-alive

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Kubernetes技术与架构-安全性

本文主要从不同层面与多个维度描述Kubernetes技术与架构的安全性。 云原生的安全性 从系统分层架构的角度分析&#xff0c;自底向上&#xff0c;云原生的安全性主要包括云、集群、容器以及代码四个层面&#xff0c;简称云原生4C安全&#xff0c;其架构图如下所示&#xff1a;…

万宾科技水环境综合治理监测系统的融合与应用

随着社会经济的快速发展&#xff0c;我国的水环境污染问题日益凸显&#xff0c;这不仅对生态环境造成了严重破坏&#xff0c;也严重威胁到人民群众的健康和生活质量。为了解决这一问题&#xff0c;城市生命线与水环境综合治理监测系统应运而生&#xff0c;二者的结合将为水环境…

【Linux】Linux中git的基本使用(三板斧)

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和Linux还有算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 …

MySQL 中的锁(一)

MySQL 中的锁 按照 MySQL 官方的说法&#xff0c;InnoDB 中锁可以分为&#xff1a; 可见&#xff0c;InnoDB 中锁非常多&#xff0c;总的来说&#xff0c;可以如下分类&#xff1a; 这些锁都是做什么的&#xff1f;具体含义是什么&#xff1f;我们现在来一一学习。 8.1. 解…

基于YOLOv8深度学习的生活垃圾分类目标检测系统【python源码+Pyqt5界面+数据集+训练代码】目标检测

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

数据结构-选择排序(简单选择、堆)

简单选择排序 基本思想 非常基础的算法&#xff0c;假设有N个数据&#xff0c;比较N-1轮&#xff0c;每轮选出当前剩余数据的最大&#xff08;最小&#xff09;放到数据 的开头&#xff0c;之后重复即可获得答案。 示例 代码 void SelectSort(OrderList *L) {RecordType t…

MySQL与其他数据库产品的比较,优势在哪里?

作为数据库管理领域的博主作家&#xff0c;我深知数据库在软件开发和数据管理中的重要性。在当今众多的数据库产品中&#xff0c;MySQL作为一种流行的开源关系型数据库管理系统&#xff0c;具有许多优势和特点。下面&#xff0c;我将通过对与其他数据库产品的比较以及MySQL的优…

Ubuntu22.04 server版本关闭DHCP,手动设置ip

在Ubuntu 22.04 中&#xff0c;网络配置已迁移到 Netplan&#xff0c;因此可以使用 Netplan 配置文件来手动设置 IP 地址并关闭 DHCP。 以下是在 Ubuntu 22.04 上手动设置 IP 地址并禁用 DHCP 的步骤&#xff1a; 打开终端&#xff0c;使用 root 权限或 sudo 执行以下命令&…

JavaScript图片处理大揭秘!掌握文件流处理方法

说在前面 &#x1f4bb;作为一名前端开发&#xff0c;我们平时也少不了对文件流数据进行处理&#xff0c;今天简单整理一下日常开发中比较常见的一些处理文件流的场景及处理方法&#xff0c;希望可以帮助到大家&#xff0c;挤出多一点的摸鱼学习时间。 常见场景 一、input框上…

计算机网络 一到二章 PPT 复习

啥币老师要隔段时间测试&#xff0c;我只能说坐胡狗吧旁边 第一章 这nm真的会考&#xff0c;我是绷不住的 这nm有五种&#xff0c;我一直以为只有三种 广播帧在后面的学习中经常遇到 虽然老师在上课的过程中并没有太过强调TCP/IP的连接和断开&#xff0c;但我必须强调一下&…

iOS--UIPickerView学习

UIPickerView 使用场景和功能UIPickerView遵循代理协议和数据源协议创建对象&#xff0c;添加代理必须实现的代理方法非必要实现的方法demo用到的其他函数提示 效果展示 使用场景和功能 UIPickerView 最常见的用途是作为选项选择器&#xff0c;允许用户从多个选项中选择一个。…

『亚马逊云科技产品测评』活动征文| 基于etcd实现服务发现

提示&#xff1a;授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 背景 etcd 是一个分布式 Key-Value 存储系统&#xff0…

Audacity降噪消除视频中杂音

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

【嵌入式Linux开发一路清障-连载04】虚拟机VirtualBox7.0安装Ubuntu22.04后挂载Windows平台共享文件夹

虚拟机安装Ubuntu22.04后挂载Windows平台共享文件夹 障碍07-虚拟机VirtualBox7.0完装完Ubuntu22.04后&#xff0c;无法成功挂载Windows平台中共享文件夹&#xff0c;无法访问电脑中的各类重要文件&#xff0c;我该怎么办&#xff1f;一、问题的模样&#xff1a;VirtualBox7.0设…

用Metasploit进行信息收集2

基于FTP协议收集信息 1.查看ftp服务的版本信息 打开metasploit 查看ftp版本的模块&#xff0c;并进入模块 msf6 > search ftp_version msf6 > use auxiliary/scanner/ftp/ftp_version msf6 auxiliary(scanner/ftp/ftp_version) > show options 查看靶机的端口开方情…

宋仕强论道之华强北自组织和激励模式(十四)

宋仕强论道之华强北自组织和激励模式&#xff08;十四&#xff09;: 为什么一个小小深圳市华强北我宋仕强就讲这么久呢&#xff0c;听说玄奘大和尚刚出道时在洛阳的白马寺讲经&#xff0c;一个“悟”字就讲了三个月。一个事物有他的复杂性和多样性&#xff0c;从自然科学和社会…

visual studio 2022 更改字体和大小

工具--->选项 文本编辑器 输出窗口