【計算機考研(408)- 數據結構】樹與二叉樹

樹與二叉樹

樹的定義及相關概念

是n(n≥0)個結點的有限集合,n = 0時,稱為空樹,這是一種特殊情況。在任意一棵非空樹中應滿足:
1)有且僅有一個特定的稱為根的結點。
2)當n > 1時,其余結點可分為m(m > 0)個互不相交的有限集合T1, T2,…, Tm,其中每個集合本身又是一棵樹,并且稱為根結點的子樹
3)樹的根結點沒有前驅結點,其余結點有且僅有一個前驅結點。
4)樹中所有結點可以有零個或多個后繼結點。

樹的基本術語

結點之間的關系描述:則有:祖先結點子孫結點雙親結點孩子節點兄弟結點堂兄弟結點,以上完全可以按照樹的結構和親戚對應的關系很方便的區分。如圖所示:

樹的結點之間的關系

很明顯地可以了解到:B的子孫有EFKL,路徑上的ABE都是K的祖先結點,E是K的雙親(父結點),K是E的子孫結點(孩子),K和L具有相同的雙親E,因此K和L是兄弟結點。結點G和EFHIJ互為堂兄弟結點。(排得差不多了,自己領會吧)。

結點、樹的屬性描述:結點的層次(深度)——從上往下數(從根到該節點的深度,例如B的深度為2),結點的高度——從下往上數,以該結點為根的子樹的高度,例如D的高度為3,樹的高度(深度)——總共多少層,上圖樹高度為4,結點的度——有幾個孩子(分支),B度為2,D度為3,樹的度——各結點的度的最大值。

樹中度大于0的結點為分支結點,度為0的結點為葉子結點。在分支結點中,每個結點的分支數就是該結點的度。

有序樹——邏輯上看,樹中結點的各子樹從左至右是有次序的,不能互換。
無序樹——邏輯上看,樹中結點的各子樹從左至右是無次序的,可以互換。
路徑——路徑是由兩個節點之間所經過的結點序列構成的。
路徑長度——所經過的邊的個數。
森林——森林是m(m≥0)棵互不相交的樹的集合。 ^ac8bfc

樹的性質

證明我就不寫了,留給我自己去推。

  • 樹中的結點數等于所有結點的度數加1(加的是根)
  • 度為m的樹中第i層至多有mi?1m^{i-1}mi?1個結點
  • 高度為h的m叉樹至多有(mh?1)/(m?1)(m^h-1)/(m-1)(mh?1)/(m?1)個結點
  • 具有n個結點的m叉樹的最小高度為?logm(n(m?1)+1)?\lceil log_m(n(m-1)+1)\rceil?logm?(n(m?1)+1)?
  • 度為m、具有n個結點的樹最大高度為n?m+1n-m+1n?m+1
  • 高度為h的m叉樹至少有h個結點。高度為h、度為m的樹至少有h+m-1個結點。

二叉樹的定義及相關概念

二叉樹是n(n≥0)個結點的有限集合:
1)或者為空二叉樹,即n = 0。
2)或者由一個根結點和兩個互不相交的被稱為根的左子樹和右子樹組成。左子樹和右子樹又分別是一棵二叉樹。
特點:1. 每個結點至多只有兩棵子樹 2. 左右子樹不能顛倒(二叉樹是有序樹)。

二叉樹和度為2的有序樹的區別:

  1. 度為2的有序樹樹至少有3個結點,而二叉樹可以為空
  2. 度為2的有序樹的左右次序是相對于另一個孩子結點而言的,若某個結點只有一個孩子結點,則這個孩子結點就無須區分左右次序。而二叉樹不一樣。

幾種特殊的二叉樹

滿二叉樹

滿二叉樹:高度為h,且含有2h?12^h-12h?1個結點。每層都含有最多的結點。除了葉子結點度都為2。

特點:

  1. 有最后一層有葉子結點
  2. 存在度為1的結點
  3. 按層序從1開始編號,結點i的左孩子為2i,右孩子為2i+1;結點i的父節點為?i/2?\lfloor i/2 \rfloor?i/2?(如果有的話)

示例圖:

滿二叉樹示例|70%

