【C++】stack和queue拓展學習

目錄

1.反向迭代器思路及實現

1.1. 源碼及框架分析

1.2. 實現反向迭代器

2.stack和queue練習拓展-計算器實現

2.1. 后綴表達式概念

2.2. 后綴表達式運算規則

2.3. 中綴表達式轉后綴表達式

2.3.1 轉換思路

2.3.2 代碼實現

2.4. 計算器實現


1.反向迭代器思路及實現

1.1. 源碼及框架分析

SGI-STL30版本源代碼,反向迭代器實現的核心源碼在stl_iterator.h中。

前文我們了解到了正向迭代器是基于原生指針的封裝實現,反向迭代器的邏輯與正向迭代器的邏輯正好相反,代碼應該高度相似,因此在學習了stack與queue之后,明白了適配器思想,我們就復用正向迭代器代碼實現反向迭代器,減少代碼冗余。

下面我們截出vector和list的的反向迭代器結構框架核心部分截取出來如下:

// stl_list.h
template <class T, class Alloc = alloc>
class list {
public:typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATIONtypedef reverse_iterator<const_iterator> const_reverse_iterator;typedef reverse_iterator<iterator> reverse_iterator;
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */typedef reverse_bidirectional_iterator<const_iterator, value_type,const_reference, difference_type> const_reverse_iterator;typedef reverse_bidirectional_iterator<iterator, value_type, reference,difference_type> reverse_iterator;
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */iterator begin() { return (link_type)((*node).next); }const_iterator begin() const { return (link_type)((*node).next); }iterator end() { return node; }const_iterator end() const { return node; }reverse_iterator rbegin() { return reverse_iterator(end()); }const_reverse_iterator rbegin() const {returnconst_reverse_iterator(end());}reverse_iterator rend() { return reverse_iterator(begin()); }const_reverse_iterator rend() const {returnconst_reverse_iterator(begin());}
};
// stl_vector.h
template <class T, class Alloc = alloc>
class vector {
public:typedef T value_type;typedef value_type* iterator;
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATIONtypedef reverse_iterator<const_iterator> const_reverse_iterator;typedef reverse_iterator<iterator> reverse_iterator;
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */typedef reverse_iterator<const_iterator, value_type, const_reference,difference_type> const_reverse_iterator;typedef reverse_iterator<iterator, value_type, reference, difference_type>reverse_iterator;
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */iterator begin() { return start; }const_iterator begin() const { return start; }iterator end() { return finish; }const_iterator end() const { return finish; }reverse_iterator rbegin() { return reverse_iterator(end()); }const_reverse_iterator rbegin() const {returnconst_reverse_iterator(end());}reverse_iterator rend() { return reverse_iterator(begin()); }const_reverse_iterator rend() const {returnconst_reverse_iterator(begin());}
};
// stl_iterator.h
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
// This is the new version of reverse_iterator, as defined in the
// draft C++ standard. It relies on the iterator_traits template,
// which in turn relies on partial specialization. The class
// reverse_bidirectional_iterator is no longer part of the draft
// standard, but it is retained for backward compatibility.
template <class Iterator>
class reverse_iterator
{
protected:Iterator current;
public:typedef typename iterator_traits<Iterator>::iterator_categoryiterator_category;typedef typename iterator_traits<Iterator>::value_typevalue_type;typedef typename iterator_traits<Iterator>::difference_typedifference_type;typedef typename iterator_traits<Iterator>::pointerpointer;typedef typename iterator_traits<Iterator>::referencereference;typedef Iterator iterator_type;typedef reverse_iterator<Iterator> self;
public:reverse_iterator() {}explicit reverse_iterator(iterator_type x) : current(x) {}reverse_iterator(const self& x) : current(x.current) {}
#ifdef __STL_MEMBER_TEMPLATEStemplate <class Iter>reverse_iterator(const reverse_iterator<Iter>& x) : current(x.current) {}
#endif /* __STL_MEMBER_TEMPLATES */iterator_type base() const { return current; }reference operator*() const {Iterator tmp = current;return *--tmp;}
#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */self& operator++() {--current;return *this;}self operator++(int) {self tmp = *this;--current;return tmp;}self& operator--() {++current;return *this;}self operator--(int) {self tmp = *this;++current;return tmp;}self operator+(difference_type n) const {return self(current - n);}self& operator+=(difference_type n) {current -= n;return *this;}self operator-(difference_type n) const {return self(current + n);}self& operator-=(difference_type n) {current += n;return *this;}reference operator[](difference_type n) const { return *(*this + n); }
};
template <class Iterator>
inline bool operator==(const reverse_iterator<Iterator>& x,const reverse_iterator<Iterator>& y) {return x.base() == y.base();
}
template <class Iterator>
inline bool operator<(const reverse_iterator<Iterator>& x,const reverse_iterator<Iterator>& y) {return y.base() < x.base();
}
template <class Iterator>
inline typename reverse_iterator<Iterator>::difference_type
operator-(const reverse_iterator<Iterator>& x,const reverse_iterator<Iterator>& y) {return y.base() - x.base();
}
template <class Iterator>
inline reverse_iterator<Iterator>
operator+(reverse_iterator<Iterator>::difference_type n,const reverse_iterator<Iterator>& x) {return reverse_iterator<Iterator>(x.base() - n);
}
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
// This is the old version of reverse_iterator, as found in the original
// HP STL. It does not use partial specialization.
template <class BidirectionalIterator, class T, class Reference = T&,class Distance = ptrdiff_t>
class reverse_bidirectional_iterator {typedef reverse_bidirectional_iterator<BidirectionalIterator, T, Reference,Distance> self;
protected:BidirectionalIterator current;
public:typedef bidirectional_iterator_tag iterator_category;typedef T value_type;typedef Distance difference_type;typedef T* pointer;typedef Reference reference;reverse_bidirectional_iterator() {}explicit reverse_bidirectional_iterator(BidirectionalIterator x): current(x) {}BidirectionalIterator base() const { return current; }Reference operator*() const {BidirectionalIterator tmp = current;return *--tmp;}
#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */self& operator++() {--current;return *this;}self operator++(int) {self tmp = *this;--current;return tmp;}self& operator--() {++current;return *this;}self operator--(int) {self tmp = *this;++current;return tmp;}
};
template <class RandomAccessIterator, class T, class Reference = T&,class Distance = ptrdiff_t>
class reverse_iterator {typedef reverse_iterator<RandomAccessIterator, T, Reference, Distance>self;
protected:RandomAccessIterator current;
public:typedef random_access_iterator_tag iterator_category;typedef T value_type;typedef Distance difference_type;typedef T* pointer;typedef Reference reference;reverse_iterator() {}explicit reverse_iterator(RandomAccessIterator x) : current(x) {}RandomAccessIterator base() const { return current; }Reference operator*() const { return *(current - 1); }
#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */self& operator++() {--current;return *this;}self operator++(int) {self tmp = *this;--current;return tmp;}self& operator--() {++current;return *this;}self operator--(int) {self tmp = *this;++current;return tmp;}self operator+(Distance n) const {return self(current - n);}self& operator+=(Distance n) {current -= n;return *this;}self operator-(Distance n) const {return self(current + n);}self& operator-=(Distance n) {current += n;return *this;}Reference operator[](Distance n) const { return *(*this + n); }
};
#endif //__STL_CLASS_PARTIAL_SPECIALIZATION

