本文章寫的比較亂,屬于是縫合怪,很多細節沒處理,顯得粗糙,日后完善,今天趕時間了。
1. 紅黑樹的修復篇章
2. 紅黑樹的代碼理解(部分寫道注釋之中了)
3. 隊列與棧的代碼
4. 重要是理解物理邏輯,從而理解代碼邏輯
目錄
一 鏈表
1. 單向鏈表
2. 雙向鏈表
雙向鏈表的操作(c語言)
1. linked_list_common.h
2. link.c
3. main.c
3. 循環列表
1. 單向循環列表
2. 雙向循環列表
4. 靜態鏈表
二 棧(stack)(代碼暫不演示)
三 隊列(queue) (代碼暫不演示)
四 樹(tree)
1. 二叉樹(Binary Tree)
2. 二叉搜索樹(BST)
3. AVL 樹
4. B 樹
5. 紅黑樹
1. red_black_common.h
2.?red_black_tree.c
3. main.c
4. 總結
1. 左右旋
2. 修復(變色,左右旋轉)
一 鏈表
鏈表(Linked List) 是一種線性數據結構,由一系列節點(Node)通過指針鏈接而成。與數組不同,鏈表的元素在內存中非連續存儲,每個節點獨立分配內存
類型 方向性 內存開銷 適用場景 單向鏈表 單向 低 簡單數據管理(如棧、隊列) 雙向鏈表 雙向 高(2指針) 頻繁雙向遍歷(如瀏覽器歷史記錄) 循環鏈表 環狀 同單向/雙向 輪詢任務、循環緩沖區 靜態鏈表 單向/雙向 固定數組 無動態內存環境(如嵌入式開發)
單向鏈表:
實現棧(LIFO)、隊列(FIFO)。
輕量級數據集合管理(如學生成績表)。
雙向鏈表:
瀏覽器前進/后退功能。
文本編輯器的撤銷/重做操作。
循環鏈表:
操作系統進程調度(時間片輪轉)。
音樂播放器的循環播放列表。
靜態鏈表:
內存受限的嵌入式系統。
預分配固定內存池的實時系統。
(此處重點且詳細的說雙向列表,雙向列表會了之后,其余兩個也就差不多了)
1. 單向鏈表
結構定義
每個節點包含?數據域?和?指向下一個節點的指針。
C語言結構體:
typedef struct SNode {int data; // 數據域struct SNode *next; // 指向下一節點的指針 } SNode;
特點:
單向遍歷,只能從頭節點開始訪問后續節點。
插入/刪除操作需定位前驅節點。
示例操作:
// 在頭節點后插入新節點 void insertAtHead(SNode **head, int val) {SNode *newNode = (SNode*)malloc(sizeof(SNode));newNode->data = val;newNode->next = *head;*head = newNode; }
2. 雙向鏈表
結構定義
每個節點包含?數據域、指向前驅節點的指針?和?指向后繼節點的指針。
C語言結構體:
typedef struct linked_list_node {// 節點數據void *data; // 8位// pre節點指針,指向的是前一個節點 8位struct linked_list_node *prev;// next指針指向的是下一個節點 8位struct linked_list_node *next;} node;// 2.定義鏈表-結構體,此結構點表示的是 typedef struct {// 頭結點node *head;// 尾節點node *tail;// 節點的個數int size;} linked_list;
特點:
支持雙向遍歷(從頭到尾或從尾到頭)。
插入/刪除操作更高效(可直接訪問前驅和后繼)。
雙向鏈表的操作(c語言)
包含了前插插入,后插插入,中間插入,刪除,查找等等
1. linked_list_common.h
#ifndef LINKED_LIST_COMMON
#define LINKED_LIST_COMMON/*雙向鏈表結構節點表示首節點 前去節點 數據 后區節點*/// 節點聲明,數據在次結構體,總體長度為24
typedef struct linked_list_node
{// 節點數據void *data; // 8位// pre節點指針,指向的是前一個節點 8位struct linked_list_node *prev;// next指針指向的是下一個節點 8位struct linked_list_node *next;} node;// 2.定義鏈表-結構體,此結構點表示的是
typedef struct
{// 頭結點node *head;// 尾節點node *tail;// 節點的個數int size;} linked_list;// 3.創建一個節點需要自己開辟空間,即使用上的nide指針的
node *create_node(void *data);// 4.初始化鏈表
void init_linked_list(linked_list *list);// 中間插入
void insert_after(linked_list *list, node *prev, void *data);// 人為規定當前案例 都放入int類型數據
// 整數int類型比較函數
int compare_int(void *a, void *b);// 添加 prepend 和 append 的聲明
void prepend(linked_list *list, void *data);
void append(linked_list *list, void *data);// 在鏈表中查找特定數據的節點,插入必須先查找對應的節點
node *search_node(linked_list *list, void *data, int (*compare)(void *, void *));// 示例:打印int數據鏈表的內容
void print_int_linked_list(linked_list *list);// 刪除節點,進行三次判斷,判斷是否為頭節點,判斷是否為節點,否則就是中間節點,然后寫出每個刪除的邏輯
// 邏輯結束后,釋放所被刪除的內存空間
void delete_node(linked_list *linked, node *node);// last.清空鏈表
void clean_linked_list(linked_list *list);#endif
2. link.c
#include <stdio.h>
#include <stdlib.h>
#include "../inc/linked_list_common1.h"/*在此處定義
*/
// 1.創建一個節點需要自己開辟空間,即使用上的nide指針的
node *create_node(void *data)
{// 創建空間,準備存取數據,別忘記了釋放空間// calloc(1, sizeof(node))由于calloc創建的是一個沒有類型的類型的數據,需要給強轉成相對應的類型嗯node *new_node = (node *)calloc(1, sizeof(node));// 如果內存無法開辟,即沒有足夠大的空間,會導致開辟失敗if (new_node == NULL){printf("內存溢出,創建節點失敗\n");exit(EXIT_FAILURE); // 異常退出}// 如果空間可以開辟,則使用結構體指針將其賦初始值new_node->data = data;new_node->prev = NULL;new_node->next = NULL;return new_node;
}// 2.初始化鏈表,因為暫時沒有數據
void init_linked_list(linked_list *list)
{// 頭結點list->head = NULL;// 尾節點list->tail = NULL;// 鏈表的節點個數list->size = 0;
}
// 7.在鏈表的中間插入節點。三個參數,即為,列表,前驅節點為參數,和數據
void insert_after(linked_list *list, node *prev, void *data)
{// 上一個節點的pre指向上上個數據,next指向下一個數據,要在中間插入一個數據的話,既要改變上一個節點的next,也要改變下一個節點的prev// 即在于找到一個prev即可找到上一個節點的next// 7.1判斷要插入的prev的節點是否為null,沒有的話,找不到前一個數據,無法插入if (prev == NULL){printf("前驅節點不能為NULL...\n");return; // 結束程序}// 7.2創建新節點 ,此節點就是要被插入的節點,node *new_node = create_node(data);// 7.3 修改新節點的prev和next指針,修改新節點的直接前驅指針,新節點的直接后繼指針為 直接前驅的nextnew_node->prev = prev;new_node->next = prev->next;// 7.4 prev為尾節點,更新新節點為新的尾節點if (prev->next == NULL){list->tail = new_node;}else{// prev不是尾節點,更新prev舊的后繼節點的prev指針指向新節點prev->next->prev = new_node;}// 設置prev的next指針指向新節點prev->next = new_node;// 鏈表節點個數+1list->size++;
}// 在鏈表頭部插入數據
void prepend(linked_list *list, void *data)
{node *new_node = create_node(data);if (list->head == NULL){// 如果鏈表為空,頭尾節點都指向新節點list->head = new_node;list->tail = new_node;}else{// 鏈表非空,更新頭節點new_node->next = list->head;list->head->prev = new_node;list->head = new_node;}list->size++;
}// 在鏈表尾部插入數據
void append(linked_list *list, void *data)
{node *new_node = create_node(data);if (list->tail == NULL){// 如果鏈表為空,頭尾節點都指向新節點list->head = new_node;list->tail = new_node;}else{// 鏈表非空,更新尾節點new_node->prev = list->tail;list->tail->next = new_node;list->tail = new_node;}list->size++;
}// 人為規定當前案例 都放入int類型數據
// 整數int類型比較函數
int compare_int(void *a, void *b)
{// 比較數值相減是否為0,0則表示相同return *(int *)a - *(int *)b;
}// 在鏈表中查找特定數據的節點,插入必須先查找對應的節點,容納后才能執行中間插入操作,
// 即必須要知道前一個節點的位置,即他的prev
node *search_node(linked_list *list, void *data, int (*compare)(void *, void *))
{// 首先必須要從list的head開始遍歷,此處名稱為迭代,先獲取list的head的節點node *current = list->head;// 遍歷列表,查找節點while (current != NULL){// 比較函數返回0,表示兩個值相等if (compare(current->data, data) == 0){// 返回找到的節點return current;}// 繼續比較下一個節點current = current->next;}// 如果循環結束都沒有找到數據對應的節點,說明該鏈表不存在該數據return NULL;
}// 示例:打印int數據鏈表的內容,全部內容,其作用與查找節點一樣
void print_int_linked_list(linked_list *list)
{// 獲取頭結點node *current = list->head;printf("雙向鏈表內容:\n");// 迭代器遍歷while (current != NULL){printf("%d ", *(int *)current->data);// 繼續下一個current = current->next;}printf("\n");printf("此時鏈表總共有%d個節點\n", list->size);
}// 刪除節點,此處有帶商榷
void delete_node(linked_list *list, node *node)
{// 判斷節點不能為空if (node == NULL){printf("節點不能為空\n");return;}// 判斷是否為頭節點if (node == list->head){ // 如果是頭節點,則使其下一個節點的list->head = node->next;if (list->head != NULL){list->head->prev = NULL;}else{// 如果刪除后鏈表為空,更新尾節點list->tail = NULL;printf("本次刪除的為頭節點%d\n", *(int *)node->data);}}// 判斷是否為尾節點else if (node == list->tail){list->tail = node->prev;if (list->tail != NULL){list->tail->next = NULL;}else{// 如果刪除后鏈表為空,更新頭節點list->head = NULL;printf("本次刪除的為尾節點%d\n", *(int *)node->data);}}// 中間節點else{node->prev->next = node->next;node->next->prev = node->prev;printf("本次刪除的為中部節點%d\n", *(int *)node->data);}// 釋放節點內存free(node);list->size--;
}// last.清空鏈表
void clean_linked_list(linked_list *list)
{// 獲取頭結點,先用上一個節點找到下一個節點,然后刪除上一個節點node *current = list->head;// 迭代器 獲取節點,釋放節點空間 利用迭代循環找到節點釋放空間while (current != NULL){// 頭結點不為Nullnode *temp = current;// 獲取下一個節點current = current->next;// 釋放節點的內存空間free(temp);}// 頭結點list->head = NULL;// 尾節點list->tail = NULL;// 鏈表的節點個數list->size = 0;
}
3. main.c
#include <stdio.h>
#include <stdlib.h>
#include "../inc/linked_list_common1.h"int main(int argc, char const *argv[])
{// 1.初始化鏈表linked_list list; // 聲明開辟內存init_linked_list(&list);// 2.在鏈表頭部插入數據int a = 10, b = 20, c = 30;prepend(&list, &a);prepend(&list, &b);prepend(&list, &c);// 打印print_int_linked_list(&list);// 3.在鏈表尾部插入數據int e = 40, f = 50;append(&list, &e);append(&list, &f);// 打印print_int_linked_list(&list);// 4.在鏈表中間插入數據// 4.1查找某個節點int g = 60;node *prev = search_node(&list, &c, compare_int);insert_after(&list, prev, &g);// 打印print_int_linked_list(&list);// 刪除節點// 查找要刪除的節點,node *target_node = search_node(&list, &a, compare_int);if (target_node != NULL){delete_node(&list, target_node);}else{printf("未找到要刪除的節點\n");}print_int_linked_list(&list);// last.清空鏈表clean_linked_list(&list);return 0;
}
3. 循環列表
特點:
無明確的頭尾界限,適合循環訪問場景(如輪詢調度)。
1. 單向循環列表
結構定義
單向循環鏈表:尾節點的?
next
?指針指向頭節點。
2. 雙向循環列表
結構定義
雙向循環鏈表:頭節點的?
prev
?指向尾節點,尾節點的?next
?指向頭節點。
4. 靜態鏈表
結構定義
使用數組模擬鏈表,節點通過數組下標鏈接。
特點:
無需動態內存分配,適用于不支持指針的環境(如嵌入式系統)。
內存固定,無法動態擴展。
二 棧(stack)(代碼暫不演示)
定義:后進先出(LIFO)的線性結構,僅允許在棧頂操作。
核心操作:
push
:入棧。
pop
:出棧。
peek
:查看棧頂元素。隊列,和棧比較相似,特殊的線性表(執行先進先出,誰頭誰尾,有待商榷)
循環隊列:
鏈式隊列:數據與 指針域
需要根據結構圖來重新模擬一下結構體的創建的理念
首先明白一點,我大概都懂他們的邏輯結構關系,我也知道他們的指針其什么作用
?1.明白隊列的物理結構關系
2.根據物理結構關系來定義結構體(結構體為何有兩個,兩個分別是什么作用,為和不創建一個)
3.根據物理結構來定義這個數據結構,使用函數寫出,讓這個鏈表成為隊列,即數據結構在c語言中并不是一種真正的結構,而是人為定義的,因為人類需要使用這種結構,例如現實問題,排隊進游樂場等等
三 隊列(queue) (代碼暫不演示)
定義:先進先出(FIFO)的線性結構,隊尾插入,隊頭刪除。
核心操作:
enqueue
:入隊。
dequeue
:出隊。
front
:查看隊頭元素。重難點:
棧空判斷:出棧前必須檢查?
top
?是否為?NULL
(否則導致未定義行為)。內存安全:出棧后必須釋放節點內存。
應用場景:
函數調用棧(遞歸實現)。
括號匹配、表達式求值。
結構體:
// 1.定義隊列中節點的 typedef struct queue_node {// 數據域void *data;// 指針域struct queue_node *next; } node;// 2.定義隊列的結構體 typedef struct {// 對首節點node *front;// 對尾節點node *rear;// 隊列中節點的個數int size; } queue;
四 樹(tree)
樹(Tree)是一種非線性數據結構,由節點(Node)和邊(Edge)組成,滿足以下條件:
每個樹有且僅有一個根節點(Root)。
除根節點外,每個節點有且僅有一個父節點。
從根節點到任意節點有唯一路徑。
1. 二叉樹(Binary Tree)
定義:每個節點最多有 2 個子節點(左和右)。
特點:結構簡單,適合遞歸操作。
應用:表達式樹、哈夫曼編碼。
C 代碼結構:
typedef struct TreeNode {int data;struct TreeNode* left;struct TreeNode* right; } TreeNode;
2. 二叉搜索樹(BST)
定義:左子樹所有節點值 < 根節點值 < 右子樹所有節點值。
特點:中序遍歷結果為有序序列。
應用:動態數據排序、字典。
插入代碼:
TreeNode* insertBST(TreeNode* root, int val) {if (root == NULL) {TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));node->data = val;node->left = node->right = NULL;return node;}if (val < root->data) root->left = insertBST(root->left, val);else root->right = insertBST(root->right, val);return root; }
3. AVL 樹
定義:平衡二叉搜索樹,任意節點左右子樹高度差 ≤ 1。
特點:通過旋轉(左旋/右旋)保持平衡。
應用:數據庫索引、實時高頻查詢。
結構擴展:
typedef struct AVLNode {int data;int height;struct AVLNode *left, *right; } AVLNode;
4. B 樹
定義:多路平衡搜索樹,每個節點可包含多個鍵和子節點。
特點:減少磁盤 I/O,適合大規模數據。
應用:文件系統、數據庫存儲。
5. 紅黑樹
定義:自平衡二叉搜索樹,通過顏色標記和規則保持平衡。
特點:插入/刪除效率高,廣泛用于庫函數(如 C++ STL)。
規則:
節點是紅或黑。
根和葉子(NIL)是黑。
紅節點的子節點必為黑。(即紅不能連續)
任意節點到葉子的路徑包含相同數量黑節點。
??? 1.節點顏色:每個節點都是紅色或黑色。
??? 2.根節點:根節點必須是黑色。
??? 3.葉子節點:所有的葉子節點(即空節點)都是黑色。
??? ?4.紅色節點的約束:紅色節點的子節點必須是黑色(即紅色節點不能有紅色子節點)。
??? 5.黑色節點的平衡:從任一節點到其每個葉子節點的所有路徑都包含相同數目的黑色節點。
?這些特性確保了紅黑樹的平衡性,使得其在最壞情況下的時間復雜度仍然保持在 O(logN)。具體來說,紅黑樹通過以下方式實現自平衡:
1. red_black_common.h
#ifndef RED_BLACK_COMMON_H
#define RED_BLACK_COMMON_H// 使用枚舉 定義節點顏色
typedef enum
{RED,BLACK
} node_color;// 定義樹,包含根節點,哨兵節,因為根節點與哨兵節點沒有繼續分支所以,樹的結構體只包含兩個數據
// 由于普通的節點,還有數據存在,即為令起一個結構體存放
typedef struct red_black_tree_common
{// 根節點tree_node *root_node;// 哨兵節點tree_node *nil_node;} tree;// 定義樹的節點,普通樹節點分為數據,左右子結點,及其這個節點的父節點(父節點有可能是根節點),節點顏色,
typedef struct tree_node
{// 1.數據域void *data;// 2.節點的顏色node_color color;// 3.父節點struct rb_tree_node *parent;// 4.左子節點struct rb_tree_node *left_child;// 5.右子節點struct rb_tree_node *right_child;
} tree_node;// 4.創建一個新的紅黑樹節點,新節點默認為紅色,左右子節點和父節點都指向哨兵節點
// 定義樹,返回值為樹節點的指針類型,參數為tree指針,與數據指針
tree_node *create_node(tree *tree, void *data);// 5.初始化一棵空樹,根節點為nil,并且哨兵節點顏色為黑色(最下面的葉子節點)
// 創建一個空樹,空樹只包含根節點與哨兵節點
tree *create_rb_tree();
/*左旋右旋,這層代碼還是簡單的,我想執導的是左右轉的目的是什么,或者說在現實世界的應用情況在什么情況下可以用到左右旋?----在修復的時候用得到,要維護紅黑樹的平衡及規則左右旋轉,先維護x與y的關系,即誰是誰的分支,重新定義x與y的雙向關系1.先判斷子結點上升的的節點與源節點的子關系,上升節點的分支與源節點的子關系2.判斷父關系
(分支節點的的父節點)上升節點的某個分支不為哨兵節點的話,則判斷其分支節點的指向為源節點(認爹)y->left_child->parent=x;x與y的關系有三種可能性1.x(源節點)為根節點,判斷(x->parent==tree->nil_node),則y就等于根節點,即tree->root_node=y;2.即x不是根節點,判斷x是其父節點的那個位置的節點,然后執行x->parent->left_child=y;3.另一個節點一樣
*/// last1.釋放節點
// 釋放樹節點的空間
void free_tree(tree *tree, tree_node *node);// last2.釋放樹
// 釋放樹的空間
void destroy_tree(tree *tree);#endif
2.?red_black_tree.c
#include <stdio.h>
#include <stdlib.h>
#include "../inc/rb_tree_common.h"// 4.創建一個新的紅黑樹節點,新節點默認為紅色,左右子節點和父節點都指向哨兵節點
rb_tree_node *create_node(rb_tree *tree, void *data)
{// 動態分配內存給新節點rb_tree_node *node = (rb_tree_node *)calloc(1, sizeof(rb_tree_node));if (node == NULL){printf("內存溢出,動態分配失敗\n");exit(EXIT_FAILURE);}// 設置新節點存儲的數據node->data = data;// 新節點的顏色默認為紅色node->color = RED;// 左右子節點和父節點都指向哨兵節點node->parent = tree->nil_node;node->left_child = tree->nil_node;node->right_child = tree->nil_node;// 返回創建的節點return node;
}// 5.初始化一棵空樹,根節點為nil,并且哨兵節點顏色為黑色(最下面的葉子節點)
rb_tree *create_rb_tree()
{// 動態分配內存給紅黑樹rb_tree *tree = (rb_tree *)calloc(1, sizeof(rb_tree));if (tree == NULL){printf("內存溢出,動態分配失敗\n");exit(EXIT_FAILURE);}// 創建哨兵節點tree->nil_node = (rb_tree_node *)calloc(1, sizeof(rb_tree_node));if (tree->nil_node == NULL){printf("內存溢出,動態分配失敗\n");exit(EXIT_FAILURE);}// 哨兵節點默認為黑色tree->nil_node->color = BLACK;// 初始化紅黑樹,沒有插入任何節點// 根節點指向哨兵節點tree->root_node = tree->nil_node;return tree;
}/*
紅黑樹的插入過程和二叉查找時的插入過程基本類似,不同的地方在于紅黑樹插入新節點后,需要進行調整,以滿足紅黑樹的性質:1.節點顏色:每個節點都是紅色或黑色。2.根節點:根節點必須是黑色。3.葉子節點:所有的葉子節點(即空節點)都是黑色。?4.紅色節點的約束:紅色節點的子節點必須是黑色(即紅色節點不能有紅色子節點)。5.黑色節點的平衡:從任一節點到其每個葉子節點的所有路徑都包含相同數目的黑色節點。
?這些特性確保了紅黑樹的平衡性,使得其在最壞情況下的時間復雜度仍然保持在 O(logN)。具體來說,紅黑樹通過以下方式實現自平衡:旋轉操作:包括左旋和右旋,用于調整節點的位置以維持樹的平衡。變色操作:用于調整節點的顏色以滿足紅黑樹的特性。
*/
// 6.左旋操作:左旋x,將x節點的右子節點提升為其父節點,并將x下移至其右子節點的左子節點的,左旋用于紅黑樹失衡調整的結構
void left_rotate(rb_tree *tree, rb_tree_node *x)
{// 6.1設置y為x的右子節點rb_tree_node *y = x->right_child;// 6.2將y的左子樹作為x的右子樹x->right_child = y->left_child;// 6.3 如果y的左子節點不是哨兵節點,要更改其父節點為xif (y->left_child != tree->nil_node){y->left_child->parent = x;}// 6.4讓y的父節點指向x的父節點y->parent = x->parent;// 6.5如果x是根節點,更新y為根節點if (x->parent == tree->nil_node){// 如果x是根節點,則更新根節點為ytree->root_node = y;}else if (x == x->parent->left_child){// x是父節點的左子節點,更新y為其左子節點x->parent->left_child = y;}else{x->parent->right_child = y;}// 6.6設置x為y的左子節點y->left_child = x;// 6.7設置x的父節點為yx->parent = y;
}// 7.右旋操作:右旋y,將y節點的左子節點提升為其父節點,并y下移至其左子節點的右子節點的,右旋用于紅黑樹失衡調整的結構
void right_rotate(rb_tree *tree, rb_tree_node *y)
{// 7.1設置x為y的左子節點rb_tree_node *x = y->left_child;// 7.2設置x的右子節點為y的左子節點y->left_child = x->right_child;if (x->right_child != tree->nil_node){// 如果x的右子節點不為哨兵節點 ,更新其父節點為yx->right_child->parent = y;}// 7.3讓x的父節點指向y的父節點x->parent = y->parent;if (y->parent == tree->nil_node){// 更新x為根節點tree->root_node = x;}else if (y == y->parent->right_child){y->parent->right_child = x;}else{y->parent->left_child = x;}// 7.4設置y為x的右子節點x->right_child = y;// 7.5更新y的父節點為xy->parent = x;
}// last1.釋放節點
void free_tree(rb_tree *tree, rb_tree_node *node)
{if (node != tree->nil_node){// 釋放左子節點free_tree(tree, node->left_child);// 釋放右子節點free_tree(tree, node->right_child);// 釋放節點本身free(node);}
}// last2.釋放樹
void destroy_tree(rb_tree *tree)
{// 從root節點,根節點開始釋放free_tree(tree, tree->root_node);// 釋放哨兵節點free(tree->nil_node);// 釋放紅黑樹的內存空間free(tree);
}
3. main.c
#include <stdio.h>
#include "../inc/rb_tree_common.h"int main(int argc, char const *argv[])
{//1.創建紅黑樹rb_tree *tree=create_rb_tree();//last.2 釋放紅黑樹destroy_tree(tree);return 0;
}
4. 總結
1. 左右旋
左旋右旋,這層代碼還是簡單的,我想執導的是左右轉的目的是什么,或者說在現實世界的應用情況
? 在什么情況下可以用到左右旋?----在修復的時候用得到,要維護紅黑樹的平衡及規則? 左右旋轉,先維護x與y的關系,即誰是誰的分支,重新定義x與y的雙向關系
? 1.先判斷子結點
? 上升的的節點與源節點的子關系,上升節點的分支與源節點的子關系
? 2.判斷父關系
(分支節點的的父節點)上升節點的某個分支不為哨兵節點的話,則判斷其分支節點的指向為源節點(認爹)y->left_child->parent=x;
? x與y的關系有三種可能性
? 1.x(源節點)為根節點,判斷(x->parent==tree->nil_node),則y就等于根節點,即tree->root_node=y;
? 2.即x不是根節點,判斷x是其父節點的那個位置的節點,然后執行x->parent->left_child=y;
? 3.另一個節點一樣
2. 修復(變色,左右旋轉)
這個我不知道怎么去描述。等有圖了繼續說
通過顏色翻轉,將紅色沖突向上傳遞,保證局部黑高不變,但可能引發更高層的紅紅沖突,需繼續循環處理。