完全二叉樹

完全二叉樹:當且僅當其每個結點都與高度為h的滿二叉樹中編號為1~n的結點一一對應時,稱為完全二叉樹。

有n個結點。特點如下:

  1. i≤?n/2?i \leq \lceil n/2 \rceili?n/2?,則結點 iii 為分支結點,否則為葉子結點。
  2. 只有最后兩層才會出現葉子結點。
  3. 最多只有一個度為 1 的結點(這種情況下該結點一定只有左孩子,沒有右孩子)。
  4. 按層序編號,若 iii 結點為葉子結點或只有左孩子,則編號大于 iii 的結點均為葉子結點。
  5. 同滿二叉樹的3.特點。

示例圖:

完全二叉樹示例|70%

完全二叉樹可以視作從滿二叉樹中刪去若干最底層、最右邊的一些連續葉節點所得到的二叉樹。

平衡二叉樹

平衡二叉樹:任意結點的左右子樹的深度之差不超過1。詳見

二叉排序樹

二叉排序樹:左子樹上所有結點均小于根結點的關鍵字;右子樹所有結點均大于根結點的關鍵字。左子樹和右子樹個是一棵二叉排序樹。詳見

正則二叉樹

正則二叉樹:樹中每個分支都有兩個孩子,即樹中只有度為0或2的結點。

二叉樹的性質

以下推導過程略,自己推。

  • 非空二叉樹的葉子結點數等于度為2的結點數加1,即n0=n2+1n_0=n_2+1n0?=n2?+1
  • 非空二叉樹第i層最多有2i?12^{i-1}2i?1個結點->m叉樹第i層最多有mi?1m^{i-1}mi?1個結點
  • 高度為h的二叉樹至多有2h?12^h-12h?1個結點(為一棵滿二叉樹)->高度為h的m叉樹至多有(mh?1)/(m?1)(m^h-1)/(m-1)(mh?1)/(m?1)個結點
  • 具有n個結點的完全二叉樹的高度?log2(n+1)?\lceil log_2(n+1)\rceil?log2?(n+1)??log2n?+1\lfloor log_2n\rfloor+1?log2?n?+1
  • 若完全二叉樹有2k個(偶數)個結點,則必有n1=1n_1=1n1?=1n0=kn_0 = kn0?=kn2=k?1n_2 = k-1n2?=k?1,若完全二叉樹有2k-1個(奇數)個結點,則必有n1=0n_1=0n1?=0n0=kn_0=kn0?=kn2=k?1n_2=k-1n2?=k?1(突破點:完全二叉樹最多只會有一個度為1的結點)

二叉樹的存儲結構

二叉樹的順序存儲結構

順序存儲結構:用一組地址連續的存儲單元一次自上而下、自左至右存儲完全二叉樹的結點元素。即完全二叉樹編號為i的結點元素存儲在某個數組下標為i-1的分量中。該結構對順序二叉樹和完全二叉樹比較合適。這種存儲結構要從數組下標1開始存儲數中的結點。

二叉樹的順序存儲中,一定要把二叉樹的結點編號與完全二叉樹對應起來,所以一定會有大量的空間被浪費掉。

基于以上特點如果用來存儲滿二叉樹完全二叉樹可能使用此方法較為適合。

二叉樹的順序存儲結構

二叉樹的鏈式存儲結構

由于順序存儲的空間利用率較低,所以我們一般都會采用鏈式存儲結構。用鏈表結點來存儲二叉樹的每個結點。如圖所示一個二叉樹鏈式存儲的結點結構。

二叉樹鏈式存儲的結點結構

二叉樹的鏈式存儲結構描述如下:

typedef struct BiTNode {ElemType data; // 結點數據struct BiTNode *lchild, *rchild; // 左右孩子指針
} BiTNode, *BiTree;

一顆二叉樹及其所對應的二叉鏈表如圖所示,展示了鏈式存儲結構:

一顆二叉樹及其所對應的二叉鏈表

當然也很容易知道,含有n個結點的二叉鏈表中,含有n+1個空鏈域。這為后面的線索二叉樹提供了方便。

二叉樹的遍歷

先序遍歷