? 源碼中我們可以看到reverse_iterator實現了兩個版本,通過
__STL_CLASS_PARTIAL_SPECIALIZATION 條件編譯控制使用哪個版本,在舊版本中,因為因為封裝是類型不好確定,我們需要自己傳遞參數,而有了萃取技術后,我們可以得到對應的類型,因此就不需要傳遞很多參數。

簡單點說就是支持偏特化的迭代器萃取以后,反向迭代器使用的是這個版本, template <class Iterator>class reverse_iterator(一個參數); 之前使用的是template <class BidirectionalIterator, class T, class Reference,class Distance>class reverse_bidirectional_iterator;template <class RandomAccessIterator, class T, class Reference,class Distance>class reverse_iterator;(多個參數)


? 我們可以看到他們的差別主要是在模板參數是否傳遞迭代器指向的數據類型,支持偏特化的迭代器萃取以后就不需要給了,因為reverse_iterator 內部可以通過迭代器萃取獲取數據類型。迭代器萃取的本質是一個特化(這里我們就不講解了),想了解可以去看源碼。

本文這里我們為了便于理解,我們主要使用模版參數傳遞數據類型的方式實現。


? 反向迭代器本質是一個適配器,使用模版實現,傳遞哪個容器的迭代器就可以封裝適配出對應的反向迭代器。因為反向迭代器的功能跟正向的迭代器功能高度相似,只是遍歷的方向相反,類似operator++ 底層調用迭代器的operator-- 等,所以封裝一下就可以實現。