先序遍歷:先訪問根結點,然后先序遍歷左子樹,最后先序遍歷右子樹。

實現:

void PreOrderTraverse(BiTree T) {if (T == NULL) return; // 遞歸終止條件visit(T); // 訪問根結點PreOrderTraverse(T->lchild); // 先序遍歷左子樹PreOrderTraverse(T->rchild); // 先序遍歷右子樹
}

中序遍歷

中序遍歷:先中序遍歷左子樹,然后訪問根結點,最后中序遍歷右子樹。

實現:

void InOrderTraverse(BiTree T) {if (T == NULL) return; // 遞歸終止條件InOrderTraverse(T->lchild); // 中序遍歷左子樹visit(T); // 訪問根結點InOrderTraverse(T->rchild); // 中序遍歷右子樹
}

后序遍歷

后序遍歷:先后序遍歷左子樹,然后后序遍歷右子樹,最后訪問根結點。

實現:

void PostOrderTraverse(BiTree T) {if (T == NULL) return; // 遞歸終止條件PostOrderTraverse(T->lchild); // 后序遍歷左子樹PostOrderTraverse(T->rchild); // 后序遍歷右子樹visit(T); // 訪問根結點
}

層次遍歷

層次遍歷:從根結點開始,按層次順序訪問結點。

實現:

void LevelOrderTraverse(BiTree T) {if (T == NULL) return; // 遞歸終止條件Queue<BiTree> q;//這里需要用到一個輔助隊列q.push(T);while (!q.empty()) {BiTree node = q.front();q.pop();visit(node);if (node->lchild != NULL) q.push(node->lchild);if (node->rchild != NULL) q.push(node->rchild);}
}

這里用到了之前已經學過的[[棧和隊列#隊列]]的知識,代碼里面用到了C++的隊列,如果是書上的,那么 push就是 EnQueuepop就是 DeQueue

算法效率分析與改造

不管是哪種算法,每個結點都訪問一次且僅訪問一次,故時間復雜度都是O(n)。

算法改造成為非遞歸算法時,通常需要借用[[棧和隊列#棧]]一個來存儲結點。如以下中序遍歷改造所示:

// 中序遍歷非遞歸算法,需要借用一個棧
void InOrder2(BiTree T){InitStack(S); BiTree p=T;  // p是遍歷指針while(p||!isEmpty(S)){if(p){Push(S,p);p=p->lchild;}else{Pop(S,p);visit(p);p=p->rchild;}}
}

利用遍歷序列構造一個二叉樹

給定先序遍歷和中序遍歷序列,可以唯一確定一棵二叉樹。先序遍歷的第一個元素是根結點,然后在中序遍歷中找到根結點的位置,左邊的部分是左子樹,右邊的部分是右子樹。

同理,給定后序遍歷和中序遍歷序列,也可以唯一確定一棵二叉樹。后序遍歷的最后一個元素是根結點,然后在中序遍歷中找到根結點的位置,左邊的部分是左子樹,右邊的部分是右子樹。

那么,給定層序和中序遍歷,也可以唯一確定一棵二叉樹。層序遍歷的第一個元素是根結點,然后在中序遍歷中找到根結點位置,左邊的部分是左子樹,右邊的部分是右子樹。

那么很顯然,先序、后序、層序倆倆組合無法唯一確定一棵二叉樹。

注:此節需要練習才能熟練掌握。

線索二叉樹

傳統的二叉樹,每個結點有兩個指針,分別指向左孩子和右孩子。不能直接得到結點在遍歷過程中的前驅和后繼結點。為了解決這個問題,引入了線索二叉樹。

在前面的內容中我們知道:在含有n個結點的二叉樹中,含有n+1個空鏈域。線索二叉樹就是利用這些空鏈域來存儲結點的前驅和后繼信息。

線索二叉樹規定:若無左子樹,令lchild指向其前驅結點;若無右子樹,令rchild指向其后繼結點。如圖所示為線索二叉樹的結點結構

線索二叉樹的結點結構

其中標志域lflagrflag用來標識指針域是指向孩子結點還是前驅/后繼結點。

{lflag=0表示?lchild指向孩子結點lflag=1表示?lchild指向前驅結點rflag=0表示?rchild指向孩子結點rflag=1表示?rchild指向后繼結點\begin{array}{l} \left\{ \begin{aligned} &\text{lflag}=0 \text{ 表示 } lchild \text{ 指向孩子結點} \\ &\text{lflag}=1 \text{ 表示 } lchild \text{ 指向前驅結點} \\ &\text{rflag}=0 \text{ 表示 } rchild \text{ 指向孩子結點} \\ &\text{rflag}=1 \text{ 表示 } rchild \text{ 指向后繼結點} \\ \end{aligned} \right. \end{array} ?????lflag=0?表示?lchild?指向孩子結點lflag=1?表示?lchild?指向前驅結點rflag=0?表示?rchild?指向孩子結點rflag=1?表示?rchild?指向后繼結點??

那么線索二叉樹的存儲結構描述如下:

typedef struct ThreadNode {ElemType data; // 結點數據struct ThreadNode *lchild, *rchild; // 左右孩子指針int lflag, rflag; // 標志域
} ThreadNode, *ThreadTree;

線索二叉樹的構造:遍歷一次二叉樹,只是在遍歷的過程中,檢查當前結點的左右指針域是否為空,若為空,將它們改為指向前驅結點或后繼結點的線索。代碼:

// 創建中序線索二叉樹
void CreateInThread(ThreadTree T) {ThreadTree pre = NULL; // pre用于記錄當前結點的前驅if (T != NULL) {InThread(T, pre);      // 對二叉樹進行中序線索化pre->rchild = NULL;    // 最后一個結點的后繼線索置空pre->rtag = 1;         // rtag=1表示rchild為線索}
}// 中序遍歷遞歸線索化
void InThread(ThreadTree &p, ThreadTree &pre) {if (p != NULL) {InThread(p->lchild, pre); // 遞歸線索化左子樹// 若左子樹為空,則lchild指向前驅pre,ltag=1if (p->lchild == NULL) {p->lchild = pre;p->ltag = 1;}// 若前驅結點的右子樹為空,則rchild指向當前結點,rtag=1if (pre != NULL && pre->rchild == NULL) {pre->rchild = p;pre->rtag = 1;}pre = p; // 更新前驅為當前結點InThread(p->rchild, pre); // 遞歸線索化右子樹}
}

先序線索化:

void CreatePreThread(ThreadTree T) {ThreadTree pre = NULL; // pre用于記錄當前結點的前驅if (T != NULL) {PreThread(T, pre);      // 對二叉樹進行先序線索化if(pre->rchild == NULL) {//這里我有點疑問,可能他和中序線索化一樣也不是不行,因為先和中的pre->rchild一定是NULL。pre->rtag = 1;      // rtag=1表示rchild為線索}}
}
// 先序遍歷遞歸線索化
void PreThread(ThreadTree p, ThreadTree &pre) {if (p != NULL) { //左子樹為空,建立線索if(p->lchild == NULL){p->lchild = pre;p->ltag = 1;}if(pre != NULL && pre->rchild == NULL){pre->rchild = p;pre->rtag = 1;}pre = p;//我們前面介紹過,如果p的左子樹為空,則建立p為左孩子,所以判斷p的左子樹代表的是否為線索if(p->ltag == 0) {PreThread(p->lchild, pre); // 遞歸線索化左子樹}PreThread(p->rchild, pre); // 遞歸線索化右子樹}
}

后序線索化:

void CreatePostThread(ThreadTree T) {ThreadTree pre = NULL; // pre用于記錄當前結點的前驅if (T != NULL) {PostThread(T, pre);      // 對二叉樹進行后序線索化if(pre->rchild == NULL) {pre->rtag = 1;      // rtag=1表示rchild為}}
}
// 后序遍歷遞歸線索化
void PostThread(ThreadTree p, ThreadTree &pre) {if (p != NULL) {PostThread(p->lchild, pre);PostThread(p->rchild, pre);if (p->lchild == NULL) {p->ltag = 1;p->lchild = pre; // 左子樹為空,建立線索}if (pre != NULL && pre->rchild == NULL) {pre->rtag = 1;pre->rchild = p;}pre=p;}
}

帶有頭結點的線索二叉樹

如圖(此為中序):

帶有頭結點的線索二叉樹

他的指向關系在圖中很明確,這樣做的好處就是能夠很方便的從前往后或者從后往前對線索二叉樹進行一個遍歷。

線索二叉樹的遍歷

線索二叉樹的遍歷:利用線索二叉樹,可以實現二叉樹遍歷的非遞歸算法。

以中序遍歷找后繼為例,代碼如下:

void Inorder(ThreadNode *T) {for (ThreadNode *p = Firstnode(T); p != NULL; p = Nextnode(p))visit(p); // 訪問結點
}
ThreadNode *Firstnode(ThreadNode *p) {while (p->ltag == 0) p = p->lchild; //找到最左下結點return p;
}
ThreadNode *Nextnode(ThreadNode *p) {if (p->rtag == 0) return Firstnode(p->rchild);else return p->rchild; // 返回后繼結點
}

對于中序線索二叉樹的遍歷,可以使用上述的實現方式,只需變化一些條件,具體可以練習。

對于先序和后序線索二叉樹的遍歷,類似的實現方式也可以使用。

樹和森林

樹的存儲結構

雙親表示法

采用一組連續空間來存儲每個結點,同時每個結點中增設一個偽指針,指示其雙親結點在數組中的位置。可以很快得到每個結點的雙親結點,但求結點的孩子時需要遍歷整個結構。

樹的雙親表示法

存儲結構描述:

#define MAX_TREE_SIZE 100 // 定義樹的最大結點數
typedef struct {ElemType data; // 結點數據int parent; // 雙親結點的下標
} PTNode; // 雙親結點結構
typedef struct {PTNode nodes[MAX_TREE_SIZE]; // 存儲結點的數組int n; // 結點數
} PTree; // 雙親表示法的樹結構

雙親表示法表示一個森林:每棵樹的根節點雙親指針= -1

孩子表示法

將每個結點的孩子結點都用單鏈表連接起來形成一個線性結構,n個結點就有n個孩子鏈表。尋找子女操作非常直接,而尋找雙親需要遍歷n個結點中孩子鏈表指針域所指向的n個孩子鏈表

樹的孩子表示法

孩子表示法表示一個森林:用孩子表示法存儲森林,需要記錄多個根的位置

孩子兄弟表示法

又稱二叉樹表示法,即以二叉鏈表作為樹的存儲結構。每個結點分為三部分:結點值、指向結點第一個孩子節點的指針,指向結點下一個兄弟結點的指針。優點是可以方便地實現樹轉換為二叉樹的操作,易于查找結點的孩子等。缺點是查找雙親麻煩

孩子兄弟表示法

存儲結構描述:

typedef struct CSNode {ElemType data; // 結點數據struct CSNode *firstchild; // 指向第一個孩子結點的指針struct CSNode *nextsibling; // 指向下一個兄弟結點的指針
} CSNode, *CSTree; // 孩子兄弟表示法

樹、森林轉化成二叉樹

樹轉換為二叉樹的規則:每個結點左指針指向它的第一個孩子結點,右指針指向它在樹中相鄰的兄弟節點,“左孩子右兄弟”,由樹轉換的二叉樹沒有右子樹。

森林轉換為二叉樹:先將森林中的每棵樹轉換為二叉樹,把第一棵樹的根作為轉換后二叉樹的根,其左子樹作為左子樹。第二棵樹作為轉換后的右子樹,第三棵樹作為轉換后右子樹的右子樹,即向右拼接。

二叉樹轉換為森林/樹的規則:反過來即可。將右子樹挨個拆下來。二叉樹轉換為樹或森林是唯一的。

樹和森林的遍歷

樹和森林遍歷與二叉樹遍歷之前的對應關系

森林二叉樹
先根遍歷先序遍歷先序遍歷
后根遍歷后序遍歷中序遍歷

樹與二叉樹的應用

哈夫曼樹和哈夫曼編碼

結點的:有某種現實含義的數值(如:表示結點的重要性等)
結點的帶權路徑長度:從樹的根到該結點的路徑長度(經過的邊數)與該結點上權值的乘積
樹的帶權路徑長度:樹中所有葉結點的帶權路徑長度之和(WPL, Weighted Path Length)
WPL=∑i=1nwi?liWPL=\sum_{i=1}^{n} w_i \cdot l_iWPL=i=1n?wi??li?

在含有n個帶權葉節點的二叉樹中,其中帶權路徑長度(WPL)最小的二叉樹稱為哈夫曼樹(Huffman Tree),也稱為最優二叉樹。

例題:

具有不同帶權長度的二叉樹

由此算得:

WPLa=7?2+5?2+2?2+4?2=36WPL_a=7*2+5*2+2*2+4*2=36WPLa?=7?2+5?2+2?2+4?2=36
WPLb=7?3+5?3+2?1+4?2=46WPL_b=7*3+5*3+2*1+4*2=46WPLb?=7?3+5?3+2?1+4?2=46
WPLc=7?1+5?2+2?3+4?3=35WPL_c=7*1+5*2+2*3+4*3=35WPLc?=7?1+5?2+2?3+4?3=35(哈夫曼樹)

構造方式:簡單說,從結點中選出兩個最小的結點,構成一個新節點,權為兩結點之和,重復直到所有結點都處理完畢。

哈夫曼編碼就是左0右1,那么a=0 ;b=10;c=110;d=111。

哈夫曼編碼的特點是:沒有一個編碼是另一個編碼的前綴,這樣可以保證編碼的唯一性。

并查集

并查集的概念及其實現

并查集是一種簡單的集合表示,它支持以下操作:Initialize(初始化)、Find(查找)、Union(合并)。

并查集的存儲結構

通常用樹的雙親表示作為并查集的存儲結構,每個子集合以一棵樹表示。多說無益,直接看示意圖:

假設有一個S={0,1,2,3,4,5,6,7,8,9,10},初始化他們都是一個個的幾個,每個子集合的數組值為-1。

初始表示:

初始

經過系列計算以后,他們合并成為了三個集合:S1={0,6,7,8}S_1=\{0,6,7,8\}S1?={0,6,7,8}S2={1,4,9}S_2=\{1,4,9\}S2?={1,4,9}S3={2,3,5}S_3=\{2,3,5\}S3?={2,3,5}

計算1

又計算,想把S1S_1S1?S2S_2S2?合并

計算2

結束,很一目了然的并查集

并查集操作的基本實現
#define MAX_SIZE 100 // 并查集的最大大小
int UFSets[MAX_SIZE];// 并查集數組(雙親表示法)
//初始化
void InitUFSets()
{for (int i = 0; i < MAX_SIZE; i++) UFSets[i] = -1; // 每個元素初始化為-1,表示每個元素都是一個獨立的集合
}
//Find 找到集合的根元素
int Find(int x)
{while (UFSets[x] >= 0) x = UFSets[x];return x;
}
//Union 合并兩個集合
void Union(int Root1, int Root2)
{if (Root1 != Root2) {//要求Root1和Root2是不同的集合UFSets[Root2] = Root1; // 將Root2的根元素指向Root1,表示合并}
}

注意:本代碼并沒有傳遞數組參數,因為只是一整個代碼,已經放在全局變量中,遇到題目需要自行分析。
復雜度分析:Find操作的時間復雜度為O(d)O(d)O(d)(d為樹深度),Union操作的時間復雜度為O(1)。

并查集之優化
//改進后的Union
void Union(int Root1, int Root2) {if(Root1 != Root2) { //要求Root1和Root2是不同的集合if (UFSets[Root1] < UFSets[Root2]) { // Root1的集合更大UFSets[Root1] += UFSets[Root2]; // 更新Root1的大小UFSets[Root2] = Root1; // 將Root2的根元素指向Root1} else {UFSets[Root2] += UFSets[Root1]; // 更新Root2的大小UFSets[Root1] = Root2; // 將Root1的根元素指向Root2}}
}
//改進后的Find,目的在于壓縮路徑,只要是根的元素,就把他掛在根元素上。
int Find(int x) {int root = x;while(UFSets[root] >= 0) {root = UFSets[root]; // 找到根元素}while(x!=root){int temp = UFSets[x]; // 臨時存儲當前元素的父節點UFSets[x] = root; // 路徑壓縮,將當前元素直接指向根元素x = temp; // 移動到下一個元素}return root;
}

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

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

相關文章

MacOS:如何利用終端來操作用戶

MacOS&#xff1a;如何利用終端來操作用戶MacOS&#xff1a;如何利用終端來操作用戶1. 創建用戶并賦予管理員權限步驟&#xff1a;2. 取消用戶的管理員權限解釋&#xff1a;3. 查看組成員查看 admin 組成員&#xff1a;查看 users 組成員&#xff1a;4. 其他常見的用戶管理命令…

基于SpringBoot+MyBatis+MySQL+VUE實現的醫療掛號管理系統(附源碼+數據庫+畢業論文+答辯PPT+項目部署視頻教程+項目所需軟件工具)

摘 要 在如今社會上&#xff0c;關于信息上面的處理&#xff0c;沒有任何一個企業或者個人會忽視&#xff0c;如何讓信息急速傳遞&#xff0c;并且歸檔儲存查詢&#xff0c;采用之前的紙張記錄模式已經不符合當前使用要求了。所以&#xff0c;對醫療掛號信息管理的提升&#x…

學成在線項目

黑馬程序員學成在線項目學習過程記錄 解決跨域問題

Shell腳本-grep工具

一、前言在 Linux/Unix 系統中&#xff0c;grep 是一個非常強大且常用的文本搜索工具&#xff0c;它可以幫助我們快速從文件或標準輸入中查找匹配特定模式的內容。無論是查看日志、調試腳本&#xff0c;還是進行自動化數據提取&#xff0c;grep 都扮演著至關重要的角色。本文將…

深入解析Ext2文件系統架構

要在硬盤上存儲文件&#xff0c;必須先將硬盤格式化為特定類型的文件系統。文件系統的主要功能就是組織和管硬盤中的文件。在Linux系統中&#xff0c;最常見的文件系統是Ext2系列&#xff0c;其早期版本為Ext2&#xff0c;后續又發展出Ext3和Ext4。雖然Ext3和Ext4對Ext2進行了功…

商業秘密保護:從法律理論到企業實戰

作者&#xff1a;邱戈龍、柯堅豪深圳商業秘密律師廣東長昊律師事務所在商業競爭中&#xff0c;商業秘密就像企業的"隱形護城河"。從法律角度看&#xff0c;它的保護路徑經歷了三次重要升級&#xff1a;從最初的"合同約定"到后來的"財產保護"&…

AI產品經理面試寶典第36天:AI+旅游以及行業痛點相關面試題的指導

一、AI如何解決旅游行業核心痛點? 面試官提問: "請結合具體案例說明AI在旅游行業的應用價值,以及它如何解決傳統旅游服務的痛點?" 你的回答: 以騰訊"一部手機游云南"為例,AI技術通過四大核心體系重構旅游體驗: 數字身份體系:通過人臉識別與用戶…

【conda】Linux系統中部署Conda環境

目錄 一、安裝 Miniconda 1.1 下載 Miniconda 安裝腳本 1.2 運行安裝腳本 1.3 初始化 Conda&#xff1a; 安裝完成后&#xff0c;初始化 Conda 環境 1.4 驗證安裝 二、設置虛擬環境默認存放路徑&#xff08;可選&#xff09; 三、conda創建虛擬環境 3.1 創建 Conda 環境…

Spring Boot 解決跨域問題

在 Spring Boot 中解決跨域問題&#xff08;CORS&#xff09;主要有三種常用方式&#xff0c;下面詳細說明每種實現方法&#xff1a; 方案一&#xff1a;全局配置&#xff08;推薦&#xff09; 在配置類中實現 WebMvcConfigurer 接口&#xff0c;統一配置所有接口的跨域規則&am…

Softhub軟件下載站實戰開發(十九):軟件信息展示

上一篇文章中我們上線了軟件分離展示&#xff0c;本篇文章我們聚焦軟件信息展示 軟件列表信息展示 點擊一級分類查詢該分類下所以軟件分類切換要有動畫效果分頁支持 核心實現 <transition-grouptag"div"class"software-grid"before-enter"before…

[HDLBits] Cs450/gshare

Branch direction predictor 分支方向預測器 A branch direction predictor generates taken/not-taken predictions of the direction of conditional branch instructions. It sits near the front of the processor pipeline, and is responsible for directing instructio…

[學習] 雙邊帶調制 (DSB) 與單邊帶調制 (SSB) 深度對比

雙邊帶調制 (DSB) 與單邊帶調制 (SSB) 深度對比 文章目錄雙邊帶調制 (DSB) 與單邊帶調制 (SSB) 深度對比**數學原理****調制表達式與頻譜****時域特性****頻域特性****Python 仿真代碼****仿真結果分析****工程應用建議**數學原理 設基帶信號為 m(t)m(t)m(t)&#xff08;帶寬為…

Gitee 提交信息的規范

在使用 git push 命令將代碼推送到 Gitee&#xff08;或任何 Git 平臺&#xff09;時&#xff0c;引號中的信息通常指的是 提交信息&#xff08;Commit Message&#xff09;。提交信息是對本次代碼修改的簡要描述&#xff0c;規范的提交信息有助于團隊協作和版本管理。 Gitee 提…

C 語言經典編程題實戰:從基礎算法到趣味問題全解析

在 C 語言學習過程中&#xff0c;通過實戰編程題鞏固知識點是非常有效的方式。本文整理了一系列經典 C 語言編程題&#xff0c;涵蓋基礎計算、邏輯判斷、圖形打印等多個維度&#xff0c;并附上完整代碼與解析&#xff0c;適合初學者參考學習上機題1.計算n以內所有正奇數的和 ?…

Chapter 3 Design of Switching Power Regulators

Chapter 3 Design of Switching Power Regulators Power Management Techniques for Integrated Circuit Design by Ke-Horng Chen 這本書比較深, 簡單介紹基本概念后, 就直接拋出大段公式和結論, 一章講其他書幾章內容, 適合有一定基礎, 想進一步做電源系統的人查閱. 優點是不…

算法題(176):three states

審題&#xff1a; 本題需要我們找到最佳鋪設道路&#xff0c;將三個國家聯通起來&#xff0c;然后輸出最佳鋪設道路的鋪設數量&#xff0c;若沒有聯通方法則輸出-1 思路&#xff1a; 首先我們正面思考&#xff1a;只需從某個點出發然后搜索到三個國家即可&#xff0c;最后對比所…

BIOS+MBR微內核加載loader程序實現過程

上一篇講到的微內核程序是由BIOS例程自動加載到內存中運行的,而且大小有限,能做的事情有限。我們知道內核程序大小是可以擴展的不能只有512字節,同時在加載運行內核前還需要完成一些必要的實模式下才能做的準備工作。所以單純在實模式下只使用微內核程序是不太夠的,就有了加…

使用Proxy設計模式來增強類的功能:ToastProxy和DesktopToast的設計關系

使用代理模式來增強類的功能&#xff1a;ToastProxy和DesktopToast Documentation: v1.0.0 Specified for Version v1.12.0&#xff0c;First Release in 2025/7/12 Documenation belongs to Projects: Charliechen114514/CCIMXDesktop: This is a Simple Desktop with Common …

瑞芯微2025開發者大會之見聞

序言本人參加了2025年的瑞芯微開發者大會&#xff0c;在展覽區看到了很多有意思的音視頻產品&#xff0c;下面按照產品類型分類給大家做一下展示。期間并沒有將所有展出物進行拍攝&#xff0c;但是基本已經覆蓋大部分內容。1、RK3566該芯片內置DSP音頻處理器&#xff0c;藍牙5.…

【最新】Java的幾種設計模式詳解及適用業務場景

? 1. 單例模式&#xff08;Singleton&#xff09; 定義&#xff1a;確保類只有一個實例&#xff0c;并提供全局訪問點。優點&#xff1a;節省資源、控制訪問。場景&#xff1a;數據庫連接池、日志管理器、配置中心。代碼要點&#xff1a; 構造方法私有靜態變量保存唯一實例公共…