? 比較奇怪的是operator*的實現,源碼內部訪問的是迭代器當前位置的前一個位置

這個要結合容器中rbegin和rend實現才能看懂,rbegin返回的是封裝end位置的反向迭代器,rend返回的是封裝begin位置迭代器的反向迭代器,這里是為了與正向迭代器對應,專門實現出一個對稱版本,begin與rend,end與rbegin,所以解引用訪問的是當前位置的前一個位置,這樣返回解引用rbegin時,返回上一個節點,即返回有效節點的最后一個節點,解引用rend就會正好返回哨兵節點。(這里沒有其他的特殊作用,如果愿意也可以不對稱實現)

1.2. 實現反向迭代器

// ReverseIterator.h
// 所有容器的反向迭代器
// 迭代器適配器
namespace zlr
{template<class Iterator, class Ref, class Ptr>struct ReverseIterator{typedef ReverseIterator<Iterator, Ref, Ptr> Self;// 正向迭代器Iterator _it;ReverseIterator(Iterator it):_it(it){}Ref operator*(){Iterator tmp = _it;return *(--tmp);}Ptr operator->(){return &(operator*());}Self& operator++(){--_it;return *this;}Self& operator--(){++_it;return *this;}Self operator++(int){Self tmp(*this);--_it;return tmp;}Self operator--(int){Self tmp(*this);--_it;return tmp;}bool operator!=(const Self& s) const{return _it != s._it;}bool operator==(const Self& s) const{return _it != s._it;}};
}
// vector.h
#include"ReverseIterator.h"
namespace zlr
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;typedef ReverseIterator<iterator, T&, T*> reverse_iterator;typedef ReverseIterator<const_iterator, const T&, const T*>const_reverse_iterator;reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}const_reverse_iterator rbegin() const{return const_reverse_iterator(end());}const_reverse_iterator rend() const{return const_reverse_iterator(begin());}iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}// ....private:iterator _start = nullptr;iterator _finish = nullptr;iterator _endofstorage = nullptr;};
}
// list.h
#include"ReverseIterator.h"
namespace zlr
{template<class T>class list{typedef ListNode<T> Node;public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T*> const_iterator;typedef ReverseIterator<iterator, T&, T*> reverse_iterator;typedef ReverseIterator<const_iterator, const T&, const T*>const_reverse_iterator;reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}const_reverse_iterator rbegin() const{return const_reverse_iterator(end());}const_reverse_iterator rend() const{return const_reverse_iterator(begin());}iterator begin(){return _head->_next;}iterator end(){return _head;}const_iterator begin() const{return _head->_next;}const_iterator end() const{return _head;}// ...private:Node* _head;size_t _size;};
}
// test.cpp
#include"list.h"
#include"vector.h"
int main()
{zlr::list<int> lt = { 1,2,3,4 };zlr::list<int>::reverse_iterator rit = lt.rbegin();while (rit != lt.rend()){//*rit = 1;cout << *rit << " ";++rit;}cout << endl;return 0;
}
//int main()
//{
// zlr::vector<int> v = { 1,2,3,4 };
// zlr::vector<int>::reverse_iterator rit = v.rbegin();
// while (rit != v.rend())
// {
// //*rit = 1;
// cout << *rit << " ";
// ++rit;
// }
// cout << endl;
//
// return 0;
//}

2.stack和queue練習拓展-計算器實現

2.1. 后綴表達式概念

? 我們日常寫的計算表達式都是中綴表達式,也就是運算符在中間,運算數在兩邊,但是中綴表達式直接讀取無法馬上進行運算,因為一個計算表達式還涉及運算符優先級問題,中綴表達式無法直接確定一個運算符優先級,必須根據相鄰運算符才能確定。如: 1-2*(3-4)+5 中遇到-和*都無法運算,因為后面還有括號優先級更高。


? 所以其中一種實現思路是把中綴表達式轉換為后綴表達式,也就是說分析計算表達式的優先級,將運算符放到前面,運算符放到運算數的后面,然后我們依次讀取后綴表達式,遇到運算符就可以進行運算了。后綴表達式也就做逆波蘭表達式(Reverse Polish Notation, RPN),這種表示法由波蘭邏輯學家J·盧卡西維茲于1929年提出,后來被廣泛應用于計算機科學中。

2.2. 后綴表達式運算規則

? 后綴表達式因為已經確定好優先級,運算符方式非常簡單,就是遇到運算符時取前面的兩個數進行運算,因為經過中綴轉后綴優先級已經確定好了,因此我們根據運算特點,使用棧來實現。


? 建立一個存儲運算數,讀取后綴表達式,遇到運算數入棧遇到運算符出棧頂的兩個數據進行運算運算后將結果作為一個運算數入棧繼續參與下一次的運算。讀取表達式結束后,最后棧里面的值就是運算結果。

??? 150. 逆波蘭表達式求值 - 力扣(LeetCode)???????

class Solution {
public:int evalRPN(const vector<string>& tokens) {stack<int> s;for (size_t i = 0; i < tokens.size(); ++i){const string& str = tokens[i];// str為運算數,入棧if (!("+" == str || "-" == str || "*" == str || "/" == str)){s.push(stoi(str));}else{// str為運算符,取前兩個運算數進行運算int right = s.top();s.pop();int left = s.top();s.pop();switch (str[0]){case '+':s.push(left + right);break;case '-':s.push(left - right);break;case '*':s.push(left * right);break;case '/':s.push(left / right);break;}}}return s.top();}
};

2.3. 中綴表達式轉后綴表達式

2.3.1 轉換思路

? 依次讀取計算表達式中的值,遇到運算數直接輸出


? 建立一個棧存儲運算符,利用棧后進新出性質,遇到后面運算符,出棧里面存的前面運算符進行比較,確定優先級。


? 遇到運算符,如果棧為空或者棧不為空且當前運算符比棧頂運算符優先級高,則當前運算符入棧。因為如果棧里面存儲的是前一個運算符,當前運算符比前一個優先級高,說明前一個不能運算,當前運算符也不能運算,因為后面可能還有更高優先級的運算符。


? 遇到運算符如果棧不為為空且當前運算符比棧頂運算符優先級低或相等,說明棧頂的運算符可以運算了,則輸出棧頂運算符,當前運算符繼續走前面遇到運算符的邏輯。


? 如果遇到(),則把括號的計算表達式當成一個子表達式進行遞歸,跟上思路類似處理子表達式,處理后轉換出的后綴表達式加在前面表達式的后面即可


? 計算表達式或者()中子表達式結束時,輸出棧中所有運算符

2.3.2 代碼實現

class Solution {
public://map<char, int> _operatorPrecedence = { { '+', 1 }, { '-', 1 }, { '*', 2//}, { '/', 2 } };//因為運算符優先級與ASCII無關,這里我們使用結構體來處理運算符的優先級比較問題//如果學習過map容器,可以使用map處理int operatorPrecedence(char ch){struct opPD{char _op;int _pd;};static opPD arr[] = { {'+', 1},{'-', 1},{'*', 2},{'/', 2} };for (auto& e : arr){if (e._op == ch){return e._pd;}}assert(false);return -1;}//因為有遞歸的情況存在,我們這里使用i來記錄當前訪問位置void toRPN(const string& s, size_t& i, vector<string>& v){stack<char> st;while (i < s.size()){if (isdigit(s[i])){// 操作數輸出string num;while (i < s.size() && isdigit(s[i])){num += s[i];++i;}v.push_back(num);}else{if (s[i] == '('){// 遞歸方式處理括號中的子表達式++i;toRPN(s, i, v);}else if (s[i] == ')'){++i;// 棧中的運算符全部輸出while (!st.empty()){v.push_back(string(1, st.top()));st.pop();}// 結束遞歸return;}else{// 運算符// 1、如果棧為空或者棧不為空且當前運算符比棧頂運算符優先級高,則當//前運算符入棧// 2、如果棧不為為空且比棧頂運算符優先級低或相等,說明棧頂的運算符//可以運算了,// 輸出棧頂運算符,當前運算符繼續走前面遇到運算符的邏輯if (st.empty() || operatorPrecedence(s[i]) >operatorPrecedence(st.top())){st.push(s[i]);++i;}else{v.push_back(string(1, st.top()));st.pop();}}}}// 棧中的運算符全部輸出while (!st.empty()){v.push_back(string(1, st.top()));st.pop();}}
};
int main()
{size_t i = 0;vector<string> v;//string str = "1+2-3";string str = "1+2-(3*4+5)-7";Solution().toRPN(str, i, v);for (auto& e : v){cout << e << " ";}cout << endl;return 0;
}

2.4. 計算器實現

?? 224. 基本計算器 - 力扣(LeetCode)?

? 有了上面兩個部分學習之后,計算器OJ的大部分問題就解決了,但是這里還有一些問題需要處理。因為OJ中給的中綴表達式是字符串,字符串中包含空格,需要去掉空格。


? 其次就是負數和減號,要進行區分,將所有的負數-x轉換為0-x,因為我們實現的代碼考慮到乘除的情況,針對括號內的符號,我們不能直接變號處理。

class Solution {
public://map<char, int> _operatorPrecedence = { { '+', 1 }, { '-', 1 }, { '*', 2
}, { '/', 2 } };
int operatorPrecedence(char ch)
{struct opPD{char _op;int _pd;};static opPD arr[] = { {'+', 1},{'-', 1},{'*', 2},{'/', 2} };for (auto& e : arr){if (e._op == ch){return e._pd;}}assert(false);return -1;
}
void toRPN(const string& s, size_t& i, vector<string>& v)
{stack<char> st;while (i < s.size()){if (isdigit(s[i])){// 運算數輸出string num;while (i < s.size() && isdigit(s[i])){num += s[i];++i;}v.push_back(num);}else{if (s[i] == '('){// 遞歸方式處理括號中的子表達式++i;toRPN(s, i, v);}else if (s[i] == ')'){++i;// 棧中的運算符全部輸出while (!st.empty()){v.push_back(string(1, st.top()));st.pop();}// 結束遞歸return;}else{// 運算符// 1、如果棧為空或者棧不為空且當前運算符比棧頂運算符優先級高,則當//前運算符入棧// 2、如果棧不為為空且比棧頂運算符優先級低或相等,說明棧頂的運算符//可以運算了,// 輸出棧頂運算符,當前運算符繼續走前面遇到運算符的邏輯if (st.empty() || operatorPrecedence(s[i]) >operatorPrecedence(st.top())){st.push(s[i]);++i;}else{v.push_back(string(1, st.top()));st.pop();}}}}// 棧中的運算符全部輸出while (!st.empty()){v.push_back(string(1, st.top()));st.pop();}
}
int evalRPN(const vector<string>& tokens) {stack<int> s;for (size_t i = 0; i < tokens.size(); ++i){const string& str = tokens[i];// str為數字if (!("+" == str || "-" == str || "*" == str || "/" == str)){s.push(stoi(str));}else{// str為操作符int right = s.top();s.pop();int left = s.top();s.pop();switch (str[0]){case '+':s.push(left + right);break;case '-':s.push(left - right);break;case '*':s.push(left * right);break;case '/':s.push(left / right);break;}}}return s.top();
}
int calculate(string s)
{// 1、去除所有空格,否則下面的一些邏輯沒辦法處理std::string news;news.reserve(s.size());for (auto ch : s){if (ch != ' ')news += ch;}s.swap(news);news.clear();// 2、將所有的負數-x轉換為0-xfor (size_t i = 0; i < s.size(); ++i){//當-的前一個字符不為運算數時,我們才添加"0-",否則就是減號,不需要處理//同時因為這里是下標比較,需要注意符號在表達式第一位的情況,防止越界if (s[i] == '-' && (i == 0 || (!isdigit(s[i - 1]) && s[i - 1] !=')')))news += "0-";elsenews += s[i];}// 中綴表達式轉成后綴表達式size_t i = 0;vector<string> v;toRPN(news, i, v);// 后綴表達式進行運算return evalRPN(v);
}
};

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/90128.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/90128.shtml
英文地址,請注明出處:http://en.pswp.cn/web/90128.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Web3與區塊鏈如何革新網絡安全——走在前沿

隨著互聯網技術的飛速發展&#xff0c;網絡安全問題日益成為全球關注的焦點。Web3和區塊鏈技術作為新興的技術力量&#xff0c;正在逐步改變網絡安全的格局。本文將探討Web3和區塊鏈技術如何革新網絡安全&#xff0c;走在技術前沿。 1. Web3技術概述 Web3&#xff0c;即第三代互…

網絡初級安全第三次作業

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>用戶登錄</title><style>* {margin:…

CSS中用display實現元素的顯示/隱藏切換

** 通過display中的none和block ** 在前端開發中&#xff0c;display: none 和 display: block 是兩種常用的 CSS 顯示模式&#xff0c;核心區別在于&#xff1a;是否在頁面中保留元素的占位空間 1. 核心區別屬性display: nonedisplay: block占位空間元素完全從渲染樹中移除&am…

因果圖方法設計測試用例的價值與使用范圍

一、因果圖方法的核心原理 因果圖方法通過分析軟件規格說明中的輸入條件&#xff08;因&#xff09;和輸出結果&#xff08;果&#xff09;之間的邏輯關系&#xff0c;利用圖形化方式將這些關系清晰展現。它使用特定的符號表示因果關系&#xff08;如恒等、非、或、與&#xff…

智慧農服數字化平臺-數字科技賦能農業,開啟智慧三農新篇章

智慧農服數字化平臺數字科技賦能農業&#xff0c;開啟智慧三農新篇章平臺概覽在鄉村振興和農業現代化的時代背景下&#xff0c;我們推出了創新的農業服務數字化平臺——一個專為農業生產者打造的綜合性SaaS服務平臺。平臺以"科技助農、數據興農"為使命&#xff0c;通…

在線教育培訓課程視頻如何防下載、防盜錄?

在數字化學習日益普及的今天&#xff0c;高質量的在線課程已成為教育機構、知識付費平臺和講師的核心競爭力。如何在不影響學員正常學習體驗的前提下&#xff0c;有效防止課程視頻被惡意盜取&#xff1f;今天介紹在線教育課程防下載、防盜錄的10種視頻加密方法&#xff0c;看看…

圖像分析學習筆記(2):圖像處理基礎

圖像分析學習筆記&#xff1a;圖像處理基礎圖像增強方法圖像復原方法圖像分割方法形態學處理圖像增強方法 目的&#xff1a;改善視覺效果&#xff0c;例如增強對比度定義&#xff1a;為了改善視覺效果、便于人或計算機對圖像的分析理解&#xff0c;針對圖像的特點或存在的問題…

生存分析機器學習問題

研究目標&#xff1a; 開發一個機器學習模型&#xff0c;用于個性化預測XXX的總體生存期。 模型輸入&#xff1a;結合生存時間、治療方案、人口統計學特征和實驗室測試結果等多種特征。 模型輸出&#xff1a;預測二元結果&#xff08;活著 vs. 死亡&#xff09;。 應用場景&…

【華為機試】547. 省份數量

文章目錄547. 省份數量描述示例 1示例 2提示解題思路核心分析問題轉化算法選擇策略1. 深度優先搜索 (DFS)2. 廣度優先搜索 (BFS)3. 并查集 (Union-Find)算法實現詳解方法一&#xff1a;深度優先搜索 (DFS)方法二&#xff1a;廣度優先搜索 (BFS)方法三&#xff1a;并查集 (Union…

09_Spring Boot 整合 Freemarker 模板引擎的坑

09_Spring Boot 整合 Freemarker 模板引擎的坑 1.背景&#xff1a; springboot 版本&#xff1a;3.0.2 2. 引入依賴 在 pom.xml 中添加&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web<…

十七、【Linux系統yum倉庫管理】替換阿里源、搭建本地yum源

替換阿里源、搭建本地yum源本章學習目標內容簡介阿里外網源核心功能本地yum核心功能操作演示替換阿里外網源備份原有yum源清理沖突配置下載阿里源配置文件添加EPEL擴展源清理緩存重建索引驗證源狀態測試安裝軟件使用鏡像搭建本地倉庫準備ISO鏡像創建掛載點目錄掛載iso文件驗證掛…

家庭網絡怎么進行公網IP獲取,及內網端口映射外網訪問配置,附無公網IP提供互聯網連接方案

在家庭網絡中&#xff0c;我們常常需要通過公網IP來訪問內網中的設備&#xff0c;比如家庭NAS、Web服務器或監控攝像頭。要實現這個目標&#xff0c;首先要確保你的網絡具有一個可用的公網IP&#xff0c;然后通過路由器配置端口映射&#xff08;Port Forwarding&#xff09;。如…

(LeetCode 面試經典 150 題 ) 128. 最長連續序列 (哈希表)

題目&#xff1a;128. 最長連續序列 思路&#xff1a;哈希表&#xff0c;時間復雜度0(n)。 用集合set來實現哈希表的功能&#xff0c;記錄所有出現的元素。然后遍歷元素&#xff0c;細節看注釋。 C版本&#xff1a; class Solution { public:int longestConsecutive(vector&…

Altera Quartus:BAT批處理實現一鍵sof文件轉換為jic文件

sof文件是Quartus編譯默認生成的程序文件&#xff0c;用于通過JTAG口下載到FPGA內部RAM&#xff0c;斷電程序會丟失&#xff0c;jic文件是用于固化到外部Flash中的程序文件&#xff0c;斷電程序不會丟失。本文介紹如何通過批處理文件實現sof到jic的一鍵自動化轉換。 Quartus工程…

基于單片機嬰兒床/嬰兒搖籃/嬰兒車設計/嬰兒監護系統

傳送門 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品題目速選一覽表 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品題目功能速覽 概述 本設計實現了一種基于單片機的多功能智能嬰兒監護系統&#xff0c;集成于嬰兒床、搖籃或嬰兒車中…

Typora + 七牛云圖床終極配置教程

本文是一份超詳細的 Typora 七牛云圖床配置指南&#xff0c;旨在幫助你實現圖片“即插即用”的順滑寫作體驗。我們將一步步完成所有配置&#xff0c;并特別針對配置過程中最常見的三個錯誤&#xff1a;ENOTFOUND (找不到服務器)、401 (無權訪問) 和 Document not found (文件不…

高性能熔斷限流實現:Spring Cloud Gateway 在電商系統的實戰優化

一、為什么需要高性能熔斷限流&#xff1f; 在電商系統中&#xff0c;尤其是大促期間&#xff0c;系統面臨的流量可能是平時的數十倍甚至上百倍。 這樣的場景下&#xff0c;熔斷限流不再是可選功能&#xff0c;而是保障系統穩定的生命線。傳統方案的問題&#xff1a; 限流精度不…

計算機網絡1.1:計算機網絡在信息時代的作用

計算機網絡已由一種通信基礎設施發展成為一種重要的信息服務基礎設施。計算機網絡已經像水、電、煤氣這些基礎設施一樣&#xff0c;成為我們生活中不可或缺的一部分。

Component cannot be used as a JSX component

今天在使用 React Ts&#xff0c;使用 react-icons 這個庫的時候&#xff0c;遇到了這個問題&#xff1a;原因用一句話概括就是 Ts 的版本太低了&#xff01; 我的 package.json&#xff1a; {"name": "frontend","version": "0.1.0"…

Centos安裝最新docker以及ubuntu安裝docker

Centos安裝最新版本docker1.更新阿里源,更新之前先做備份mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup更新阿里源wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo2.運行 yum makecache 生成緩存…