refactor: Replace 结点 with 节点 (#452)

* Replace 结点 with 节点
Update the footnotes in the figures

* Update mindmap

* Reduce the size of the mindmap.png
This commit is contained in:
Yudong Jin 2023-04-09 04:32:17 +08:00 committed by GitHub
parent 3f4e32b2b0
commit 1c8b7ef559
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
395 changed files with 2056 additions and 2056 deletions

View File

@ -6,14 +6,14 @@
#include "../include/include.h"
/* 在链表的结点 n0 之后插入结点 P */
/* 在链表的节点 n0 之后插入节点 P */
void insert(ListNode* n0, ListNode* P) {
ListNode *n1 = n0->next;
P->next = n1;
n0->next = P;
}
/* 删除链表的结点 n0 之后的首个结点 */
/* 删除链表的节点 n0 之后的首个节点 */
// 由于引入了 stdio.h ,此处无法使用 remove 关键词
// 详见 https://github.com/krahets/hello-algo/pull/244#discussion_r1067863888
void removeNode(ListNode* n0) {
@ -27,7 +27,7 @@ void removeNode(ListNode* n0) {
free(P);
}
/* 访问链表中索引为 index 的点 */
/* 访问链表中索引为 index 的点 */
ListNode* access(ListNode* head, int index) {
while (head && head->next && index) {
head = head->next;
@ -36,7 +36,7 @@ ListNode* access(ListNode* head, int index) {
return head;
}
/* 在链表中查找值为 target 的首个点 */
/* 在链表中查找值为 target 的首个点 */
int find(ListNode* head, int target) {
int index = 0;
while (head) {
@ -52,7 +52,7 @@ int find(ListNode* head, int target) {
/* Driver Code */
int main() {
/* 初始化链表 */
// 初始化各个
// 初始化各个
ListNode* n0 = newListNode(1);
ListNode* n1 = newListNode(3);
ListNode* n2 = newListNode(2);
@ -66,23 +66,23 @@ int main() {
printf("初始化的链表为\r\n");
printLinkedList(n0);
/* 插入点 */
/* 插入点 */
insert(n0, newListNode(0));
printf("插入点后的链表为\r\n");
printf("插入点后的链表为\r\n");
printLinkedList(n0);
/* 删除点 */
/* 删除点 */
removeNode(n0);
printf("删除点后的链表为\r\n");
printf("删除点后的链表为\r\n");
printLinkedList(n0);
/* 访问点 */
/* 访问点 */
ListNode* node = access(n0, 3);
printf("链表中索引 3 处的点的值 = %d\r\n", node->val);
printf("链表中索引 3 处的点的值 = %d\r\n", node->val);
/* 查找点 */
/* 查找点 */
int index = find(n0, 2);
printf("链表中值为 2 的点的索引 = %d\r\n", index);
printf("链表中值为 2 的点的索引 = %d\r\n", index);
return 0;
}

View File

@ -27,23 +27,23 @@ maxHeap *newMaxHeap(int nums[], int size) {
h->size = size;
memcpy(h->data, nums, size * sizeof(int));
for (int i = size - 1; i >= 0; i--) {
// 堆化除叶结点以外的其他所有结
// 堆化除叶节点以外的其他所有节
siftDown(h, i);
}
return h;
}
/* 获取左子点索引 */
/* 获取左子点索引 */
int left(maxHeap *h, int i) {
return 2 * i + 1;
}
/* 获取右子点索引 */
/* 获取右子点索引 */
int right(maxHeap *h, int i) {
return 2 * i + 2;
}
/* 获取父点索引 */
/* 获取父点索引 */
int parent(maxHeap *h, int i) {
return (i - 1) / 2;
}
@ -72,12 +72,12 @@ int peek(maxHeap *h) {
/* 元素入堆 */
int push(maxHeap *h, int val) {
// 默认情况下,不应该添加这么多
// 默认情况下,不应该添加这么多
if (h->size == MAX_SIZE) {
printf("heap is full!");
return NIL;
}
// 添加
// 添加
h->data[h->size] = val;
h->size++;
@ -92,9 +92,9 @@ int pop(maxHeap *h) {
printf("heap is empty!");
return NIL;
}
// 交换根结点与最右叶结点(即交换首元素与尾元素)
// 交换根节点与最右叶节点(即交换首元素与尾元素)
swap(h, 0, size(h) - 1);
// 删除
// 删除
int val = h->data[h->size - 1];
h->size--;
// 从顶至底堆化
@ -105,10 +105,10 @@ int pop(maxHeap *h) {
}
/* 从点 i 开始,从顶至底堆化 */
/* 从点 i 开始,从顶至底堆化 */
void siftDown(maxHeap *h, int i) {
while (true) {
// 判断结点 i, l, r 中值最大的结点,记为 max
// 判断节点 i, l, r 中值最大的节点,记为 max
int l = left(h, i);
int r = right(h, i);
int max = i;
@ -118,27 +118,27 @@ void siftDown(maxHeap *h, int i) {
if (r < size(h) && h->data[r] > h->data[max]) {
max = r;
}
// 若点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
// 若点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if (max == i) {
break;
}
// 交换两
// 交换两
swap(h, i, max);
// 循环向下堆化
i = max;
}
}
/* 从点 i 开始,从底至顶堆化 */
/* 从点 i 开始,从底至顶堆化 */
void siftUp(maxHeap *h, int i) {
while (true) {
// 获取结点 i 的父结
// 获取节点 i 的父节
int p = parent(h, i);
// 当“越过根结点”或“结点无需修复”时,结束堆化
// 当“越过根节点”或“节点无需修复”时,结束堆化
if (p < 0 || h->data[i] <= h->data[p]) {
break;
}
// 交换两
// 交换两
swap(h, i, p);
// 循环向上堆化
i = p;

View File

@ -22,12 +22,12 @@ int linearSearchArray(int *nums, int len, int target) {
ListNode* linearSearchLinkedList(ListNode* head, int target) {
// 遍历链表
while (head != NULL) {
// 找到目标点,返回之
// 找到目标点,返回之
if (head->val == target)
return head;
head = head->next;
}
// 未找到目标点,返回 NULL
// 未找到目标点,返回 NULL
return NULL;
}
@ -44,9 +44,9 @@ int main() {
ListNode* head = arrToLinkedList(nums, 10);
ListNode* node = linearSearchLinkedList(head, target);
if(node == NULL) {
printf("目标结点值 3 的对应结点对象为 NULL\n");
printf("目标节点值 3 的对应节点对象为 NULL\n");
} else {
printf("目标结点值 3 的对应结点对象为 addr: %p val: %d\n", node, node->val);
printf("目标节点值 3 的对应节点对象为 addr: %p val: %d\n", node, node->val);
}
return 0;

View File

@ -6,16 +6,16 @@
#include "../include/include.h"
/* 双向链表点 */
/* 双向链表点 */
struct DoublyListNode {
int val; // 点值
struct DoublyListNode *next; // 后继
struct DoublyListNode *prev; // 前驱
int val; // 点值
struct DoublyListNode *next; // 后继
struct DoublyListNode *prev; // 前驱
};
typedef struct DoublyListNode DoublyListNode;
/* 双向链表点构造方法 */
/* 双向链表点构造方法 */
DoublyListNode *newDoublyListNode(int num) {
DoublyListNode* new = (DoublyListNode *) malloc(sizeof(DoublyListNode));
new->val = num;
@ -24,14 +24,14 @@ DoublyListNode *newDoublyListNode(int num) {
return new;
}
/* 双向链表点析构方法 */
/* 双向链表点析构方法 */
void delDoublyListNode(DoublyListNode *node) {
free(node);
}
/* 基于双向链表实现的双向队列 */
struct LinkedListDeque {
DoublyListNode *front, *rear; // 头结点 front ,尾结点 rear
DoublyListNode *front, *rear; // 头节点 front ,尾节点 rear
int queSize; // 双向队列的长度
};
@ -47,7 +47,7 @@ LinkedListDeque *newLinkedListDeque() {
/* 析构方法 */
void delLinkedListdeque(LinkedListDeque *deque) {
// 释放所有
// 释放所有
for (int i=0; i<deque->queSize && deque->front != NULL; i++) {
DoublyListNode *tmp = deque->front;
deque->front = deque->front->next;
@ -79,7 +79,7 @@ void push(LinkedListDeque *deque, int num, bool isFront) {
// 将 node 添加至链表头部
deque->front->prev = node;
node->next = deque->front;
deque->front = node;// 更新头
deque->front = node;// 更新头
}
// 对尾入队操作
else {
@ -120,25 +120,25 @@ int pop(LinkedListDeque *deque, bool isFront) {
int val;
// 队首出队操作
if(isFront) {
val = peekFirst(deque); // 暂存头点值
val = peekFirst(deque); // 暂存头点值
DoublyListNode *fNext = deque->front->next;
if (fNext) {
fNext->prev = NULL;
deque->front->next = NULL;
delDoublyListNode(deque->front);
}
deque->front = fNext; // 更新头
deque->front = fNext; // 更新头
}
// 队尾出队操作
else {
val = peekLast(deque); // 暂存尾点值
val = peekLast(deque); // 暂存尾点值
DoublyListNode *rPrev = deque->rear->prev;
if (rPrev) {
rPrev->next = NULL;
deque->rear->prev = NULL;
delDoublyListNode(deque->rear);
}
deque->rear = rPrev; // 更新尾
deque->rear = rPrev; // 更新尾
}
deque->queSize--; // 更新队列长度
return val;

View File

@ -24,7 +24,7 @@ LinkedListQueue *newLinkedListQueue() {
/* 析构方法 */
void delLinkedListQueue(LinkedListQueue *queue) {
// 释放所有
// 释放所有
for (int i=0; i<queue->queSize && queue->front != NULL; i++) {
ListNode *tmp = queue->front;
queue->front = queue->front->next;
@ -46,14 +46,14 @@ bool empty(LinkedListQueue *queue) {
/* 入队 */
void push(LinkedListQueue *queue, int num) {
// 尾点处添加 node
// 尾点处添加 node
ListNode *node = newListNode(num);
// 如果队列为空,则令头、尾结点都指向该结
// 如果队列为空,则令头、尾节点都指向该节
if (queue->front == NULL) {
queue->front = node;
queue->rear = node;
}
// 如果队列不为空,则将该结点添加到尾结点后
// 如果队列不为空,则将该节点添加到尾节点后
else {
queue->rear->next = node;
queue->rear = node;

View File

@ -8,7 +8,7 @@
/* 基于链表实现的栈 */
struct linkedListStack {
ListNode *top; // 将头点作为栈顶
ListNode *top; // 将头点作为栈顶
int size; // 栈的长度
};
@ -55,8 +55,8 @@ int peek(linkedListStack *s) {
void push(linkedListStack *s, int num) {
assert(s);
ListNode *node = (ListNode *) malloc(sizeof(ListNode));
node->next = s->top; // 更新新加点指针域
node->val = num; // 更新新加点数据域
node->next = s->top; // 更新新加点指针域
node->val = num; // 更新新加点数据域
s->top = node; // 更新栈顶
s->size++; // 更新栈大小
}

View File

@ -21,18 +21,18 @@ avlTree *newAVLTree() {
}
int height(TreeNode *node) {
// 空结点高度为 -1 ,叶结点高度为 0
// 空节点高度为 -1 ,叶节点高度为 0
if (node != NULL) {
return node->height;
}
return -1;
}
/* 更新点高度 */
/* 更新点高度 */
int updateHeight(TreeNode *node) {
int lh = height(node->left);
int rh = height(node->right);
// 点高度等于最高子树高度 + 1
// 点高度等于最高子树高度 + 1
if (lh > rh) {
node->height = lh + 1;
} else {
@ -42,11 +42,11 @@ int updateHeight(TreeNode *node) {
/* 获取平衡因子 */
int balanceFactor(TreeNode *node) {
// 空点平衡因子为 0
// 空点平衡因子为 0
if (node == NULL) {
return 0;
}
// 点平衡因子 = 左子树高度 - 右子树高度
// 点平衡因子 = 左子树高度 - 右子树高度
return height(node->left) - height(node->right);
}
@ -58,10 +58,10 @@ TreeNode *rightRotate(TreeNode *node) {
// 以 child 为原点,将 node 向右旋转
child->right = node;
node->left = grandChild;
// 更新点高度
// 更新点高度
updateHeight(node);
updateHeight(child);
// 返回旋转后子树的根
// 返回旋转后子树的根
return child;
}
@ -73,16 +73,16 @@ TreeNode *leftRotate(TreeNode *node) {
// 以 child 为原点,将 node 向左旋转
child->left = node;
node->right = grandChild;
// 更新点高度
// 更新点高度
updateHeight(node);
updateHeight(child);
// 返回旋转后子树的根
// 返回旋转后子树的根
return child;
}
/* 执行旋转操作,使该子树重新恢复平衡 */
TreeNode *rotate(TreeNode *node) {
// 获取点 node 的平衡因子
// 获取点 node 的平衡因子
int bf = balanceFactor(node);
// 左偏树
if (bf > 1) {
@ -110,54 +110,54 @@ TreeNode *rotate(TreeNode *node) {
return node;
}
/* 递归插入点(辅助方法) */
/* 递归插入点(辅助方法) */
TreeNode *insertHelper(TreeNode *node, int val) {
if (node == NULL) {
return newTreeNode(val);
}
/* 1. 查找插入位置,并插入点 */
/* 1. 查找插入位置,并插入点 */
if (val < node->val) {
node->left = insertHelper(node->left, val);
} else if (val > node->val) {
node->right = insertHelper(node->right, val);
} else {
// 重复点不插入,直接返回
// 重复点不插入,直接返回
return node;
}
// 更新点高度
// 更新点高度
updateHeight(node);
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
node = rotate(node);
// 返回子树的根
// 返回子树的根
return node;
}
/* 插入点 */
/* 插入点 */
TreeNode *insert(avlTree *tree, int val) {
tree->root = insertHelper(tree->root, val);
return tree->root;
}
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
/* 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) */
TreeNode *getInOrderNext(TreeNode *node) {
if (node == NULL) {
return node;
}
// 循环访问左子结点,直到叶结点时为最小结点,跳出
// 循环访问左子节点,直到叶节点时为最小节点,跳出
while (node->left != NULL) {
node = node->left;
}
return node;
}
/* 递归删除点(辅助方法) */
/* 递归删除点(辅助方法) */
TreeNode *removeHelper(TreeNode *node, int val) {
TreeNode *child, *grandChild, *temp;
if (node == NULL) {
return NULL;
}
/* 1. 查找点,并删除之 */
/* 1. 查找点,并删除之 */
if (val < node->val) {
node->left = removeHelper(node->left, val);
} else if (val > node->val) {
@ -168,64 +168,64 @@ TreeNode *removeHelper(TreeNode *node, int val) {
if (node->right != NULL) {
child = node->right;
}
// 子点数量 = 0 ,直接删除 node 并返回
// 子点数量 = 0 ,直接删除 node 并返回
if (child == NULL) {
return NULL;
} else {
// 子点数量 = 1 ,直接删除 node
// 子点数量 = 1 ,直接删除 node
node = child;
}
} else {
// 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结
// 子节点数量 = 2 ,则将中序遍历的下个节点删除,并用该节点替换当前节
temp = getInOrderNext(node->right);
node->right = removeHelper(node->right, temp->val);
node->val = temp->val;
}
}
// 更新点高度
// 更新点高度
updateHeight(node);
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
node = rotate(node);
// 返回子树的根
// 返回子树的根
return node;
}
/* 删除点 */
/* 删除点 */
// 由于引入了 stdio.h ,此处无法使用 remove 关键词
TreeNode *removeNode(avlTree *tree, int val) {
TreeNode *root = removeHelper(tree->root, val);
return root;
}
/* 查找点 */
/* 查找点 */
TreeNode *search(avlTree *tree, int val) {
TreeNode *cur = tree->root;
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
while (cur != NULL) {
if (cur->val < val) {
// 目标点在 cur 的右子树中
// 目标点在 cur 的右子树中
cur = cur->right;
} else if (cur->val > val) {
// 目标点在 cur 的左子树中
// 目标点在 cur 的左子树中
cur = cur->left;
} else {
// 找到目标点,跳出循环
// 找到目标点,跳出循环
break;
}
}
// 找到目标点,跳出循环
// 找到目标点,跳出循环
return cur;
}
void testInsert(avlTree *tree, int val) {
insert(tree, val);
printf("\n插入点 %d 后AVL 树为 \n", val);
printf("\n插入点 %d 后AVL 树为 \n", val);
printTree(tree->root);
}
void testRemove(avlTree *tree, int val) {
removeNode(tree, val);
printf("\n删除点 %d 后AVL 树为 \n", val);
printf("\n删除点 %d 后AVL 树为 \n", val);
printTree(tree->root);
}
@ -233,8 +233,8 @@ void testRemove(avlTree *tree, int val) {
int main() {
/* 初始化空 AVL 树 */
avlTree *tree = (avlTree *) newAVLTree();
/* 插入点 */
// 请关注插入点后AVL 树是如何保持平衡的
/* 插入点 */
// 请关注插入点后AVL 树是如何保持平衡的
testInsert(tree, 1);
testInsert(tree, 2);
testInsert(tree, 3);
@ -246,16 +246,16 @@ int main() {
testInsert(tree, 10);
testInsert(tree, 6);
/* 插入重复点 */
/* 插入重复点 */
testInsert(tree, 7);
/* 删除点 */
// 请关注删除点后AVL 树是如何保持平衡的
testRemove(tree, 8); // 删除度为 0 的
testRemove(tree, 5); // 删除度为 1 的
testRemove(tree, 4); // 删除度为 2 的
/* 删除点 */
// 请关注删除点后AVL 树是如何保持平衡的
testRemove(tree, 8); // 删除度为 0 的
testRemove(tree, 5); // 删除度为 1 的
testRemove(tree, 4); // 删除度为 2 的
/* 查询点 */
/* 查询点 */
TreeNode *node = search(tree, 7);
printf("\n查找到的结点对象结点值 = %d \n", node->val);
printf("\n查找到的节点对象节点值 = %d \n", node->val);
}

View File

@ -23,7 +23,7 @@ TreeNode *buildTree(int nums[], int i, int j) {
if (i > j) {
return NULL;
}
// 将数组中间结点作为根结
// 将数组中间节点作为根节
int mid = (i + j) / 2;
TreeNode *root = newTreeNode(nums[mid]);
// 递归建立左子树和右子树
@ -43,39 +43,39 @@ binarySearchTree *newBinarySearchTree(int nums[], int size) {
return bst;
}
/* 获取二叉树根点 */
/* 获取二叉树根点 */
TreeNode *getRoot(binarySearchTree *bst) {
return bst->root;
}
/* 查找点 */
/* 查找点 */
TreeNode *search(binarySearchTree *bst, int num) {
TreeNode *cur = bst->root;
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
while (cur != NULL) {
if (cur->val < num) {
// 目标点在 cur 的右子树中
// 目标点在 cur 的右子树中
cur = cur->right;
} else if (cur->val > num) {
// 目标点在 cur 的左子树中
// 目标点在 cur 的左子树中
cur = cur->left;
} else {
// 找到目标点,跳出循环
// 找到目标点,跳出循环
break;
}
}
// 返回目标
// 返回目标
return cur;
}
/* 插入点 */
/* 插入点 */
TreeNode *insert(binarySearchTree *bst, int num) {
// 若树为空,直接提前返回
if (bst->root == NULL) return NULL;
TreeNode *cur = bst->root, *pre = NULL;
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
while (cur != NULL) {
// 找到重复点,直接返回
// 找到重复点,直接返回
if (cur->val == num) {
return NULL;
}
@ -88,7 +88,7 @@ TreeNode *insert(binarySearchTree *bst, int num) {
cur = cur->left;
}
}
// 插入点 val
// 插入点 val
TreeNode *node = newTreeNode(num);
if (pre->val < num) {
pre->right = node;
@ -98,56 +98,56 @@ TreeNode *insert(binarySearchTree *bst, int num) {
return node;
}
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
/* 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) */
TreeNode *getInOrderNext(TreeNode *root) {
if (root == NULL) return root;
// 循环访问左子结点,直到叶结点时为最小结点,跳出
// 循环访问左子节点,直到叶节点时为最小节点,跳出
while (root->left != NULL) {
root = root->left;
}
return root;
}
/* 删除点 */
/* 删除点 */
// 由于引入了 stdio.h ,此处无法使用 remove 关键词
TreeNode *removeNode(binarySearchTree *bst, int num) {
// 若树为空,直接提前返回
if (bst->root == NULL) return NULL;
TreeNode *cur = bst->root, *pre = NULL;
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
while (cur != NULL) {
// 找到待删除点,跳出循环
// 找到待删除点,跳出循环
if (cur->val == num) break;
pre = cur;
if (cur->val < num) {
// 待删除点在 root 的右子树中
// 待删除点在 root 的右子树中
cur = cur->right;
} else {
// 待删除点在 root 的左子树中
// 待删除点在 root 的左子树中
cur = cur->left;
}
}
// 若无待删除点,则直接返回
// 若无待删除点,则直接返回
if (cur == NULL) {
return NULL;
}
// 判断待删除结点是否存在子结
// 判断待删除节点是否存在子节
if (cur->left == NULL || cur->right == NULL) {
/* 子点数量 = 0 or 1 */
// 当子结点数量 = 0 / 1 时, child = nullptr / 该子结
/* 子点数量 = 0 or 1 */
// 当子节点数量 = 0 / 1 时, child = nullptr / 该子节
TreeNode *child = cur->left != NULL ? cur->left : cur->right;
// 删除点 cur
// 删除点 cur
if (pre->left == cur) {
pre->left = child;
} else {
pre->right = child;
}
} else {
/* 子点数量 = 2 */
// 获取中序遍历中 cur 的下一个
/* 子点数量 = 2 */
// 获取中序遍历中 cur 的下一个
TreeNode *nex = getInOrderNext(cur->right);
int tmp = nex->val;
// 递归删除点 nex
// 递归删除点 nex
removeNode(bst, nex->val);
// 将 nex 的值复制给 cur
cur->val = tmp;
@ -163,26 +163,26 @@ int main() {
printf("初始化的二叉树为\n");
printTree(getRoot(bst));
/* 查找点 */
/* 查找点 */
TreeNode *node = search(bst, 7);
printf("查找到的结点对象的结点值 = %d\n", node->val);
printf("查找到的节点对象的节点值 = %d\n", node->val);
/* 插入点 */
/* 插入点 */
insert(bst, 16);
printf("插入点 16 后,二叉树为\n");
printf("插入点 16 后,二叉树为\n");
printTree(getRoot(bst));
/* 删除点 */
/* 删除点 */
removeNode(bst, 1);
printf("删除点 1 后,二叉树为\n");
printf("删除点 1 后,二叉树为\n");
printTree(getRoot(bst));
removeNode(bst, 2);
printf("删除点 2 后,二叉树为\n");
printf("删除点 2 后,二叉树为\n");
printTree(getRoot(bst));
removeNode(bst, 4);
printf("删除点 4 后,二叉树为\n");
printf("删除点 4 后,二叉树为\n");
printTree(getRoot(bst));
// 释放内存

View File

@ -9,7 +9,7 @@
/* Driver Code */
int main() {
/* 初始化二叉树 */
// 初始化
// 初始化
TreeNode* n1 = newTreeNode(1);
TreeNode* n2 = newTreeNode(2);
TreeNode* n3 = newTreeNode(3);
@ -23,19 +23,19 @@ int main() {
printf("初始化二叉树\n");
printTree(n1);
/* 插入与删除点 */
/* 插入与删除点 */
TreeNode* P = newTreeNode(0);
// 在 n1 -> n2 中间插入点 P
// 在 n1 -> n2 中间插入点 P
n1->left = P;
P->left = n2;
printf("插入点 P 后\n");
printf("插入点 P 后\n");
printTree(n1);
// 删除点 P
// 删除点 P
n1->left = n2;
// 释放内存
free(P);
printf("删除点 P 后\n");
printf("删除点 P 后\n");
printTree(n1);
return 0;

View File

@ -18,7 +18,7 @@ int *levelOrder(TreeNode *root, int *size) {
queue = (TreeNode **) malloc(sizeof(TreeNode) * MAX_NODE_SIZE);
// 队列指针
front = 0, rear = 0;
// 加入根
// 加入根
queue[rear++] = root;
// 初始化一个列表,用于保存遍历序列
/* 辅助数组 */
@ -28,14 +28,14 @@ int *levelOrder(TreeNode *root, int *size) {
while (front < rear) {
// 队列出队
node = queue[front++];
// 保存点值
// 保存点值
arr[index++] = node->val;
if (node->left != NULL) {
// 左子点入队
// 左子点入队
queue[rear++] = node->left;
}
if (node->right != NULL) {
// 右子点入队
// 右子点入队
queue[rear++] = node->right;
}
}
@ -59,7 +59,7 @@ int main() {
/* 层序遍历 */
// 需要传入数组的长度
int *arr = levelOrder(root, &size);
printf("层序遍历的点打印序列 = ");
printf("层序遍历的点打印序列 = ");
printArray(arr, size);
return 0;

View File

@ -12,7 +12,7 @@ int *arr;
/* 前序遍历 */
void preOrder(TreeNode *root, int *size) {
if (root == NULL) return;
// 访问优先级:根点 -> 左子树 -> 右子树
// 访问优先级:根点 -> 左子树 -> 右子树
arr[(*size)++] = root->val;
preOrder(root->left, size);
preOrder(root->right, size);
@ -21,7 +21,7 @@ void preOrder(TreeNode *root, int *size) {
/* 中序遍历 */
void inOrder(TreeNode *root, int *size) {
if (root == NULL) return;
// 访问优先级:左子树 -> 根点 -> 右子树
// 访问优先级:左子树 -> 根点 -> 右子树
inOrder(root->left, size);
arr[(*size)++] = root->val;
inOrder(root->right, size);
@ -30,7 +30,7 @@ void inOrder(TreeNode *root, int *size) {
/* 后序遍历 */
void postOrder(TreeNode *root, int *size) {
if (root == NULL) return;
// 访问优先级:左子树 -> 右子树 -> 根
// 访问优先级:左子树 -> 右子树 -> 根
postOrder(root->left, size);
postOrder(root->right, size);
arr[(*size)++] = root->val;
@ -52,19 +52,19 @@ int main() {
arr = (int *) malloc(sizeof(int) * MAX_NODE_SIZE);
size = 0;
preOrder(root, &size);
printf("前序遍历的点打印序列 = ");
printf("前序遍历的点打印序列 = ");
printArray(arr, size);
/* 中序遍历 */
size = 0;
inOrder(root, &size);
printf("中序遍历的点打印序列 = ");
printf("中序遍历的点打印序列 = ");
printArray(arr, size);
/* 后序遍历 */
size = 0;
postOrder(root, &size);
printf("后序遍历的点打印序列 = ");
printf("后序遍历的点打印序列 = ");
printArray(arr, size);
return 0;

View File

@ -10,16 +10,16 @@
extern "C" {
#endif
/* 链表点结构体 */
/* 链表点结构体 */
struct ListNode {
int val; // 点值
struct ListNode *next; // 指向下一点的指针(引用)
int val; // 点值
struct ListNode *next; // 指向下一点的指针(引用)
};
// typedef 作用是为一种数据类型定义一个新名字
typedef struct ListNode ListNode;
/* 构造函数,初始化一个新点 */
/* 构造函数,初始化一个新点 */
ListNode *newListNode(int val) {
ListNode *node, *next;
node = (ListNode *) malloc(sizeof(ListNode));

View File

@ -52,18 +52,18 @@ TreeNode *arrToTree(const int *arr, size_t size) {
TreeNode *root, *node;
TreeNode **queue;
/* 根点 */
/* 根点 */
root = newTreeNode(arr[0]);
/* 辅助队列 */
queue = (TreeNode **) malloc(sizeof(TreeNode) * MAX_NODE_SIZE);
// 队列指针
front = 0, rear = 0;
// 将根点放入队尾
// 将根点放入队尾
queue[rear++] = root;
// 记录遍历数组的索引
index = 0;
while (front < rear) {
// 取队列中的头结点,并让头结点出队
// 取队列中的头节点,并让头节点出队
node = queue[front++];
index++;
if (index < size) {
@ -103,14 +103,14 @@ int *treeToArr(TreeNode *root) {
queue = (TreeNode **) malloc(sizeof(TreeNode) * MAX_NODE_SIZE);
// 队列指针
front = 0, rear = 0;
// 将根点放入队尾
// 将根点放入队尾
queue[rear++] = root;
/* 辅助数组 */
arr = (int *) malloc(sizeof(int) * MAX_NODE_SIZE);
// 数组指针
index = 0;
while (front < rear) {
// 取队列中的头结点,并让头结点出队
// 取队列中的头节点,并让头节点出队
node = queue[front++];
if (node != NULL) {
arr[index] = node->val;

View File

@ -6,14 +6,14 @@
#include "../include/include.hpp"
/* 在链表的结点 n0 之后插入结点 P */
/* 在链表的节点 n0 之后插入节点 P */
void insert(ListNode* n0, ListNode* P) {
ListNode* n1 = n0->next;
P->next = n1;
n0->next = P;
}
/* 删除链表的结点 n0 之后的首个结点 */
/* 删除链表的节点 n0 之后的首个节点 */
void remove(ListNode* n0) {
if (n0->next == nullptr)
return;
@ -25,7 +25,7 @@ void remove(ListNode* n0) {
delete P;
}
/* 访问链表中索引为 index 的点 */
/* 访问链表中索引为 index 的点 */
ListNode* access(ListNode* head, int index) {
for (int i = 0; i < index; i++) {
if (head == nullptr)
@ -35,7 +35,7 @@ ListNode* access(ListNode* head, int index) {
return head;
}
/* 在链表中查找值为 target 的首个点 */
/* 在链表中查找值为 target 的首个点 */
int find(ListNode* head, int target) {
int index = 0;
while (head != nullptr) {
@ -51,7 +51,7 @@ int find(ListNode* head, int target) {
/* Driver Code */
int main() {
/* 初始化链表 */
// 初始化各个
// 初始化各个
ListNode* n0 = new ListNode(1);
ListNode* n1 = new ListNode(3);
ListNode* n2 = new ListNode(2);
@ -65,23 +65,23 @@ int main() {
cout << "初始化的链表为" << endl;
PrintUtil::printLinkedList(n0);
/* 插入点 */
/* 插入点 */
insert(n0, new ListNode(0));
cout << "插入点后的链表为" << endl;
cout << "插入点后的链表为" << endl;
PrintUtil::printLinkedList(n0);
/* 删除点 */
/* 删除点 */
remove(n0);
cout << "删除点后的链表为" << endl;
cout << "删除点后的链表为" << endl;
PrintUtil::printLinkedList(n0);
/* 访问点 */
/* 访问点 */
ListNode* node = access(n0, 3);
cout << "链表中索引 3 处的点的值 = " << node->val << endl;
cout << "链表中索引 3 处的点的值 = " << node->val << endl;
/* 查找点 */
/* 查找点 */
int index = find(n0, 2);
cout << "链表中值为 2 的点的索引 = " << index << endl;
cout << "链表中值为 2 的点的索引 = " << index << endl;
// 释放内存
freeMemoryLinkedList(n0);

View File

@ -12,7 +12,7 @@ public:
// 邻接表key: 顶点value该顶点的所有邻接顶点
unordered_map<Vertex*, vector<Vertex*>> adjList;
/* 在 vector 中删除指定点 */
/* 在 vector 中删除指定点 */
void remove(vector<Vertex*> &vec, Vertex *vet) {
for (int i = 0; i < vec.size(); i++) {
if (vec[i] == vet) {

View File

@ -12,47 +12,47 @@ private:
// 使用动态数组,这样无需考虑扩容问题
vector<int> maxHeap;
/* 获取左子点索引 */
/* 获取左子点索引 */
int left(int i) {
return 2 * i + 1;
}
/* 获取右子点索引 */
/* 获取右子点索引 */
int right(int i) {
return 2 * i + 2;
}
/* 获取父点索引 */
/* 获取父点索引 */
int parent(int i) {
return (i - 1) / 2; // 向下取整
}
/* 从点 i 开始,从底至顶堆化 */
/* 从点 i 开始,从底至顶堆化 */
void siftUp(int i) {
while (true) {
// 获取结点 i 的父结
// 获取节点 i 的父节
int p = parent(i);
// 当“越过根结点”或“结点无需修复”时,结束堆化
// 当“越过根节点”或“节点无需修复”时,结束堆化
if (p < 0 || maxHeap[i] <= maxHeap[p])
break;
// 交换两
// 交换两
swap(maxHeap[i], maxHeap[p]);
// 循环向上堆化
i = p;
}
}
/* 从点 i 开始,从顶至底堆化 */
/* 从点 i 开始,从顶至底堆化 */
void siftDown(int i) {
while (true) {
// 判断结点 i, l, r 中值最大的结点,记为 ma
// 判断节点 i, l, r 中值最大的节点,记为 ma
int l = left(i), r = right(i), ma = i;
// 若点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
// 若点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if (l < size() && maxHeap[l] > maxHeap[ma])
ma = l;
if (r < size() && maxHeap[r] > maxHeap[ma])
ma = r;
// 若点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
// 若点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if (ma == i)
break;
swap(maxHeap[i], maxHeap[ma]);
@ -66,7 +66,7 @@ public:
MaxHeap(vector<int> nums) {
// 将列表元素原封不动添加进堆
maxHeap = nums;
// 堆化除叶结点以外的其他所有结
// 堆化除叶节点以外的其他所有节
for (int i = parent(size() - 1); i >= 0; i--) {
siftDown(i);
}
@ -89,7 +89,7 @@ public:
/* 元素入堆 */
void push(int val) {
// 添加
// 添加
maxHeap.push_back(val);
// 从底至顶堆化
siftUp(size() - 1);
@ -101,9 +101,9 @@ public:
if (empty()) {
throw out_of_range("堆为空");
}
// 交换根结点与最右叶结点(即交换首元素与尾元素)
// 交换根节点与最右叶节点(即交换首元素与尾元素)
swap(maxHeap[0], maxHeap[size() - 1]);
// 删除
// 删除
maxHeap.pop_back();
// 从顶至底堆化
siftDown(0);

View File

@ -17,7 +17,7 @@ int hashingSearchArray(unordered_map<int, int> map, int target) {
/* 哈希查找(链表) */
ListNode* hashingSearchLinkedList(unordered_map<int, ListNode*> map, int target) {
// 哈希表的 key: 目标结点值value: 结点对象
// 哈希表的 key: 目标节点值value: 节点对象
// 若哈希表中无此 key ,返回 nullptr
if (map.find(target) == map.end())
return nullptr;
@ -44,11 +44,11 @@ int main() {
// 初始化哈希表
unordered_map<int, ListNode*> map1;
while (head != nullptr) {
map1[head->val] = head; // key: 结点值value: 结
map1[head->val] = head; // key: 节点值value: 节
head = head->next;
}
ListNode* node = hashingSearchLinkedList(map1, target);
cout << "目标结点值 3 的对应结点对象为 " << node << endl;
cout << "目标节点值 3 的对应节点对象为 " << node << endl;
return 0;
}

View File

@ -22,12 +22,12 @@ int linearSearchArray(vector<int>& nums, int target) {
ListNode* linearSearchLinkedList(ListNode* head, int target) {
// 遍历链表
while (head != nullptr) {
// 找到目标点,返回之
// 找到目标点,返回之
if (head->val == target)
return head;
head = head->next;
}
// 未找到目标点,返回 nullptr
// 未找到目标点,返回 nullptr
return nullptr;
}
@ -44,7 +44,7 @@ int main() {
/* 在链表中执行线性查找 */
ListNode* head = vecToLinkedList(nums);
ListNode* node = linearSearchLinkedList(head, target);
cout << "目标结点值 3 的对应结点对象为 " << node << endl;
cout << "目标节点值 3 的对应节点对象为 " << node << endl;
return 0;
}

View File

@ -7,18 +7,18 @@
#include "../include/include.hpp"
/* 双向链表点 */
/* 双向链表点 */
struct DoublyListNode {
int val; // 点值
DoublyListNode *next; // 后继点指针
DoublyListNode *prev; // 前驱点指针
int val; // 点值
DoublyListNode *next; // 后继点指针
DoublyListNode *prev; // 前驱点指针
DoublyListNode(int val) : val(val), prev(nullptr), next(nullptr) {}
};
/* 基于双向链表实现的双向队列 */
class LinkedListDeque {
private:
DoublyListNode *front, *rear; // 头结点 front ,尾结点 rear
DoublyListNode *front, *rear; // 头节点 front ,尾节点 rear
int queSize = 0; // 双向队列的长度
public:
@ -27,7 +27,7 @@ public:
/* 析构方法 */
~LinkedListDeque() {
// 遍历链表删除点,释放内存
// 遍历链表删除点,释放内存
DoublyListNode *pre, *cur = front;
while (cur != nullptr) {
pre = cur;
@ -57,13 +57,13 @@ public:
// 将 node 添加至链表头部
front->prev = node;
node->next = front;
front = node; // 更新头
front = node; // 更新头
// 队尾入队操作
} else {
// 将 node 添加至链表尾部
rear->next = node;
node->prev = rear;
rear = node; // 更新尾
rear = node; // 更新尾
}
queSize++; // 更新队列长度
}
@ -86,26 +86,26 @@ public:
int val;
// 队首出队操作
if (isFront) {
val = front->val; // 暂存头点值
// 删除头
val = front->val; // 暂存头点值
// 删除头
DoublyListNode *fNext = front->next;
if (fNext != nullptr) {
fNext->prev = nullptr;
front->next = nullptr;
delete front;
}
front = fNext; // 更新头
front = fNext; // 更新头
// 队尾出队操作
} else {
val = rear->val; // 暂存尾点值
// 删除尾
val = rear->val; // 暂存尾点值
// 删除尾
DoublyListNode *rPrev = rear->prev;
if (rPrev != nullptr) {
rPrev->next = nullptr;
rear->prev = nullptr;
delete rear;
}
rear = rPrev; // 更新尾
rear = rPrev; // 更新尾
}
queSize--; // 更新队列长度
return val;

View File

@ -9,7 +9,7 @@
/* 基于链表实现的队列 */
class LinkedListQueue {
private:
ListNode *front, *rear; // 头结点 front ,尾结点 rear
ListNode *front, *rear; // 头节点 front ,尾节点 rear
int queSize;
public:
@ -20,7 +20,7 @@ public:
}
~LinkedListQueue() {
// 遍历链表删除点,释放内存
// 遍历链表删除点,释放内存
freeMemoryLinkedList(front);
}
@ -36,14 +36,14 @@ public:
/* 入队 */
void push(int num) {
// 尾点后添加 num
// 尾点后添加 num
ListNode* node = new ListNode(num);
// 如果队列为空,则令头、尾结点都指向该结
// 如果队列为空,则令头、尾节点都指向该节
if (front == nullptr) {
front = node;
rear = node;
}
// 如果队列不为空,则将该结点添加到尾结点后
// 如果队列不为空,则将该节点添加到尾节点后
else {
rear->next = node;
rear = node;
@ -54,7 +54,7 @@ public:
/* 出队 */
void pop() {
int num = peek();
// 删除头
// 删除头
ListNode *tmp = front;
front = front->next;
// 释放内存

View File

@ -9,7 +9,7 @@
/* 基于链表实现的栈 */
class LinkedListStack {
private:
ListNode* stackTop; // 将头点作为栈顶
ListNode* stackTop; // 将头点作为栈顶
int stkSize; // 栈的长度
public:
@ -19,7 +19,7 @@ public:
}
~LinkedListStack() {
// 遍历链表删除点,释放内存
// 遍历链表删除点,释放内存
freeMemoryLinkedList(stackTop);
}

View File

@ -9,11 +9,11 @@
/* AVL 树 */
class AVLTree {
public:
TreeNode* root; // 根
TreeNode* root; // 根
private:
/* 更新点高度 */
/* 更新点高度 */
void updateHeight(TreeNode* node) {
// 点高度等于最高子树高度 + 1
// 点高度等于最高子树高度 + 1
node->height = max(height(node->left), height(node->right)) + 1;
}
@ -24,10 +24,10 @@ private:
// 以 child 为原点,将 node 向右旋转
child->right = node;
node->left = grandChild;
// 更新点高度
// 更新点高度
updateHeight(node);
updateHeight(child);
// 返回旋转后子树的根
// 返回旋转后子树的根
return child;
}
@ -38,16 +38,16 @@ private:
// 以 child 为原点,将 node 向左旋转
child->left = node;
node->right = grandChild;
// 更新点高度
// 更新点高度
updateHeight(node);
updateHeight(child);
// 返回旋转后子树的根
// 返回旋转后子树的根
return child;
}
/* 执行旋转操作,使该子树重新恢复平衡 */
TreeNode* rotate(TreeNode* node) {
// 获取点 node 的平衡因子
// 获取点 node 的平衡因子
int _balanceFactor = balanceFactor(node);
// 左偏树
if (_balanceFactor > 1) {
@ -75,40 +75,40 @@ private:
return node;
}
/* 递归插入点(辅助方法) */
/* 递归插入点(辅助方法) */
TreeNode* insertHelper(TreeNode* node, int val) {
if (node == nullptr)
return new TreeNode(val);
/* 1. 查找插入位置,并插入点 */
/* 1. 查找插入位置,并插入点 */
if (val < node->val)
node->left = insertHelper(node->left, val);
else if (val > node->val)
node->right = insertHelper(node->right, val);
else
return node; // 重复点不插入,直接返回
updateHeight(node); // 更新点高度
return node; // 重复点不插入,直接返回
updateHeight(node); // 更新点高度
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
node = rotate(node);
// 返回子树的根
// 返回子树的根
return node;
}
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
/* 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) */
TreeNode* getInOrderNext(TreeNode* node) {
if (node == nullptr)
return node;
// 循环访问左子结点,直到叶结点时为最小结点,跳出
// 循环访问左子节点,直到叶节点时为最小节点,跳出
while (node->left != nullptr) {
node = node->left;
}
return node;
}
/* 递归删除点(辅助方法) */
/* 递归删除点(辅助方法) */
TreeNode* removeHelper(TreeNode* node, int val) {
if (node == nullptr)
return nullptr;
/* 1. 查找点,并删除之 */
/* 1. 查找点,并删除之 */
if (val < node->val)
node->left = removeHelper(node->left, val);
else if (val > node->val)
@ -116,74 +116,74 @@ private:
else {
if (node->left == nullptr || node->right == nullptr) {
TreeNode* child = node->left != nullptr ? node->left : node->right;
// 子点数量 = 0 ,直接删除 node 并返回
// 子点数量 = 0 ,直接删除 node 并返回
if (child == nullptr) {
delete node;
return nullptr;
}
// 子点数量 = 1 ,直接删除 node
// 子点数量 = 1 ,直接删除 node
else {
delete node;
node = child;
}
} else {
// 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结
// 子节点数量 = 2 ,则将中序遍历的下个节点删除,并用该节点替换当前节
TreeNode* temp = getInOrderNext(node->right);
int tempVal = temp->val;
node->right = removeHelper(node->right, temp->val);
node->val = tempVal;
}
}
updateHeight(node); // 更新点高度
updateHeight(node); // 更新点高度
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
node = rotate(node);
// 返回子树的根
// 返回子树的根
return node;
}
public:
/* 获取点高度 */
/* 获取点高度 */
int height(TreeNode* node) {
// 空结点高度为 -1 ,叶结点高度为 0
// 空节点高度为 -1 ,叶节点高度为 0
return node == nullptr ? -1 : node->height;
}
/* 获取平衡因子 */
int balanceFactor(TreeNode* node) {
// 空点平衡因子为 0
// 空点平衡因子为 0
if (node == nullptr) return 0;
// 点平衡因子 = 左子树高度 - 右子树高度
// 点平衡因子 = 左子树高度 - 右子树高度
return height(node->left) - height(node->right);
}
/* 插入点 */
/* 插入点 */
TreeNode* insert(int val) {
root = insertHelper(root, val);
return root;
}
/* 删除点 */
/* 删除点 */
TreeNode* remove(int val) {
root = removeHelper(root, val);
return root;
}
/* 查找点 */
/* 查找点 */
TreeNode* search(int val) {
TreeNode* cur = root;
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
while (cur != nullptr) {
// 目标点在 cur 的右子树中
// 目标点在 cur 的右子树中
if (cur->val < val)
cur = cur->right;
// 目标点在 cur 的左子树中
// 目标点在 cur 的左子树中
else if (cur->val > val)
cur = cur->left;
// 找到目标点,跳出循环
// 找到目标点,跳出循环
else
break;
}
// 返回目标
// 返回目标
return cur;
}
@ -198,21 +198,21 @@ public:
void testInsert(AVLTree& tree, int val) {
tree.insert(val);
cout << "\n插入" << val << "AVL 树为" << endl;
cout << "\n插入" << val << "AVL 树为" << endl;
PrintUtil::printTree(tree.root);
}
void testRemove(AVLTree& tree, int val) {
tree.remove(val);
cout << "\n删除" << val << "AVL 树为" << endl;
cout << "\n删除" << val << "AVL 树为" << endl;
PrintUtil::printTree(tree.root);
}
int main() {
/* 初始化空 AVL 树 */
AVLTree avlTree;
/* 插入点 */
// 请关注插入点后AVL 树是如何保持平衡的
/* 插入点 */
// 请关注插入点后AVL 树是如何保持平衡的
testInsert(avlTree, 1);
testInsert(avlTree, 2);
testInsert(avlTree, 3);
@ -224,16 +224,16 @@ int main() {
testInsert(avlTree, 10);
testInsert(avlTree, 6);
/* 插入重复点 */
/* 插入重复点 */
testInsert(avlTree, 7);
/* 删除点 */
// 请关注删除点后AVL 树是如何保持平衡的
testRemove(avlTree, 8); // 删除度为 0 的
testRemove(avlTree, 5); // 删除度为 1 的
testRemove(avlTree, 4); // 删除度为 2 的
/* 删除点 */
// 请关注删除点后AVL 树是如何保持平衡的
testRemove(avlTree, 8); // 删除度为 0 的
testRemove(avlTree, 5); // 删除度为 1 的
testRemove(avlTree, 4); // 删除度为 2 的
/* 查询点 */
/* 查询点 */
TreeNode* node = avlTree.search(7);
cout << "\n查找到的点对象为 " << node << "点值 = " << node->val << endl;
cout << "\n查找到的点对象为 " << node << "点值 = " << node->val << endl;
}

View File

@ -21,7 +21,7 @@ public:
freeMemoryTree(root);
}
/* 获取二叉树根点 */
/* 获取二叉树根点 */
TreeNode* getRoot() {
return root;
}
@ -29,7 +29,7 @@ public:
/* 构建二叉搜索树 */
TreeNode* buildTree(vector<int> nums, int i, int j) {
if (i > j) return nullptr;
// 将数组中间结点作为根结
// 将数组中间节点作为根节
int mid = (i + j) / 2;
TreeNode* root = new TreeNode(nums[mid]);
// 递归建立左子树和右子树
@ -38,30 +38,30 @@ public:
return root;
}
/* 查找点 */
/* 查找点 */
TreeNode* search(int num) {
TreeNode* cur = root;
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
while (cur != nullptr) {
// 目标点在 cur 的右子树中
// 目标点在 cur 的右子树中
if (cur->val < num) cur = cur->right;
// 目标点在 cur 的左子树中
// 目标点在 cur 的左子树中
else if (cur->val > num) cur = cur->left;
// 找到目标点,跳出循环
// 找到目标点,跳出循环
else break;
}
// 返回目标
// 返回目标
return cur;
}
/* 插入点 */
/* 插入点 */
TreeNode* insert(int num) {
// 若树为空,直接提前返回
if (root == nullptr) return nullptr;
TreeNode *cur = root, *pre = nullptr;
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
while (cur != nullptr) {
// 找到重复点,直接返回
// 找到重复点,直接返回
if (cur->val == num) return nullptr;
pre = cur;
// 插入位置在 cur 的右子树中
@ -69,46 +69,46 @@ public:
// 插入位置在 cur 的左子树中
else cur = cur->left;
}
// 插入点 val
// 插入点 val
TreeNode* node = new TreeNode(num);
if (pre->val < num) pre->right = node;
else pre->left = node;
return node;
}
/* 删除点 */
/* 删除点 */
TreeNode* remove(int num) {
// 若树为空,直接提前返回
if (root == nullptr) return nullptr;
TreeNode *cur = root, *pre = nullptr;
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
while (cur != nullptr) {
// 找到待删除点,跳出循环
// 找到待删除点,跳出循环
if (cur->val == num) break;
pre = cur;
// 待删除点在 cur 的右子树中
// 待删除点在 cur 的右子树中
if (cur->val < num) cur = cur->right;
// 待删除点在 cur 的左子树中
// 待删除点在 cur 的左子树中
else cur = cur->left;
}
// 若无待删除点,则直接返回
// 若无待删除点,则直接返回
if (cur == nullptr) return nullptr;
// 子点数量 = 0 or 1
// 子点数量 = 0 or 1
if (cur->left == nullptr || cur->right == nullptr) {
// 当子结点数量 = 0 / 1 时, child = nullptr / 该子结
// 当子节点数量 = 0 / 1 时, child = nullptr / 该子节
TreeNode* child = cur->left != nullptr ? cur->left : cur->right;
// 删除点 cur
// 删除点 cur
if (pre->left == cur) pre->left = child;
else pre->right = child;
// 释放内存
delete cur;
}
// 子点数量 = 2
// 子点数量 = 2
else {
// 获取中序遍历中 cur 的下一个
// 获取中序遍历中 cur 的下一个
TreeNode* nex = getInOrderNext(cur->right);
int tmp = nex->val;
// 递归删除点 nex
// 递归删除点 nex
remove(nex->val);
// 将 nex 的值复制给 cur
cur->val = tmp;
@ -116,10 +116,10 @@ public:
return cur;
}
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
/* 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) */
TreeNode* getInOrderNext(TreeNode* root) {
if (root == nullptr) return root;
// 循环访问左子结点,直到叶结点时为最小结点,跳出
// 循环访问左子节点,直到叶节点时为最小节点,跳出
while (root->left != nullptr) {
root = root->left;
}
@ -136,24 +136,24 @@ int main() {
cout << endl << "初始化的二叉树为\n" << endl;
PrintUtil::printTree(bst->getRoot());
/* 查找点 */
/* 查找点 */
TreeNode* node = bst->search(7);
cout << endl << "查找到的点对象为 " << node << "点值 = " << node->val << endl;
cout << endl << "查找到的点对象为 " << node << "点值 = " << node->val << endl;
/* 插入点 */
/* 插入点 */
node = bst->insert(16);
cout << endl << "插入点 16 后,二叉树为\n" << endl;
cout << endl << "插入点 16 后,二叉树为\n" << endl;
PrintUtil::printTree(bst->getRoot());
/* 删除点 */
/* 删除点 */
bst->remove(1);
cout << endl << "删除点 1 后,二叉树为\n" << endl;
cout << endl << "删除点 1 后,二叉树为\n" << endl;
PrintUtil::printTree(bst->getRoot());
bst->remove(2);
cout << endl << "删除点 2 后,二叉树为\n" << endl;
cout << endl << "删除点 2 后,二叉树为\n" << endl;
PrintUtil::printTree(bst->getRoot());
bst->remove(4);
cout << endl << "删除点 4 后,二叉树为\n" << endl;
cout << endl << "删除点 4 后,二叉树为\n" << endl;
PrintUtil::printTree(bst->getRoot());
// 释放内存

View File

@ -10,7 +10,7 @@
/* Driver Code */
int main() {
/* 初始化二叉树 */
// 初始化
// 初始化
TreeNode* n1 = new TreeNode(1);
TreeNode* n2 = new TreeNode(2);
TreeNode* n3 = new TreeNode(3);
@ -24,17 +24,17 @@ int main() {
cout << endl << "初始化二叉树\n" << endl;
PrintUtil::printTree(n1);
/* 插入与删除点 */
/* 插入与删除点 */
TreeNode* P = new TreeNode(0);
// 在 n1 -> n2 中间插入点 P
// 在 n1 -> n2 中间插入点 P
n1->left = P;
P->left = n2;
cout << endl << "插入点 P 后\n" << endl;
cout << endl << "插入点 P 后\n" << endl;
PrintUtil::printTree(n1);
// 删除点 P
// 删除点 P
n1->left = n2;
delete P; // 释放内存
cout << endl << "删除点 P 后\n" << endl;
cout << endl << "删除点 P 后\n" << endl;
PrintUtil::printTree(n1);
// 释放内存

View File

@ -8,7 +8,7 @@
/* 层序遍历 */
vector<int> levelOrder(TreeNode* root) {
// 初始化队列,加入根
// 初始化队列,加入根
queue<TreeNode*> queue;
queue.push(root);
// 初始化一个列表,用于保存遍历序列
@ -16,11 +16,11 @@ vector<int> levelOrder(TreeNode* root) {
while (!queue.empty()) {
TreeNode* node = queue.front();
queue.pop(); // 队列出队
vec.push_back(node->val); // 保存点值
vec.push_back(node->val); // 保存点值
if (node->left != nullptr)
queue.push(node->left); // 左子点入队
queue.push(node->left); // 左子点入队
if (node->right != nullptr)
queue.push(node->right); // 右子点入队
queue.push(node->right); // 右子点入队
}
return vec;
}
@ -36,7 +36,7 @@ int main() {
/* 层序遍历 */
vector<int> vec = levelOrder(root);
cout << endl << "层序遍历的点打印序列 = ";
cout << endl << "层序遍历的点打印序列 = ";
PrintUtil::printVector(vec);
return 0;

View File

@ -12,7 +12,7 @@ vector<int> vec;
/* 前序遍历 */
void preOrder(TreeNode* root) {
if (root == nullptr) return;
// 访问优先级:根点 -> 左子树 -> 右子树
// 访问优先级:根点 -> 左子树 -> 右子树
vec.push_back(root->val);
preOrder(root->left);
preOrder(root->right);
@ -21,7 +21,7 @@ void preOrder(TreeNode* root) {
/* 中序遍历 */
void inOrder(TreeNode* root) {
if (root == nullptr) return;
// 访问优先级:左子树 -> 根点 -> 右子树
// 访问优先级:左子树 -> 根点 -> 右子树
inOrder(root->left);
vec.push_back(root->val);
inOrder(root->right);
@ -30,7 +30,7 @@ void inOrder(TreeNode* root) {
/* 后序遍历 */
void postOrder(TreeNode* root) {
if (root == nullptr) return;
// 访问优先级:左子树 -> 右子树 -> 根
// 访问优先级:左子树 -> 右子树 -> 根
postOrder(root->left);
postOrder(root->right);
vec.push_back(root->val);
@ -48,19 +48,19 @@ int main() {
/* 前序遍历 */
vec.clear();
preOrder(root);
cout << endl << "前序遍历的点打印序列 = ";
cout << endl << "前序遍历的点打印序列 = ";
PrintUtil::printVector(vec);
/* 中序遍历 */
vec.clear();
inOrder(root);
cout << endl << "中序遍历的点打印序列 = ";
cout << endl << "中序遍历的点打印序列 = ";
PrintUtil::printVector(vec);
/* 后序遍历 */
vec.clear();
postOrder(root);
cout << endl << "后序遍历的点打印序列 = ";
cout << endl << "后序遍历的点打印序列 = ";
PrintUtil::printVector(vec);
return 0;

View File

@ -9,7 +9,7 @@ namespace hello_algo.chapter_array_and_linkedlist;
public class linked_list
{
/* 在链表的结点 n0 之后插入结点 P */
/* 在链表的节点 n0 之后插入节点 P */
public static void insert(ListNode n0, ListNode P)
{
ListNode? n1 = n0.next;
@ -17,7 +17,7 @@ public class linked_list
n0.next = P;
}
/* 删除链表的结点 n0 之后的首个结点 */
/* 删除链表的节点 n0 之后的首个节点 */
public static void remove(ListNode n0)
{
if (n0.next == null)
@ -28,7 +28,7 @@ public class linked_list
n0.next = n1;
}
/* 访问链表中索引为 index 的点 */
/* 访问链表中索引为 index 的点 */
public static ListNode? access(ListNode head, int index)
{
for (int i = 0; i < index; i++)
@ -40,7 +40,7 @@ public class linked_list
return head;
}
/* 在链表中查找值为 target 的首个点 */
/* 在链表中查找值为 target 的首个点 */
public static int find(ListNode head, int target)
{
int index = 0;
@ -59,7 +59,7 @@ public class linked_list
public void Test()
{
// 初始化链表
// 初始化各个
// 初始化各个
ListNode n0 = new ListNode(1);
ListNode n1 = new ListNode(3);
ListNode n2 = new ListNode(2);
@ -72,20 +72,20 @@ public class linked_list
n3.next = n4;
Console.WriteLine($"初始化的链表为{n0}");
// 插入
// 插入
insert(n0, new ListNode(0));
Console.WriteLine($"插入点后的链表为{n0}");
Console.WriteLine($"插入点后的链表为{n0}");
// 删除
// 删除
remove(n0);
Console.WriteLine($"删除点后的链表为{n0}");
Console.WriteLine($"删除点后的链表为{n0}");
// 访问
// 访问
ListNode? node = access(n0, 3);
Console.WriteLine($"链表中索引 3 处的点的值 = {node?.val}");
Console.WriteLine($"链表中索引 3 处的点的值 = {node?.val}");
// 查找
// 查找
int index = find(n0, 2);
Console.WriteLine($"链表中值为 2 的点的索引 = {index}");
Console.WriteLine($"链表中值为 2 的点的索引 = {index}");
}
}

View File

@ -26,7 +26,7 @@ class MaxHeap
{
// 将列表元素原封不动添加进堆
maxHeap = new List<int>(nums);
// 堆化除叶结点以外的其他所有结
// 堆化除叶节点以外的其他所有节
var size = parent(this.size() - 1);
for (int i = size; i >= 0; i--)
{
@ -34,19 +34,19 @@ class MaxHeap
}
}
/* 获取左子点索引 */
/* 获取左子点索引 */
int left(int i)
{
return 2 * i + 1;
}
/* 获取右子点索引 */
/* 获取右子点索引 */
int right(int i)
{
return 2 * i + 2;
}
/* 获取父点索引 */
/* 获取父点索引 */
int parent(int i)
{
return (i - 1) / 2; // 向下整除
@ -61,7 +61,7 @@ class MaxHeap
/* 元素入堆 */
public void push(int val)
{
// 添加
// 添加
maxHeap.Add(val);
// 从底至顶堆化
siftUp(size() - 1);
@ -79,17 +79,17 @@ class MaxHeap
return size() == 0;
}
/* 从点 i 开始,从底至顶堆化 */
/* 从点 i 开始,从底至顶堆化 */
void siftUp(int i)
{
while (true)
{
// 获取结点 i 的父结
// 获取节点 i 的父节
int p = parent(i);
// 越过根结点点无需修复则结束堆化
// 越过根节点点无需修复则结束堆化
if (p < 0 || maxHeap[i] <= maxHeap[p])
break;
// 交换两
// 交换两
swap(i, p);
// 循环向上堆化
i = p;
@ -102,9 +102,9 @@ class MaxHeap
// 判空处理
if (isEmpty())
throw new IndexOutOfRangeException();
// 交换根结点与最右叶结即交换首元素与尾元素
// 交换根节点与最右叶节即交换首元素与尾元素
swap(0, size() - 1);
// 删除
// 删除
int val = maxHeap.Last();
maxHeap.RemoveAt(size() - 1);
// 从顶至底堆化
@ -113,20 +113,20 @@ class MaxHeap
return val;
}
/* 从点 i 开始,从顶至底堆化 */
/* 从点 i 开始,从顶至底堆化 */
void siftDown(int i)
{
while (true)
{
// 判断 i, l, r 中值最大的记为 ma
// 判断 i, l, r 中值最大的记为 ma
int l = left(i), r = right(i), ma = i;
if (l < size() && maxHeap[l] > maxHeap[ma])
ma = l;
if (r < size() && maxHeap[r] > maxHeap[ma])
ma = r;
// 结点 i 最大越过叶结则结束堆化
// 节点 i 最大越过叶节则结束堆化
if (ma == i) break;
// 交换两
// 交换两
swap(i, ma);
// 循环向下堆化
i = ma;

View File

@ -23,7 +23,7 @@ public class hashing_search
static ListNode? hashingSearchLinkedList(Dictionary<int, ListNode> map, int target)
{
// 哈希表的 key: 目标结点值value: 点对象
// 哈希表的 key: 目标节点值value: 点对象
// 若哈希表中无此 key 返回 null
return map.GetValueOrDefault(target);
}
@ -50,10 +50,10 @@ public class hashing_search
Dictionary<int, ListNode> map1 = new();
while (head != null)
{
map1[head.val] = head; // key: 结点值value:
map1[head.val] = head; // key: 节点值value:
head = head.next;
}
ListNode? node = hashingSearchLinkedList(map1, target);
Console.WriteLine("目标结点值 3 的对应结点对象为 " + node);
Console.WriteLine("目标节点值 3 的对应节点对象为 " + node);
}
}

View File

@ -31,12 +31,12 @@ public class linear_search
// 遍历链表
while (head != null)
{
// 找到目标返回之
// 找到目标返回之
if (head.val == target)
return head;
head = head.next;
}
// 未找到目标返回 null
// 未找到目标返回 null
return null;
}
@ -53,6 +53,6 @@ public class linear_search
/* 在链表中执行线性查找 */
ListNode head = ListNode.ArrToLinkedList(nums);
ListNode? node = linearSearchLinkedList(head, target);
Console.WriteLine("目标结点值 3 的对应结点对象为 " + node);
Console.WriteLine("目标节点值 3 的对应节点对象为 " + node);
}
}

View File

@ -8,12 +8,12 @@ using NUnit.Framework;
namespace hello_algo.chapter_stack_and_queue
{
/* 双向链表点 */
/* 双向链表点 */
public class ListNode
{
public int val; // 点值
public ListNode? next; // 后继点引用指针
public ListNode? prev; // 前驱点引用指针
public int val; // 点值
public ListNode? next; // 后继点引用指针
public ListNode? prev; // 前驱点引用指针
public ListNode(int val)
{
@ -26,7 +26,7 @@ namespace hello_algo.chapter_stack_and_queue
/* 基于双向链表实现的双向队列 */
public class LinkedListDeque
{
private ListNode? front, rear; // 结点 front, 尾结 rear
private ListNode? front, rear; // 节点 front, 尾节 rear
private int queSize = 0; // 双向队列的长度
public LinkedListDeque()
@ -63,7 +63,7 @@ namespace hello_algo.chapter_stack_and_queue
// node 添加至链表头部
front.prev = node;
node.next = front;
front = node; // 更新头
front = node; // 更新头
}
// 队尾入队操作
else
@ -71,7 +71,7 @@ namespace hello_algo.chapter_stack_and_queue
// node 添加至链表尾部
rear.next = node;
node.prev = rear;
rear = node; // 更新尾
rear = node; // 更新尾
}
queSize++; // 更新队列长度
@ -102,8 +102,8 @@ namespace hello_algo.chapter_stack_and_queue
// 队首出队操作
if (isFront)
{
val = front.val; // 暂存头点值
// 删除头
val = front.val; // 暂存头点值
// 删除头
ListNode fNext = front.next;
if (fNext != null)
{
@ -111,13 +111,13 @@ namespace hello_algo.chapter_stack_and_queue
front.next = null;
}
front = fNext; // 更新头
front = fNext; // 更新头
}
// 队尾出队操作
else
{
val = rear.val; // 暂存尾点值
// 删除尾
val = rear.val; // 暂存尾点值
// 删除尾
ListNode rPrev = rear.prev;
if (rPrev != null)
{
@ -125,7 +125,7 @@ namespace hello_algo.chapter_stack_and_queue
rear.prev = null;
}
rear = rPrev; // 更新尾
rear = rPrev; // 更新尾
}
queSize--; // 更新队列长度

View File

@ -12,7 +12,7 @@ namespace hello_algo.chapter_stack_and_queue;
/* 基于链表实现的队列 */
class LinkedListQueue
{
private ListNode? front, rear; // 结点 front 尾结 rear
private ListNode? front, rear; // 节点 front 尾节 rear
private int queSize = 0;
public LinkedListQueue()
@ -36,14 +36,14 @@ class LinkedListQueue
/* 入队 */
public void push(int num)
{
// 点后添加 num
// 点后添加 num
ListNode node = new ListNode(num);
// 如果队列为空则令头结点都指向该结
// 如果队列为空则令头节点都指向该节
if (front == null)
{
front = node;
rear = node;
// 如果队列不为空则将该结点添加到尾结点后
// 如果队列不为空则将该节点添加到尾节点后
}
else if (rear != null)
{
@ -57,7 +57,7 @@ class LinkedListQueue
public int pop()
{
int num = peek();
// 删除头
// 删除头
front = front?.next;
queSize--;
return num;

View File

@ -12,7 +12,7 @@ namespace hello_algo.chapter_stack_and_queue;
/* 基于链表实现的栈 */
class LinkedListStack
{
private ListNode? stackPeek; // 将头点作为栈顶
private ListNode? stackPeek; // 将头点作为栈顶
private int stkSize = 0; // 栈的长度
public LinkedListStack()

View File

@ -12,28 +12,28 @@ namespace hello_algo.chapter_tree;
/* AVL 树 */
class AVLTree
{
public TreeNode? root; //
public TreeNode? root; //
/* 获取点高度 */
/* 获取点高度 */
public int height(TreeNode? node)
{
// 结点高度为 -1 叶结点高度为 0
// 节点高度为 -1 叶节点高度为 0
return node == null ? -1 : node.height;
}
/* 更新点高度 */
/* 更新点高度 */
private void updateHeight(TreeNode node)
{
// 点高度等于最高子树高度 + 1
// 点高度等于最高子树高度 + 1
node.height = Math.Max(height(node.left), height(node.right)) + 1;
}
/* 获取平衡因子 */
public int balanceFactor(TreeNode? node)
{
// 点平衡因子为 0
// 点平衡因子为 0
if (node == null) return 0;
// 点平衡因子 = 左子树高度 - 右子树高度
// 点平衡因子 = 左子树高度 - 右子树高度
return height(node.left) - height(node.right);
}
@ -45,10 +45,10 @@ class AVLTree
// child 为原点 node 向右旋转
child.right = node;
node.left = grandChild;
// 更新点高度
// 更新点高度
updateHeight(node);
updateHeight(child);
// 返回旋转后子树的根
// 返回旋转后子树的根
return child;
}
@ -60,17 +60,17 @@ class AVLTree
// child 为原点 node 向左旋转
child.left = node;
node.right = grandChild;
// 更新点高度
// 更新点高度
updateHeight(node);
updateHeight(child);
// 返回旋转后子树的根
// 返回旋转后子树的根
return child;
}
/* 执行旋转操作,使该子树重新恢复平衡 */
TreeNode? rotate(TreeNode? node)
{
// 获取 node 的平衡因子
// 获取 node 的平衡因子
int balanceFactorInt = balanceFactor(node);
// 左偏树
if (balanceFactorInt > 1)
@ -106,43 +106,43 @@ class AVLTree
return node;
}
/* 插入点 */
/* 插入点 */
public TreeNode? insert(int val)
{
root = insertHelper(root, val);
return root;
}
/* 递归插入点(辅助方法) */
/* 递归插入点(辅助方法) */
private TreeNode? insertHelper(TreeNode? node, int val)
{
if (node == null) return new TreeNode(val);
/* 1. 查找插入位置,并插入点 */
/* 1. 查找插入位置,并插入点 */
if (val < node.val)
node.left = insertHelper(node.left, val);
else if (val > node.val)
node.right = insertHelper(node.right, val);
else
return node; // 重复点不插入直接返回
updateHeight(node); // 更新点高度
return node; // 重复点不插入直接返回
updateHeight(node); // 更新点高度
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
node = rotate(node);
// 返回子树的根
// 返回子树的根
return node;
}
/* 删除点 */
/* 删除点 */
public TreeNode? remove(int val)
{
root = removeHelper(root, val);
return root;
}
/* 递归删除点(辅助方法) */
/* 递归删除点(辅助方法) */
private TreeNode? removeHelper(TreeNode? node, int val)
{
if (node == null) return null;
/* 1. 查找点,并删除之 */
/* 1. 查找点,并删除之 */
if (val < node.val)
node.left = removeHelper(node.left, val);
else if (val > node.val)
@ -152,33 +152,33 @@ class AVLTree
if (node.left == null || node.right == null)
{
TreeNode? child = node.left != null ? node.left : node.right;
// 点数量 = 0 直接删除 node 并返回
// 点数量 = 0 直接删除 node 并返回
if (child == null)
return null;
// 点数量 = 1 直接删除 node
// 点数量 = 1 直接删除 node
else
node = child;
}
else
{
// 点数量 = 2 则将中序遍历的下个结点删除并用该结点替换当前结
// 点数量 = 2 则将中序遍历的下个节点删除并用该节点替换当前节
TreeNode? temp = getInOrderNext(node.right);
node.right = removeHelper(node.right, temp.val);
node.val = temp.val;
}
}
updateHeight(node); // 更新点高度
updateHeight(node); // 更新点高度
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
node = rotate(node);
// 返回子树的根
// 返回子树的根
return node;
}
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
/* 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) */
private TreeNode? getInOrderNext(TreeNode? node)
{
if (node == null) return node;
// 循环访问左子结点直到叶结点时为最小结跳出
// 循环访问左子节点直到叶节点时为最小节跳出
while (node.left != null)
{
node = node.left;
@ -186,24 +186,24 @@ class AVLTree
return node;
}
/* 查找点 */
/* 查找点 */
public TreeNode? search(int val)
{
TreeNode? cur = root;
// 循环查找越过叶点后跳出
// 循环查找越过叶点后跳出
while (cur != null)
{
// 目标点在 cur 的右子树中
// 目标点在 cur 的右子树中
if (cur.val < val)
cur = cur.right;
// 目标点在 cur 的左子树中
// 目标点在 cur 的左子树中
else if (cur.val > val)
cur = cur.left;
// 找到目标跳出循环
// 找到目标跳出循环
else
break;
}
// 返回目标
// 返回目标
return cur;
}
}
@ -213,14 +213,14 @@ public class avl_tree
static void testInsert(AVLTree tree, int val)
{
tree.insert(val);
Console.WriteLine("\n插入" + val + "AVL 树为");
Console.WriteLine("\n插入" + val + "AVL 树为");
PrintUtil.PrintTree(tree.root);
}
static void testRemove(AVLTree tree, int val)
{
tree.remove(val);
Console.WriteLine("\n删除" + val + "AVL 树为");
Console.WriteLine("\n删除" + val + "AVL 树为");
PrintUtil.PrintTree(tree.root);
}
@ -230,8 +230,8 @@ public class avl_tree
/* 初始化空 AVL 树 */
AVLTree avlTree = new AVLTree();
/* 插入点 */
// 请关注插入点后AVL 树是如何保持平衡的
/* 插入点 */
// 请关注插入点后AVL 树是如何保持平衡的
testInsert(avlTree, 1);
testInsert(avlTree, 2);
testInsert(avlTree, 3);
@ -243,17 +243,17 @@ public class avl_tree
testInsert(avlTree, 10);
testInsert(avlTree, 6);
/* 插入重复点 */
/* 插入重复点 */
testInsert(avlTree, 7);
/* 删除点 */
// 请关注删除点后AVL 树是如何保持平衡的
testRemove(avlTree, 8); // 删除度为 0
testRemove(avlTree, 5); // 删除度为 1
testRemove(avlTree, 4); // 删除度为 2
/* 删除点 */
// 请关注删除点后AVL 树是如何保持平衡的
testRemove(avlTree, 8); // 删除度为 0
testRemove(avlTree, 5); // 删除度为 1
testRemove(avlTree, 4); // 删除度为 2
/* 查询点 */
/* 查询点 */
TreeNode? node = avlTree.search(7);
Console.WriteLine("\n查找到的点对象为 " + node + "点值 = " + node?.val);
Console.WriteLine("\n查找到的点对象为 " + node + "点值 = " + node?.val);
}
}

View File

@ -19,7 +19,7 @@ class BinarySearchTree
root = buildTree(nums, 0, nums.Length - 1); // 构建二叉搜索树
}
/* 获取二叉树根点 */
/* 获取二叉树根点 */
public TreeNode? getRoot()
{
return root;
@ -29,7 +29,7 @@ class BinarySearchTree
public TreeNode? buildTree(int[] nums, int i, int j)
{
if (i > j) return null;
// 将数组中间结点作为根结
// 将数组中间节点作为根节
int mid = (i + j) / 2;
TreeNode root = new TreeNode(nums[mid]);
// 递归建立左子树和右子树
@ -38,34 +38,34 @@ class BinarySearchTree
return root;
}
/* 查找点 */
/* 查找点 */
public TreeNode? search(int num)
{
TreeNode? cur = root;
// 循环查找越过叶点后跳出
// 循环查找越过叶点后跳出
while (cur != null)
{
// 目标点在 cur 的右子树中
// 目标点在 cur 的右子树中
if (cur.val < num) cur = cur.right;
// 目标点在 cur 的左子树中
// 目标点在 cur 的左子树中
else if (cur.val > num) cur = cur.left;
// 找到目标跳出循环
// 找到目标跳出循环
else break;
}
// 返回目标
// 返回目标
return cur;
}
/* 插入点 */
/* 插入点 */
public TreeNode? insert(int num)
{
// 若树为空直接提前返回
if (root == null) return null;
TreeNode? cur = root, pre = null;
// 循环查找越过叶点后跳出
// 循环查找越过叶点后跳出
while (cur != null)
{
// 找到重复直接返回
// 找到重复直接返回
if (cur.val == num) return null;
pre = cur;
// 插入位置在 cur 的右子树中
@ -74,7 +74,7 @@ class BinarySearchTree
else cur = cur.left;
}
// 插入 val
// 插入 val
TreeNode node = new TreeNode(num);
if (pre != null)
{
@ -85,31 +85,31 @@ class BinarySearchTree
}
/* 删除点 */
/* 删除点 */
public TreeNode? remove(int num)
{
// 若树为空直接提前返回
if (root == null) return null;
TreeNode? cur = root, pre = null;
// 循环查找越过叶点后跳出
// 循环查找越过叶点后跳出
while (cur != null)
{
// 找到待删除跳出循环
// 找到待删除跳出循环
if (cur.val == num) break;
pre = cur;
// 待删除点在 cur 的右子树中
// 待删除点在 cur 的右子树中
if (cur.val < num) cur = cur.right;
// 待删除点在 cur 的左子树中
// 待删除点在 cur 的左子树中
else cur = cur.left;
}
// 若无待删除则直接返回
// 若无待删除则直接返回
if (cur == null || pre == null) return null;
// 点数量 = 0 or 1
// 点数量 = 0 or 1
if (cur.left == null || cur.right == null)
{
// 当子点数量 = 0 / 1 child = null / 该子
// 当子点数量 = 0 / 1 child = null / 该子
TreeNode? child = cur.left != null ? cur.left : cur.right;
// 删除 cur
// 删除 cur
if (pre.left == cur)
{
pre.left = child;
@ -119,15 +119,15 @@ class BinarySearchTree
pre.right = child;
}
}
// 点数量 = 2
// 点数量 = 2
else
{
// 获取中序遍历中 cur 的下一个
// 获取中序遍历中 cur 的下一个
TreeNode? nex = getInOrderNext(cur.right);
if (nex != null)
{
int tmp = nex.val;
// 递归删除 nex
// 递归删除 nex
remove(nex.val);
// nex 的值复制给 cur
cur.val = tmp;
@ -136,11 +136,11 @@ class BinarySearchTree
return cur;
}
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
/* 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) */
private TreeNode? getInOrderNext(TreeNode? root)
{
if (root == null) return root;
// 循环访问左子结点直到叶结点时为最小结跳出
// 循环访问左子节点直到叶节点时为最小节跳出
while (root.left != null)
{
root = root.left;
@ -160,24 +160,24 @@ public class binary_search_tree
Console.WriteLine("\n初始化的二叉树为\n");
PrintUtil.PrintTree(bst.getRoot());
/* 查找点 */
/* 查找点 */
TreeNode? node = bst.search(7);
Console.WriteLine("\n查找到的点对象为 " + node + "点值 = " + node.val);
Console.WriteLine("\n查找到的点对象为 " + node + "点值 = " + node.val);
/* 插入点 */
/* 插入点 */
node = bst.insert(16);
Console.WriteLine("\n插入点 16 后,二叉树为\n");
Console.WriteLine("\n插入点 16 后,二叉树为\n");
PrintUtil.PrintTree(bst.getRoot());
/* 删除点 */
/* 删除点 */
bst.remove(1);
Console.WriteLine("\n删除点 1 后,二叉树为\n");
Console.WriteLine("\n删除点 1 后,二叉树为\n");
PrintUtil.PrintTree(bst.getRoot());
bst.remove(2);
Console.WriteLine("\n删除点 2 后,二叉树为\n");
Console.WriteLine("\n删除点 2 后,二叉树为\n");
PrintUtil.PrintTree(bst.getRoot());
bst.remove(4);
Console.WriteLine("\n删除点 4 后,二叉树为\n");
Console.WriteLine("\n删除点 4 后,二叉树为\n");
PrintUtil.PrintTree(bst.getRoot());
}
}

View File

@ -15,7 +15,7 @@ public class binary_tree
public void Test()
{
/* 初始化二叉树 */
// 初始化
// 初始化
TreeNode n1 = new TreeNode(1);
TreeNode n2 = new TreeNode(2);
TreeNode n3 = new TreeNode(3);
@ -29,16 +29,16 @@ public class binary_tree
Console.WriteLine("\n初始化二叉树\n");
PrintUtil.PrintTree(n1);
/* 插入与删除点 */
/* 插入与删除点 */
TreeNode P = new TreeNode(0);
// n1 -> n2 中间插入 P
// n1 -> n2 中间插入 P
n1.left = P;
P.left = n2;
Console.WriteLine("\n插入点 P 后\n");
Console.WriteLine("\n插入点 P 后\n");
PrintUtil.PrintTree(n1);
// 删除 P
// 删除 P
n1.left = n2;
Console.WriteLine("\n删除点 P 后\n");
Console.WriteLine("\n删除点 P 后\n");
PrintUtil.PrintTree(n1);
}
}

View File

@ -15,7 +15,7 @@ public class binary_tree_bfs
/* 层序遍历 */
public List<int> levelOrder(TreeNode root)
{
// 初始化队列加入根
// 初始化队列加入根
Queue<TreeNode> queue = new();
queue.Enqueue(root);
// 初始化一个列表用于保存遍历序列
@ -23,11 +23,11 @@ public class binary_tree_bfs
while (queue.Count != 0)
{
TreeNode node = queue.Dequeue(); // 队列出队
list.Add(node.val); // 保存点值
list.Add(node.val); // 保存点值
if (node.left != null)
queue.Enqueue(node.left); // 左子点入队
queue.Enqueue(node.left); // 左子点入队
if (node.right != null)
queue.Enqueue(node.right); // 右子点入队
queue.Enqueue(node.right); // 右子点入队
}
return list;
}
@ -42,6 +42,6 @@ public class binary_tree_bfs
PrintUtil.PrintTree(root);
List<int> list = levelOrder(root);
Console.WriteLine("\n层序遍历的点打印序列 = " + string.Join(",", list.ToArray()));
Console.WriteLine("\n层序遍历的点打印序列 = " + string.Join(",", list.ToArray()));
}
}

View File

@ -17,7 +17,7 @@ public class binary_tree_dfs
void preOrder(TreeNode? root)
{
if (root == null) return;
// 访问优先级 -> 左子树 -> 右子树
// 访问优先级 -> 左子树 -> 右子树
list.Add(root.val);
preOrder(root.left);
preOrder(root.right);
@ -27,7 +27,7 @@ public class binary_tree_dfs
void inOrder(TreeNode? root)
{
if (root == null) return;
// 访问优先级左子树 -> -> 右子树
// 访问优先级左子树 -> -> 右子树
inOrder(root.left);
list.Add(root.val);
inOrder(root.right);
@ -37,7 +37,7 @@ public class binary_tree_dfs
void postOrder(TreeNode? root)
{
if (root == null) return;
// 访问优先级左子树 -> 右子树 ->
// 访问优先级左子树 -> 右子树 ->
postOrder(root.left);
postOrder(root.right);
list.Add(root.val);
@ -54,14 +54,14 @@ public class binary_tree_dfs
list.Clear();
preOrder(root);
Console.WriteLine("\n前序遍历的点打印序列 = " + string.Join(",", list.ToArray()));
Console.WriteLine("\n前序遍历的点打印序列 = " + string.Join(",", list.ToArray()));
list.Clear();
inOrder(root);
Console.WriteLine("\n中序遍历的点打印序列 = " + string.Join(",", list.ToArray()));
Console.WriteLine("\n中序遍历的点打印序列 = " + string.Join(",", list.ToArray()));
list.Clear();
postOrder(root);
Console.WriteLine("\n后序遍历的点打印序列 = " + string.Join(",", list.ToArray()));
Console.WriteLine("\n后序遍历的点打印序列 = " + string.Join(",", list.ToArray()));
}
}

View File

@ -8,10 +8,10 @@ namespace hello_algo.include;
public class TreeNode
{
public int val; // 点值
public int height; // 点高度
public TreeNode? left; // 左子点引用
public TreeNode? right; // 右子点引用
public int val; // 点值
public int height; // 点高度
public TreeNode? left; // 左子点引用
public TreeNode? right; // 右子点引用
public TreeNode(int x)
{

View File

@ -9,14 +9,14 @@ import '../utils/print_util.dart';
class LinkedList {
/* 在链表的结点 n0 之后插入结点 P */
/* 在链表的节点 n0 之后插入节点 P */
void insert(ListNode n0, ListNode P) {
ListNode? n1 = n0.next;
P.next = n1;
n0.next = P;
}
/* 删除链表的结点 n0 之后的首个结点 */
/* 删除链表的节点 n0 之后的首个节点 */
void remove(ListNode n0) {
if (n0.next == null) return;
ListNode P = n0.next!;
@ -24,7 +24,7 @@ class LinkedList {
n0.next = n1;
}
/* 访问链表中索引为 index 的点 */
/* 访问链表中索引为 index 的点 */
ListNode? access(ListNode? head, int index) {
for (var i = 0; i < index; i++) {
if (head == null) return null;
@ -33,7 +33,7 @@ class LinkedList {
return head;
}
/* 在链表中查找值为 target 的首个点 */
/* 在链表中查找值为 target 的首个点 */
int find(ListNode? head, int target) {
int index = 0;
while (head != null) {
@ -50,7 +50,7 @@ class LinkedList {
/* Driver Code */
int main() {
//
//
//
ListNode n0 = ListNode(1);
ListNode n1 = ListNode(3);
ListNode n2 = ListNode(2);
@ -65,21 +65,21 @@ int main() {
print('初始化的链表为');
printLinkedList(n0);
/* 插入点 */
/* 插入点 */
LinkedList().insert(n0, ListNode(0));
printLinkedList(n0);
/* 删除点 */
/* 删除点 */
LinkedList().remove(n0);
printLinkedList(n0);
/* 访问点 */
/* 访问点 */
ListNode? node = LinkedList().access(n0, 3);
print('链表中索引 3 处的点的值 = ${node!.val}');
print('链表中索引 3 处的点的值 = ${node!.val}');
/* 查找点 */
/* 查找点 */
int index = LinkedList().find(n0, 2);
print('链表中值为 2 的点的索引 = $index');
print('链表中值为 2 的点的索引 = $index');
return 0;
}

View File

@ -4,19 +4,19 @@
* Author: liuyuxin (gvenusleo@gmail.com)
*/
/* 双向链表点 */
/* 双向链表点 */
class ListNode {
int val; //
ListNode? next; //
ListNode? prev; //
int val; //
ListNode? next; //
ListNode? prev; //
ListNode(this.val, {this.next, this.prev});
}
/* 基于双向链表实现的双向对列 */
class LinkedListDeque {
late ListNode? _front; // _front
late ListNode? _rear; // _rear
late ListNode? _front; // _front
late ListNode? _rear; // _rear
int _queSize = 0; //
LinkedListDeque() {
@ -45,13 +45,13 @@ class LinkedListDeque {
// node
_front!.prev = node;
node.next = _front;
_front = node; //
_front = node; //
} else {
//
// node
_rear!.next = node;
node.prev = _rear;
_rear = node; //
_rear = node; //
}
_queSize++; //
}
@ -75,24 +75,24 @@ class LinkedListDeque {
final int val;
if (isFront) {
//
val = _front!.val; //
//
val = _front!.val; //
//
ListNode? fNext = _front!.next;
if (fNext != null) {
fNext.prev = null;
_front!.next = null;
}
_front = fNext; //
_front = fNext; //
} else {
//
val = _rear!.val; //
//
val = _rear!.val; //
//
ListNode? rPrev = _rear!.prev;
if (rPrev != null) {
rPrev.next = null;
_rear!.prev = null;
}
_rear = rPrev; //
_rear = rPrev; //
}
_queSize--; //
return val;

View File

@ -8,8 +8,8 @@ import '../utils/list_node.dart';
/* 基于链表实现的队列 */
class LinkedListQueue {
ListNode? _front; // _front
ListNode? _rear; // _rear
ListNode? _front; // _front
ListNode? _rear; // _rear
int _queSize = 0; //
LinkedListQueue() {
@ -29,14 +29,14 @@ class LinkedListQueue {
/* 入队 */
void push(int num) {
// num
// num
final node = ListNode(num);
//
//
if (_front == null) {
_front = node;
_rear = node;
} else {
//
//
_rear!.next = node;
_rear = node;
}
@ -46,7 +46,7 @@ class LinkedListQueue {
/* 出队 */
int pop() {
final int num = peek();
//
//
_front = _front!.next;
_queSize--;
return num;

View File

@ -8,7 +8,7 @@ import '../utils/list_node.dart';
/* 基于链表类实现的栈 */
class LinkedListStack {
ListNode? _stackPeek; //
ListNode? _stackPeek; //
int _stkSize = 0; //
LinkedListStack() {

View File

@ -16,22 +16,22 @@ class AVLTree {
root = null;
}
/* 获取点高度 */
/* 获取点高度 */
int height(TreeNode? node) {
return node == null ? -1 : node.height;
}
/* 更新点高度 */
/* 更新点高度 */
void updateHeight(TreeNode? node) {
// + 1
// + 1
node!.height = max(height(node.left), height(node.right)) + 1;
}
/* 获取平衡因子 */
int balanceFactor(TreeNode? node) {
// 0
// 0
if (node == null) return 0;
// = -
// = -
return height(node.left) - height(node.right);
}
@ -42,10 +42,10 @@ class AVLTree {
// child node
child.right = node;
node.left = grandChild;
//
//
updateHeight(node);
updateHeight(child);
//
//
return child;
}
@ -56,16 +56,16 @@ class AVLTree {
// child node
child.left = node;
node.right = grandChild;
//
//
updateHeight(node);
updateHeight(child);
//
//
return child;
}
/* 执行旋转操作,使该子树重新恢复平衡 */
TreeNode? rotate(TreeNode? node) {
// node
// node
int factor = balanceFactor(node);
//
if (factor > 1) {
@ -93,39 +93,39 @@ class AVLTree {
return node;
}
/* 插入点 */
/* 插入点 */
TreeNode? insert(int val) {
root = insertHelper(root, val);
return root;
}
/* 递归插入点(辅助方法) */
/* 递归插入点(辅助方法) */
TreeNode? insertHelper(TreeNode? node, int val) {
if (node == null) return TreeNode(val);
/* 1. 查找插入位置,并插入点 */
/* 1. 查找插入位置,并插入点 */
if (val < node.val)
node.left = insertHelper(node.left, val);
else if (val > node.val)
node.right = insertHelper(node.right, val);
else
return node; //
updateHeight(node); //
return node; //
updateHeight(node); //
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
node = rotate(node);
//
//
return node;
}
/* 删除点 */
/* 删除点 */
TreeNode? remove(int val) {
root = removeHelper(root, val);
return root;
}
/* 递归删除点(辅助方法) */
/* 递归删除点(辅助方法) */
TreeNode? removeHelper(TreeNode? node, int val) {
if (node == null) return null;
/* 1. 查找点,并删除之 */
/* 1. 查找点,并删除之 */
if (val < node.val)
node.left = removeHelper(node.left, val);
else if (val > node.val)
@ -133,48 +133,48 @@ class AVLTree {
else {
if (node.left == null || node.right == null) {
TreeNode? child = node.left ?? node.right;
// = 0 node
// = 0 node
if (child == null)
return null;
// = 1 node
// = 1 node
else
node = child;
} else {
// = 2
// = 2
TreeNode? temp = getInOrderNext(node.right);
node.right = removeHelper(node.right, temp!.val);
node.val = temp.val;
}
}
updateHeight(node); //
updateHeight(node); //
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
node = rotate(node);
//
//
return node;
}
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
/* 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) */
TreeNode? getInOrderNext(TreeNode? node) {
if (node == null) return node;
// 访
// 访
while (node!.left != null) {
node = node.left;
}
return node;
}
/* 查找点 */
/* 查找点 */
TreeNode? search(int val) {
TreeNode? cur = root;
//
//
while (cur != null) {
// cur
// cur
if (val < cur.val)
cur = cur.left;
// cur
// cur
else if (val > cur.val)
cur = cur.right;
//
//
else
break;
}
@ -184,13 +184,13 @@ class AVLTree {
void testInsert(AVLTree tree, int val) {
tree.insert(val);
print("\n插入$valAVL 树为");
print("\n插入$valAVL 树为");
printTree(tree.root);
}
void testRemove(AVLTree tree, int val) {
tree.remove(val);
print("\n删除$valAVL 树为");
print("\n删除$valAVL 树为");
printTree(tree.root);
}
@ -198,8 +198,8 @@ void testRemove(AVLTree tree, int val) {
void main() {
/* 初始化空 AVL 树 */
AVLTree avlTree = AVLTree();
/* 插入点 */
// AVL
/* 插入点 */
// AVL
testInsert(avlTree, 1);
testInsert(avlTree, 2);
testInsert(avlTree, 3);
@ -211,16 +211,16 @@ void main() {
testInsert(avlTree, 10);
testInsert(avlTree, 6);
/* 插入重复点 */
/* 插入重复点 */
testInsert(avlTree, 7);
/* 删除点 */
// AVL
testRemove(avlTree, 8); // 0
testRemove(avlTree, 5); // 1
testRemove(avlTree, 4); // 2
/* 删除点 */
// AVL
testRemove(avlTree, 8); // 0
testRemove(avlTree, 5); // 1
testRemove(avlTree, 4); // 2
/* 查询点 */
/* 查询点 */
TreeNode? node = avlTree.search(7);
print("\n查找到的结点对象为 $node,结点值 = ${node!.val}");
print("\n查找到的节点对象为 $node,节点值 = ${node!.val}");
}

View File

@ -15,7 +15,7 @@ void binarySearchTree(List<int> nums) {
root = buildTree(nums, 0, nums.length - 1); //
}
/* 获取二叉树的根点 */
/* 获取二叉树的根点 */
TreeNode? getRoot() {
return root;
}
@ -25,7 +25,7 @@ TreeNode? buildTree(List<int> nums, int i, int j) {
if (i > j) {
return null;
}
//
//
int mid = (i + j) ~/ 2;
TreeNode? root = TreeNode(nums[mid]);
root.left = buildTree(nums, i, mid - 1);
@ -33,34 +33,34 @@ TreeNode? buildTree(List<int> nums, int i, int j) {
return root;
}
/* 查找点 */
/* 查找点 */
TreeNode? search(int num) {
TreeNode? cur = root;
//
//
while (cur != null) {
// cur
// cur
if (cur.val < num)
cur = cur.right;
// cur
// cur
else if (cur.val > num)
cur = cur.left;
//
//
else
break;
}
//
//
return cur;
}
/* 插入点 */
/* 插入点 */
TreeNode? insert(int num) {
//
if (root == null) return null;
TreeNode? cur = root;
TreeNode? pre = null;
//
//
while (cur != null) {
//
//
if (cur.val == num) return null;
pre = cur;
// cur
@ -70,7 +70,7 @@ TreeNode? insert(int num) {
else
cur = cur.left;
}
// val
// val
TreeNode? node = TreeNode(num);
if (pre!.val < num)
pre.right = node;
@ -79,42 +79,42 @@ TreeNode? insert(int num) {
return node;
}
/* 删除点 */
/* 删除点 */
TreeNode? remove(int num) {
//
if (root == null) return null;
TreeNode? cur = root;
TreeNode? pre = null;
//
//
while (cur != null) {
//
//
if (cur.val == num) break;
pre = cur;
// cur
// cur
if (cur.val < num)
cur = cur.right;
// cur
// cur
else
cur = cur.left;
}
//
//
if (cur == null) return null;
// = 0 or 1
// = 0 or 1
if (cur.left == null || cur.right == null) {
// = 0 / 1 child = null /
// = 0 / 1 child = null /
TreeNode? child = cur.left ?? cur.right;
// cur
// cur
if (pre!.left == cur)
pre.left = child;
else
pre.right = child;
} else {
// = 2
// cur
// = 2
// cur
TreeNode? nex = getInOrderNext(cur.right);
int tem = nex!.val;
// nex
// nex
remove(nex.val);
// nex cur
cur.val = tem;
@ -122,10 +122,10 @@ TreeNode? remove(int num) {
return cur;
}
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
/* 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) */
TreeNode? getInOrderNext(TreeNode? root) {
if (root == null) return null;
// 访
// 访
while (root!.left != null) {
root = root.left;
}
@ -140,23 +140,23 @@ void main() {
print("\n初始化的二叉树为\n");
printTree(getRoot());
/* 查找点 */
/* 查找点 */
TreeNode? node = search(7);
print("\n查找到的结点对象为 $node,结点值 = ${node?.val}");
print("\n查找到的节点对象为 $node,节点值 = ${node?.val}");
/* 插入点 */
/* 插入点 */
node = insert(16);
print("\n插入点 16 后,二叉树为\n");
print("\n插入点 16 后,二叉树为\n");
printTree(getRoot());
/* 删除点 */
/* 删除点 */
remove(1);
print("\n删除点 1 后,二叉树为\n");
print("\n删除点 1 后,二叉树为\n");
printTree(getRoot());
remove(2);
print("\n删除点 2 后,二叉树为\n");
print("\n删除点 2 后,二叉树为\n");
printTree(getRoot());
remove(4);
print("\n删除点 4 后,二叉树为\n");
print("\n删除点 4 后,二叉树为\n");
printTree(getRoot());
}

View File

@ -9,7 +9,7 @@ import '../utils/tree_node.dart';
void main() {
/* 初始化二叉树 */
//
//
TreeNode n1 = TreeNode(1);
TreeNode n2 = TreeNode(2);
TreeNode n3 = TreeNode(3);
@ -23,15 +23,15 @@ void main() {
print("\n初始化二叉树\n");
printTree(n1);
/* 插入与删除点 */
/* 插入与删除点 */
TreeNode p = TreeNode(0);
// n1 -> n2 p
// n1 -> n2 p
n1.left = p;
p.left = n2;
print("\n插入点 P 后\n");
print("\n插入点 P 后\n");
printTree(n1);
// P
// P
n1.left = n2;
print("\n删除点 P 后\n");
print("\n删除点 P 后\n");
printTree(n1);
}

View File

@ -10,16 +10,16 @@ import '../utils/tree_node.dart';
/* 层序遍历 */
List<int> levelOrder(TreeNode? root) {
//
//
Queue<TreeNode?> queue = Queue();
queue.add(root);
//
List<int> res = [];
while (queue.isNotEmpty) {
TreeNode? node = queue.removeFirst(); //
res.add(node!.val); //
if (node.left != null) queue.add(node.left); //
if (node.right != null) queue.add(node.right); //
res.add(node!.val); //
if (node.left != null) queue.add(node.left); //
if (node.right != null) queue.add(node.right); //
}
return res;
}
@ -34,5 +34,5 @@ void main() {
//
List<int> res = levelOrder(root);
print("\n层序遍历的点打印序列 = $res");
print("\n层序遍历的点打印序列 = $res");
}

View File

@ -13,7 +13,7 @@ List<int> list = [];
/* 前序遍历 */
void preOrder(TreeNode? node) {
if (node == null) return;
// 访 -> ->
// 访 -> ->
list.add(node.val);
preOrder(node.left);
preOrder(node.right);
@ -22,7 +22,7 @@ void preOrder(TreeNode? node) {
/* 中序遍历 */
void inOrder(TreeNode? node) {
if (node == null) return;
// 访 -> ->
// 访 -> ->
inOrder(node.left);
list.add(node.val);
inOrder(node.right);
@ -31,7 +31,7 @@ void inOrder(TreeNode? node) {
/* 后序遍历 */
void postOrder(TreeNode? node) {
if (node == null) return;
// 访 -> ->
// 访 -> ->
postOrder(node.left);
postOrder(node.right);
list.add(node.val);
@ -48,15 +48,15 @@ void main() {
/* 前序遍历 */
list.clear();
preOrder(root);
print("\n前序遍历的点打印序列 = $list");
print("\n前序遍历的点打印序列 = $list");
/* 中序遍历 */
list.clear();
inOrder(root);
print("\n中序遍历的点打印序列 = $list");
print("\n中序遍历的点打印序列 = $list");
/* 后序遍历 */
list.clear();
postOrder(root);
print("\n后序遍历的点打印序列 = $list");
print("\n后序遍历的点打印序列 = $list");
}

View File

@ -7,10 +7,10 @@
import 'dart:collection';
class TreeNode {
int val; //
int height; //
TreeNode? left; //
TreeNode? right; //
int val; //
int height; //
TreeNode? left; //
TreeNode? right; //
TreeNode(this.val, [this.height = 0, this.left, this.right]);
}

View File

@ -8,14 +8,14 @@ import (
. "github.com/krahets/hello-algo/pkg"
)
/* 在链表的结点 n0 之后插入结点 P */
/* 在链表的节点 n0 之后插入节点 P */
func insertNode(n0 *ListNode, P *ListNode) {
n1 := n0.Next
P.Next = n1
n0.Next = P
}
/* 删除链表的结点 n0 之后的首个结点 */
/* 删除链表的节点 n0 之后的首个节点 */
func removeNode(n0 *ListNode) {
if n0.Next == nil {
return
@ -26,7 +26,7 @@ func removeNode(n0 *ListNode) {
n0.Next = n1
}
/* 访问链表中索引为 index 的点 */
/* 访问链表中索引为 index 的点 */
func access(head *ListNode, index int) *ListNode {
for i := 0; i < index; i++ {
if head == nil {
@ -37,7 +37,7 @@ func access(head *ListNode, index int) *ListNode {
return head
}
/* 在链表中查找值为 target 的首个点 */
/* 在链表中查找值为 target 的首个点 */
func findNode(head *ListNode, target int) int {
index := 0
for head != nil {

View File

@ -13,7 +13,7 @@ import (
func TestLinkedList(t *testing.T) {
/* 初始化链表 1 -> 3 -> 2 -> 5 -> 4 */
// 初始化各个
// 初始化各个
n0 := NewListNode(1)
n1 := NewListNode(3)
n2 := NewListNode(2)
@ -28,21 +28,21 @@ func TestLinkedList(t *testing.T) {
fmt.Println("初始化的链表为")
PrintLinkedList(n0)
/* 插入点 */
/* 插入点 */
insertNode(n0, NewListNode(0))
fmt.Println("插入点后的链表为")
fmt.Println("插入点后的链表为")
PrintLinkedList(n0)
/* 删除点 */
/* 删除点 */
removeNode(n0)
fmt.Println("删除点后的链表为")
fmt.Println("删除点后的链表为")
PrintLinkedList(n0)
/* 访问点 */
/* 访问点 */
node := access(n0, 3)
fmt.Println("链表中索引 3 处的点的值 =", node)
fmt.Println("链表中索引 3 处的点的值 =", node)
/* 查找点 */
/* 查找点 */
index := findNode(n0, 2)
fmt.Println("链表中值为 2 的点的索引 =", index)
fmt.Println("链表中值为 2 的点的索引 =", index)
}

View File

@ -27,23 +27,23 @@ func newMaxHeap(nums []any) *maxHeap {
// 将列表元素原封不动添加进堆
h := &maxHeap{data: nums}
for i := len(h.data) - 1; i >= 0; i-- {
// 堆化除叶结点以外的其他所有结
// 堆化除叶节点以外的其他所有节
h.siftDown(i)
}
return h
}
/* 获取左子点索引 */
/* 获取左子点索引 */
func (h *maxHeap) left(i int) int {
return 2*i + 1
}
/* 获取右子点索引 */
/* 获取右子点索引 */
func (h *maxHeap) right(i int) int {
return 2*i + 2
}
/* 获取父点索引 */
/* 获取父点索引 */
func (h *maxHeap) parent(i int) int {
// 向下整除
return (i - 1) / 2
@ -71,22 +71,22 @@ func (h *maxHeap) peek() any {
/* 元素入堆 */
func (h *maxHeap) push(val any) {
// 添加
// 添加
h.data = append(h.data, val)
// 从底至顶堆化
h.siftUp(len(h.data) - 1)
}
/* 从点 i 开始,从底至顶堆化 */
/* 从点 i 开始,从底至顶堆化 */
func (h *maxHeap) siftUp(i int) {
for true {
// 获取结点 i 的父结
// 获取节点 i 的父节
p := h.parent(i)
// 当“越过根结点”或“结点无需修复”时,结束堆化
// 当“越过根节点”或“节点无需修复”时,结束堆化
if p < 0 || h.data[i].(int) <= h.data[p].(int) {
break
}
// 交换两
// 交换两
h.swap(i, p)
// 循环向上堆化
i = p
@ -100,9 +100,9 @@ func (h *maxHeap) pop() any {
fmt.Println("error")
return nil
}
// 交换根结点与最右叶结点(即交换首元素与尾元素)
// 交换根节点与最右叶节点(即交换首元素与尾元素)
h.swap(0, h.size()-1)
// 删除
// 删除
val := h.data[len(h.data)-1]
h.data = h.data[:len(h.data)-1]
// 从顶至底堆化
@ -112,10 +112,10 @@ func (h *maxHeap) pop() any {
return val
}
/* 从点 i 开始,从顶至底堆化 */
/* 从点 i 开始,从顶至底堆化 */
func (h *maxHeap) siftDown(i int) {
for true {
// 判断结点 i, l, r 中值最大的结点,记为 max
// 判断节点 i, l, r 中值最大的节点,记为 max
l, r, max := h.left(i), h.right(i), i
if l < h.size() && h.data[l].(int) > h.data[max].(int) {
max = l
@ -123,11 +123,11 @@ func (h *maxHeap) siftDown(i int) {
if r < h.size() && h.data[r].(int) > h.data[max].(int) {
max = r
}
// 若点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
// 若点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if max == i {
break
}
// 交换两
// 交换两
h.swap(i, max)
// 循环向下堆化
i = max

View File

@ -19,7 +19,7 @@ func hashingSearchArray(m map[int]int, target int) int {
/* 哈希查找(链表) */
func hashingSearchLinkedList(m map[int]*ListNode, target int) *ListNode {
// 哈希表的 key: 目标结点值value: 结点对象
// 哈希表的 key: 目标节点值value: 节点对象
// 若哈希表中无此 key ,返回 nil
if node, ok := m[target]; ok {
return node

View File

@ -32,5 +32,5 @@ func TestHashingSearch(t *testing.T) {
head = head.Next
}
node := hashingSearchLinkedList(m1, target)
fmt.Println("目标结点值 3 的对应结点对象为 ", node)
fmt.Println("目标节点值 3 的对应节点对象为 ", node)
}

View File

@ -25,7 +25,7 @@ func linearSearchArray(nums []int, target int) int {
func linearSearchLinkedList(node *ListNode, target int) *ListNode {
// 遍历链表
for node != nil {
// 找到目标点,返回之
// 找到目标点,返回之
if node.Val == target {
return node
}

View File

@ -22,5 +22,5 @@ func TestLinearSearch(t *testing.T) {
// 在链表中执行线性查找
head := ArrayToLinkedList(nums)
node := linearSearchLinkedList(head, target)
fmt.Println("目标结点值 3 的对应结点对象为", node)
fmt.Println("目标节点值 3 的对应节点对象为", node)
}

View File

@ -8,7 +8,7 @@ import . "github.com/krahets/hello-algo/pkg"
/* AVL 树 */
type aVLTree struct {
// 根
// 根
root *TreeNode
}
@ -16,20 +16,20 @@ func newAVLTree() *aVLTree {
return &aVLTree{root: nil}
}
/* 获取点高度 */
/* 获取点高度 */
func (t *aVLTree) height(node *TreeNode) int {
// 空结点高度为 -1 ,叶结点高度为 0
// 空节点高度为 -1 ,叶节点高度为 0
if node != nil {
return node.Height
}
return -1
}
/* 更新点高度 */
/* 更新点高度 */
func (t *aVLTree) updateHeight(node *TreeNode) {
lh := t.height(node.Left)
rh := t.height(node.Right)
// 点高度等于最高子树高度 + 1
// 点高度等于最高子树高度 + 1
if lh > rh {
node.Height = lh + 1
} else {
@ -39,11 +39,11 @@ func (t *aVLTree) updateHeight(node *TreeNode) {
/* 获取平衡因子 */
func (t *aVLTree) balanceFactor(node *TreeNode) int {
// 空点平衡因子为 0
// 空点平衡因子为 0
if node == nil {
return 0
}
// 点平衡因子 = 左子树高度 - 右子树高度
// 点平衡因子 = 左子树高度 - 右子树高度
return t.height(node.Left) - t.height(node.Right)
}
@ -54,10 +54,10 @@ func (t *aVLTree) rightRotate(node *TreeNode) *TreeNode {
// 以 child 为原点,将 node 向右旋转
child.Right = node
node.Left = grandChild
// 更新点高度
// 更新点高度
t.updateHeight(node)
t.updateHeight(child)
// 返回旋转后子树的根
// 返回旋转后子树的根
return child
}
@ -68,16 +68,16 @@ func (t *aVLTree) leftRotate(node *TreeNode) *TreeNode {
// 以 child 为原点,将 node 向左旋转
child.Left = node
node.Right = grandChild
// 更新点高度
// 更新点高度
t.updateHeight(node)
t.updateHeight(child)
// 返回旋转后子树的根
// 返回旋转后子树的根
return child
}
/* 执行旋转操作,使该子树重新恢复平衡 */
func (t *aVLTree) rotate(node *TreeNode) *TreeNode {
// 获取点 node 的平衡因子
// 获取点 node 的平衡因子
// Go 推荐短变量,这里 bf 指代 t.balanceFactor
bf := t.balanceFactor(node)
// 左偏树
@ -106,46 +106,46 @@ func (t *aVLTree) rotate(node *TreeNode) *TreeNode {
return node
}
/* 插入点 */
/* 插入点 */
func (t *aVLTree) insert(val int) *TreeNode {
t.root = t.insertHelper(t.root, val)
return t.root
}
/* 递归插入点(辅助方法) */
/* 递归插入点(辅助方法) */
func (t *aVLTree) insertHelper(node *TreeNode, val int) *TreeNode {
if node == nil {
return NewTreeNode(val)
}
/* 1. 查找插入位置,并插入点 */
/* 1. 查找插入位置,并插入点 */
if val < node.Val {
node.Left = t.insertHelper(node.Left, val)
} else if val > node.Val {
node.Right = t.insertHelper(node.Right, val)
} else {
// 重复点不插入,直接返回
// 重复点不插入,直接返回
return node
}
// 更新点高度
// 更新点高度
t.updateHeight(node)
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
node = t.rotate(node)
// 返回子树的根
// 返回子树的根
return node
}
/* 删除点 */
/* 删除点 */
func (t *aVLTree) remove(val int) *TreeNode {
root := t.removeHelper(t.root, val)
return root
}
/* 递归删除点(辅助方法) */
/* 递归删除点(辅助方法) */
func (t *aVLTree) removeHelper(node *TreeNode, val int) *TreeNode {
if node == nil {
return nil
}
/* 1. 查找点,并删除之 */
/* 1. 查找点,并删除之 */
if val < node.Val {
node.Left = t.removeHelper(node.Left, val)
} else if val > node.Val {
@ -156,56 +156,56 @@ func (t *aVLTree) removeHelper(node *TreeNode, val int) *TreeNode {
if node.Right != nil {
child = node.Right
}
// 子点数量 = 0 ,直接删除 node 并返回
// 子点数量 = 0 ,直接删除 node 并返回
if child == nil {
return nil
} else {
// 子点数量 = 1 ,直接删除 node
// 子点数量 = 1 ,直接删除 node
node = child
}
} else {
// 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结
// 子节点数量 = 2 ,则将中序遍历的下个节点删除,并用该节点替换当前节
temp := t.getInOrderNext(node.Right)
node.Right = t.removeHelper(node.Right, temp.Val)
node.Val = temp.Val
}
}
// 更新点高度
// 更新点高度
t.updateHeight(node)
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
node = t.rotate(node)
// 返回子树的根
// 返回子树的根
return node
}
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
/* 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) */
func (t *aVLTree) getInOrderNext(node *TreeNode) *TreeNode {
if node == nil {
return node
}
// 循环访问左子结点,直到叶结点时为最小结点,跳出
// 循环访问左子节点,直到叶节点时为最小节点,跳出
for node.Left != nil {
node = node.Left
}
return node
}
/* 查找点 */
/* 查找点 */
func (t *aVLTree) search(val int) *TreeNode {
cur := t.root
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
for cur != nil {
if cur.Val < val {
// 目标点在 cur 的右子树中
// 目标点在 cur 的右子树中
cur = cur.Right
} else if cur.Val > val {
// 目标点在 cur 的左子树中
// 目标点在 cur 的左子树中
cur = cur.Left
} else {
// 找到目标点,跳出循环
// 找到目标点,跳出循环
break
}
}
// 返回目标
// 返回目标
return cur
}

View File

@ -14,8 +14,8 @@ import (
func TestAVLTree(t *testing.T) {
/* 初始化空 AVL 树 */
tree := newAVLTree()
/* 插入点 */
// 请关注插入点后AVL 树是如何保持平衡的
/* 插入点 */
// 请关注插入点后AVL 树是如何保持平衡的
testInsert(tree, 1)
testInsert(tree, 2)
testInsert(tree, 3)
@ -27,28 +27,28 @@ func TestAVLTree(t *testing.T) {
testInsert(tree, 10)
testInsert(tree, 6)
/* 插入重复点 */
/* 插入重复点 */
testInsert(tree, 7)
/* 删除点 */
// 请关注删除点后AVL 树是如何保持平衡的
testRemove(tree, 8) // 删除度为 0 的
testRemove(tree, 5) // 删除度为 1 的
testRemove(tree, 4) // 删除度为 2 的
/* 删除点 */
// 请关注删除点后AVL 树是如何保持平衡的
testRemove(tree, 8) // 删除度为 0 的
testRemove(tree, 5) // 删除度为 1 的
testRemove(tree, 4) // 删除度为 2 的
/* 查询点 */
/* 查询点 */
node := tree.search(7)
fmt.Printf("\n查找到的结点对象为 %#v ,结点值 = %d \n", node, node.Val)
fmt.Printf("\n查找到的节点对象为 %#v ,节点值 = %d \n", node, node.Val)
}
func testInsert(tree *aVLTree, val int) {
tree.insert(val)
fmt.Printf("\n插入点 %d 后AVL 树为 \n", val)
fmt.Printf("\n插入点 %d 后AVL 树为 \n", val)
PrintTree(tree.root)
}
func testRemove(tree *aVLTree, val int) {
tree.remove(val)
fmt.Printf("\n删除点 %d 后AVL 树为 \n", val)
fmt.Printf("\n删除点 %d 后AVL 树为 \n", val)
PrintTree(tree.root)
}

View File

@ -28,7 +28,7 @@ func (bst *binarySearchTree) buildTree(nums []int, left, right int) *TreeNode {
if left > right {
return nil
}
// 将数组中间结点作为根结
// 将数组中间节点作为根节
middle := left + (right-left)>>1
root := NewTreeNode(nums[middle])
// 递归构建左子树和右子树
@ -37,53 +37,53 @@ func (bst *binarySearchTree) buildTree(nums []int, left, right int) *TreeNode {
return root
}
/* 获取根点 */
/* 获取根点 */
func (bst *binarySearchTree) getRoot() *TreeNode {
return bst.root
}
/* 获取中序遍历的下一个结点(仅适用于 root 有左子结点的情况) */
/* 获取中序遍历的下一个节点(仅适用于 root 有左子节点的情况) */
func (bst *binarySearchTree) getInOrderNext(node *TreeNode) *TreeNode {
if node == nil {
return node
}
// 循环访问左子结点,直到叶结点时为最小结点,跳出
// 循环访问左子节点,直到叶节点时为最小节点,跳出
for node.Left != nil {
node = node.Left
}
return node
}
/* 查找点 */
/* 查找点 */
func (bst *binarySearchTree) search(num int) *TreeNode {
node := bst.root
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
for node != nil {
if node.Val < num {
// 目标点在 cur 的右子树中
// 目标点在 cur 的右子树中
node = node.Right
} else if node.Val > num {
// 目标点在 cur 的左子树中
// 目标点在 cur 的左子树中
node = node.Left
} else {
// 找到目标点,跳出循环
// 找到目标点,跳出循环
break
}
}
// 返回目标
// 返回目标
return node
}
/* 插入点 */
/* 插入点 */
func (bst *binarySearchTree) insert(num int) *TreeNode {
cur := bst.root
// 若树为空,直接提前返回
if cur == nil {
return nil
}
// 待插入结点之前的结点位置
// 待插入节点之前的节点位置
var pre *TreeNode = nil
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
for cur != nil {
if cur.Val == num {
return nil
@ -95,7 +95,7 @@ func (bst *binarySearchTree) insert(num int) *TreeNode {
cur = cur.Left
}
}
// 插入
// 插入
node := NewTreeNode(num)
if pre.Val < num {
pre.Right = node
@ -105,54 +105,54 @@ func (bst *binarySearchTree) insert(num int) *TreeNode {
return cur
}
/* 删除点 */
/* 删除点 */
func (bst *binarySearchTree) remove(num int) *TreeNode {
cur := bst.root
// 若树为空,直接提前返回
if cur == nil {
return nil
}
// 待删除结点之前的结点位置
// 待删除节点之前的节点位置
var pre *TreeNode = nil
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
for cur != nil {
if cur.Val == num {
break
}
pre = cur
if cur.Val < num {
// 待删除点在右子树中
// 待删除点在右子树中
cur = cur.Right
} else {
// 待删除点在左子树中
// 待删除点在左子树中
cur = cur.Left
}
}
// 若无待删除点,则直接返回
// 若无待删除点,则直接返回
if cur == nil {
return nil
}
// 子点数为 0 或 1
// 子点数为 0 或 1
if cur.Left == nil || cur.Right == nil {
var child *TreeNode = nil
// 取出待删除结点的子结
// 取出待删除节点的子节
if cur.Left != nil {
child = cur.Left
} else {
child = cur.Right
}
// 将子结点替换为待删除结
// 将子节点替换为待删除节
if pre.Left == cur {
pre.Left = child
} else {
pre.Right = child
}
// 子点数为 2
// 子点数为 2
} else {
// 获取中序遍历中待删除结点 cur 的下一个结
// 获取中序遍历中待删除节点 cur 的下一个节
next := bst.getInOrderNext(cur)
temp := next.Val
// 递归删除点 next
// 递归删除点 next
bst.remove(next.Val)
// 将 next 的值复制给 cur
cur.Val = temp

View File

@ -15,27 +15,27 @@ func TestBinarySearchTree(t *testing.T) {
fmt.Println("\n初始化的二叉树为:")
bst.print()
// 获取根
// 获取根
node := bst.getRoot()
fmt.Println("\n二叉树的根点为:", node.Val)
fmt.Println("\n二叉树的根点为:", node.Val)
// 查找
// 查找
node = bst.search(7)
fmt.Println("查找到的结点对象为", node, ",结点值 =", node.Val)
fmt.Println("查找到的节点对象为", node, ",节点值 =", node.Val)
// 插入
// 插入
node = bst.insert(16)
fmt.Println("\n插入点后 16 的二叉树为:")
fmt.Println("\n插入点后 16 的二叉树为:")
bst.print()
// 删除
// 删除
bst.remove(1)
fmt.Println("\n删除点 1 后的二叉树为:")
fmt.Println("\n删除点 1 后的二叉树为:")
bst.print()
bst.remove(2)
fmt.Println("\n删除点 2 后的二叉树为:")
fmt.Println("\n删除点 2 后的二叉树为:")
bst.print()
bst.remove(4)
fmt.Println("\n删除点 4 后的二叉树为:")
fmt.Println("\n删除点 4 后的二叉树为:")
bst.print()
}

View File

@ -12,7 +12,7 @@ import (
/* 层序遍历 */
func levelOrder(root *TreeNode) []int {
// 初始化队列,加入根
// 初始化队列,加入根
queue := list.New()
queue.PushBack(root)
// 初始化一个切片,用于保存遍历序列
@ -20,14 +20,14 @@ func levelOrder(root *TreeNode) []int {
for queue.Len() > 0 {
// 队列出队
node := queue.Remove(queue.Front()).(*TreeNode)
// 保存点值
// 保存点值
nums = append(nums, node.Val)
if node.Left != nil {
// 左子点入队
// 左子点入队
queue.PushBack(node.Left)
}
if node.Right != nil {
// 右子点入队
// 右子点入队
queue.PushBack(node.Right)
}
}

View File

@ -20,5 +20,5 @@ func TestLevelOrder(t *testing.T) {
// 层序遍历
nums := levelOrder(root)
fmt.Println("\n层序遍历的点打印序列 =", nums)
fmt.Println("\n层序遍历的点打印序列 =", nums)
}

View File

@ -15,7 +15,7 @@ func preOrder(node *TreeNode) {
if node == nil {
return
}
// 访问优先级:根点 -> 左子树 -> 右子树
// 访问优先级:根点 -> 左子树 -> 右子树
nums = append(nums, node.Val)
preOrder(node.Left)
preOrder(node.Right)
@ -26,7 +26,7 @@ func inOrder(node *TreeNode) {
if node == nil {
return
}
// 访问优先级:左子树 -> 根点 -> 右子树
// 访问优先级:左子树 -> 根点 -> 右子树
inOrder(node.Left)
nums = append(nums, node.Val)
inOrder(node.Right)
@ -37,7 +37,7 @@ func postOrder(node *TreeNode) {
if node == nil {
return
}
// 访问优先级:左子树 -> 右子树 -> 根
// 访问优先级:左子树 -> 右子树 -> 根
postOrder(node.Left)
postOrder(node.Right)
nums = append(nums, node.Val)

View File

@ -21,15 +21,15 @@ func TestPreInPostOrderTraversal(t *testing.T) {
// 前序遍历
nums = nil
preOrder(root)
fmt.Println("\n前序遍历的点打印序列 =", nums)
fmt.Println("\n前序遍历的点打印序列 =", nums)
// 中序遍历
nums = nil
inOrder(root)
fmt.Println("\n中序遍历的点打印序列 =", nums)
fmt.Println("\n中序遍历的点打印序列 =", nums)
// 后序遍历
nums = nil
postOrder(root)
fmt.Println("\n后序遍历的点打印序列 =", nums)
fmt.Println("\n后序遍历的点打印序列 =", nums)
}

View File

@ -13,7 +13,7 @@ import (
func TestBinaryTree(t *testing.T) {
/* 初始化二叉树 */
// 初始化
// 初始化
n1 := NewTreeNode(1)
n2 := NewTreeNode(2)
n3 := NewTreeNode(3)
@ -27,15 +27,15 @@ func TestBinaryTree(t *testing.T) {
fmt.Println("初始化二叉树")
PrintTree(n1)
/* 插入与删除点 */
// 插入
/* 插入与删除点 */
// 插入
p := NewTreeNode(0)
n1.Left = p
p.Left = n2
fmt.Println("插入点 P 后")
fmt.Println("插入点 P 后")
PrintTree(n1)
// 删除
// 删除
n1.Left = n2
fmt.Println("删除点 P 后")
fmt.Println("删除点 P 后")
PrintTree(n1)
}

View File

@ -9,10 +9,10 @@ import (
)
type TreeNode struct {
Val int // 点值
Height int // 点高度
Left *TreeNode // 左子点引用
Right *TreeNode // 右子点引用
Val int // 点值
Height int // 点高度
Left *TreeNode // 左子点引用
Right *TreeNode // 右子点引用
}
func NewTreeNode(v int) *TreeNode {

View File

@ -9,14 +9,14 @@ package chapter_array_and_linkedlist;
import include.*;
public class linked_list {
/* 在链表的结点 n0 之后插入结点 P */
/* 在链表的节点 n0 之后插入节点 P */
static void insert(ListNode n0, ListNode P) {
ListNode n1 = n0.next;
P.next = n1;
n0.next = P;
}
/* 删除链表的结点 n0 之后的首个结点 */
/* 删除链表的节点 n0 之后的首个节点 */
static void remove(ListNode n0) {
if (n0.next == null)
return;
@ -26,7 +26,7 @@ public class linked_list {
n0.next = n1;
}
/* 访问链表中索引为 index 的点 */
/* 访问链表中索引为 index 的点 */
static ListNode access(ListNode head, int index) {
for (int i = 0; i < index; i++) {
if (head == null)
@ -36,7 +36,7 @@ public class linked_list {
return head;
}
/* 在链表中查找值为 target 的首个点 */
/* 在链表中查找值为 target 的首个点 */
static int find(ListNode head, int target) {
int index = 0;
while (head != null) {
@ -51,7 +51,7 @@ public class linked_list {
/* Driver Code */
public static void main(String[] args) {
/* 初始化链表 */
// 初始化各个
// 初始化各个
ListNode n0 = new ListNode(1);
ListNode n1 = new ListNode(3);
ListNode n2 = new ListNode(2);
@ -65,22 +65,22 @@ public class linked_list {
System.out.println("初始化的链表为");
PrintUtil.printLinkedList(n0);
/* 插入点 */
/* 插入点 */
insert(n0, new ListNode(0));
System.out.println("插入点后的链表为");
System.out.println("插入点后的链表为");
PrintUtil.printLinkedList(n0);
/* 删除点 */
/* 删除点 */
remove(n0);
System.out.println("删除点后的链表为");
System.out.println("删除点后的链表为");
PrintUtil.printLinkedList(n0);
/* 访问点 */
/* 访问点 */
ListNode node = access(n0, 3);
System.out.println("链表中索引 3 处的点的值 = " + node.val);
System.out.println("链表中索引 3 处的点的值 = " + node.val);
/* 查找点 */
/* 查找点 */
int index = find(n0, 2);
System.out.println("链表中值为 2 的点的索引 = " + index);
System.out.println("链表中值为 2 的点的索引 = " + index);
}
}

View File

@ -18,23 +18,23 @@ class MaxHeap {
public MaxHeap(List<Integer> nums) {
// 将列表元素原封不动添加进堆
maxHeap = new ArrayList<>(nums);
// 堆化除叶结点以外的其他所有结
// 堆化除叶节点以外的其他所有节
for (int i = parent(size() - 1); i >= 0; i--) {
siftDown(i);
}
}
/* 获取左子点索引 */
/* 获取左子点索引 */
private int left(int i) {
return 2 * i + 1;
}
/* 获取右子点索引 */
/* 获取右子点索引 */
private int right(int i) {
return 2 * i + 2;
}
/* 获取父点索引 */
/* 获取父点索引 */
private int parent(int i) {
return (i - 1) / 2; // 向下整除
}
@ -65,21 +65,21 @@ class MaxHeap {
/* 元素入堆 */
public void push(int val) {
// 添加
// 添加
maxHeap.add(val);
// 从底至顶堆化
siftUp(size() - 1);
}
/* 从点 i 开始,从底至顶堆化 */
/* 从点 i 开始,从底至顶堆化 */
private void siftUp(int i) {
while (true) {
// 获取结点 i 的父结
// 获取节点 i 的父节
int p = parent(i);
// 越过根结点点无需修复结束堆化
// 越过根节点点无需修复结束堆化
if (p < 0 || maxHeap.get(i) <= maxHeap.get(p))
break;
// 交换两
// 交换两
swap(i, p);
// 循环向上堆化
i = p;
@ -91,9 +91,9 @@ class MaxHeap {
// 判空处理
if (isEmpty())
throw new EmptyStackException();
// 交换根结点与最右叶结即交换首元素与尾元素
// 交换根节点与最右叶节即交换首元素与尾元素
swap(0, size() - 1);
// 删除
// 删除
int val = maxHeap.remove(size() - 1);
// 从顶至底堆化
siftDown(0);
@ -101,18 +101,18 @@ class MaxHeap {
return val;
}
/* 从点 i 开始,从顶至底堆化 */
/* 从点 i 开始,从顶至底堆化 */
private void siftDown(int i) {
while (true) {
// 判断 i, l, r 中值最大的记为 ma
// 判断 i, l, r 中值最大的记为 ma
int l = left(i), r = right(i), ma = i;
if (l < size() && maxHeap.get(l) > maxHeap.get(ma))
ma = l;
if (r < size() && maxHeap.get(r) > maxHeap.get(ma))
ma = r;
// i 最大或索引 l, r 越界则无需继续堆化跳出
// i 最大或索引 l, r 越界则无需继续堆化跳出
if (ma == i) break;
// 交换两
// 交换两
swap(i, ma);
// 循环向下堆化
i = ma;

View File

@ -19,7 +19,7 @@ public class hashing_search {
/* 哈希查找(链表) */
static ListNode hashingSearchLinkedList(Map<Integer, ListNode> map, int target) {
// 哈希表的 key: 目标结点值value: 点对象
// 哈希表的 key: 目标节点值value: 点对象
// 若哈希表中无此 key 返回 null
return map.getOrDefault(target, null);
}
@ -42,10 +42,10 @@ public class hashing_search {
// 初始化哈希表
Map<Integer, ListNode> map1 = new HashMap<>();
while (head != null) {
map1.put(head.val, head); // key: 结点值value:
map1.put(head.val, head); // key: 节点值value:
head = head.next;
}
ListNode node = hashingSearchLinkedList(map1, target);
System.out.println("目标结点值 3 的对应结点对象为 " + node);
System.out.println("目标节点值 3 的对应节点对象为 " + node);
}
}

View File

@ -25,12 +25,12 @@ public class linear_search {
static ListNode linearSearchLinkedList(ListNode head, int target) {
// 遍历链表
while (head != null) {
// 找到目标返回之
// 找到目标返回之
if (head.val == target)
return head;
head = head.next;
}
// 未找到目标返回 null
// 未找到目标返回 null
return null;
}
@ -45,6 +45,6 @@ public class linear_search {
/* 在链表中执行线性查找 */
ListNode head = ListNode.arrToLinkedList(nums);
ListNode node = linearSearchLinkedList(head, target);
System.out.println("目标结点值 3 的对应结点对象为 " + node);
System.out.println("目标节点值 3 的对应节点对象为 " + node);
}
}

View File

@ -8,11 +8,11 @@ package chapter_stack_and_queue;
import java.util.*;
/* 双向链表点 */
/* 双向链表点 */
class ListNode {
int val; // 点值
ListNode next; // 后继点引用指针
ListNode prev; // 前驱点引用指针
int val; // 点值
ListNode next; // 后继点引用指针
ListNode prev; // 前驱点引用指针
ListNode(int val) {
this.val = val;
prev = next = null;
@ -21,7 +21,7 @@ class ListNode {
/* 基于双向链表实现的双向队列 */
class LinkedListDeque {
private ListNode front, rear; // 结点 front 尾结 rear
private ListNode front, rear; // 节点 front 尾节 rear
private int queSize = 0; // 双向队列的长度
public LinkedListDeque() {
@ -49,13 +49,13 @@ class LinkedListDeque {
// node 添加至链表头部
front.prev = node;
node.next = front;
front = node; // 更新头
front = node; // 更新头
// 队尾入队操作
} else {
// node 添加至链表尾部
rear.next = node;
node.prev = rear;
rear = node; // 更新尾
rear = node; // 更新尾
}
queSize++; // 更新队列长度
}
@ -78,24 +78,24 @@ class LinkedListDeque {
int val;
// 队首出队操作
if (isFront) {
val = front.val; // 暂存头点值
// 删除头
val = front.val; // 暂存头点值
// 删除头
ListNode fNext = front.next;
if (fNext != null) {
fNext.prev = null;
front.next = null;
}
front = fNext; // 更新头
front = fNext; // 更新头
// 队尾出队操作
} else {
val = rear.val; // 暂存尾点值
// 删除尾
val = rear.val; // 暂存尾点值
// 删除尾
ListNode rPrev = rear.prev;
if (rPrev != null) {
rPrev.next = null;
rear.prev = null;
}
rear = rPrev; // 更新尾
rear = rPrev; // 更新尾
}
queSize--; // 更新队列长度
return val;

View File

@ -10,7 +10,7 @@ import java.util.*;
/* 基于链表实现的队列 */
class LinkedListQueue {
private ListNode front, rear; // 结点 front 尾结 rear
private ListNode front, rear; // 节点 front 尾节 rear
private int queSize = 0;
public LinkedListQueue() {
@ -30,13 +30,13 @@ class LinkedListQueue {
/* 入队 */
public void push(int num) {
// 点后添加 num
// 点后添加 num
ListNode node = new ListNode(num);
// 如果队列为空则令头结点都指向该结
// 如果队列为空则令头节点都指向该节
if (front == null) {
front = node;
rear = node;
// 如果队列不为空则将该结点添加到尾结点后
// 如果队列不为空则将该节点添加到尾节点后
} else {
rear.next = node;
rear = node;
@ -47,7 +47,7 @@ class LinkedListQueue {
/* 出队 */
public int pop() {
int num = peek();
// 删除头
// 删除头
front = front.next;
queSize--;
return num;

View File

@ -11,7 +11,7 @@ import include.*;
/* 基于链表实现的栈 */
class LinkedListStack {
private ListNode stackPeek; // 将头点作为栈顶
private ListNode stackPeek; // 将头点作为栈顶
private int stkSize = 0; // 栈的长度
public LinkedListStack() {

View File

@ -10,25 +10,25 @@ import include.*;
/* AVL 树 */
class AVLTree {
TreeNode root; //
TreeNode root; //
/* 获取点高度 */
/* 获取点高度 */
public int height(TreeNode node) {
// 结点高度为 -1 叶结点高度为 0
// 节点高度为 -1 叶节点高度为 0
return node == null ? -1 : node.height;
}
/* 更新点高度 */
/* 更新点高度 */
private void updateHeight(TreeNode node) {
// 点高度等于最高子树高度 + 1
// 点高度等于最高子树高度 + 1
node.height = Math.max(height(node.left), height(node.right)) + 1;
}
/* 获取平衡因子 */
public int balanceFactor(TreeNode node) {
// 点平衡因子为 0
// 点平衡因子为 0
if (node == null) return 0;
// 点平衡因子 = 左子树高度 - 右子树高度
// 点平衡因子 = 左子树高度 - 右子树高度
return height(node.left) - height(node.right);
}
@ -39,10 +39,10 @@ class AVLTree {
// child 为原点 node 向右旋转
child.right = node;
node.left = grandChild;
// 更新点高度
// 更新点高度
updateHeight(node);
updateHeight(child);
// 返回旋转后子树的根
// 返回旋转后子树的根
return child;
}
@ -53,16 +53,16 @@ class AVLTree {
// child 为原点 node 向左旋转
child.left = node;
node.right = grandChild;
// 更新点高度
// 更新点高度
updateHeight(node);
updateHeight(child);
// 返回旋转后子树的根
// 返回旋转后子树的根
return child;
}
/* 执行旋转操作,使该子树重新恢复平衡 */
private TreeNode rotate(TreeNode node) {
// 获取 node 的平衡因子
// 获取 node 的平衡因子
int balanceFactor = balanceFactor(node);
// 左偏树
if (balanceFactor > 1) {
@ -90,39 +90,39 @@ class AVLTree {
return node;
}
/* 插入点 */
/* 插入点 */
public TreeNode insert(int val) {
root = insertHelper(root, val);
return root;
}
/* 递归插入点(辅助方法) */
/* 递归插入点(辅助方法) */
private TreeNode insertHelper(TreeNode node, int val) {
if (node == null) return new TreeNode(val);
/* 1. 查找插入位置,并插入点 */
/* 1. 查找插入位置,并插入点 */
if (val < node.val)
node.left = insertHelper(node.left, val);
else if (val > node.val)
node.right = insertHelper(node.right, val);
else
return node; // 重复点不插入直接返回
updateHeight(node); // 更新点高度
return node; // 重复点不插入直接返回
updateHeight(node); // 更新点高度
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
node = rotate(node);
// 返回子树的根
// 返回子树的根
return node;
}
/* 删除点 */
/* 删除点 */
public TreeNode remove(int val) {
root = removeHelper(root, val);
return root;
}
/* 递归删除点(辅助方法) */
/* 递归删除点(辅助方法) */
private TreeNode removeHelper(TreeNode node, int val) {
if (node == null) return null;
/* 1. 查找点,并删除之 */
/* 1. 查找点,并删除之 */
if (val < node.val)
node.left = removeHelper(node.left, val);
else if (val > node.val)
@ -130,52 +130,52 @@ class AVLTree {
else {
if (node.left == null || node.right == null) {
TreeNode child = node.left != null ? node.left : node.right;
// 点数量 = 0 直接删除 node 并返回
// 点数量 = 0 直接删除 node 并返回
if (child == null)
return null;
// 点数量 = 1 直接删除 node
// 点数量 = 1 直接删除 node
else
node = child;
} else {
// 点数量 = 2 则将中序遍历的下个结点删除并用该结点替换当前结
// 点数量 = 2 则将中序遍历的下个节点删除并用该节点替换当前节
TreeNode temp = getInOrderNext(node.right);
node.right = removeHelper(node.right, temp.val);
node.val = temp.val;
}
}
updateHeight(node); // 更新点高度
updateHeight(node); // 更新点高度
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
node = rotate(node);
// 返回子树的根
// 返回子树的根
return node;
}
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
/* 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) */
private TreeNode getInOrderNext(TreeNode node) {
if (node == null) return node;
// 循环访问左子结点直到叶结点时为最小结跳出
// 循环访问左子节点直到叶节点时为最小节跳出
while (node.left != null) {
node = node.left;
}
return node;
}
/* 查找点 */
/* 查找点 */
public TreeNode search(int val) {
TreeNode cur = root;
// 循环查找越过叶点后跳出
// 循环查找越过叶点后跳出
while (cur != null) {
// 目标点在 cur 的右子树中
// 目标点在 cur 的右子树中
if (cur.val < val)
cur = cur.right;
// 目标点在 cur 的左子树中
// 目标点在 cur 的左子树中
else if (cur.val > val)
cur = cur.left;
// 找到目标跳出循环
// 找到目标跳出循环
else
break;
}
// 返回目标
// 返回目标
return cur;
}
}
@ -183,13 +183,13 @@ class AVLTree {
public class avl_tree {
static void testInsert(AVLTree tree, int val) {
tree.insert(val);
System.out.println("\n插入" + val + "AVL 树为");
System.out.println("\n插入" + val + "AVL 树为");
PrintUtil.printTree(tree.root);
}
static void testRemove(AVLTree tree, int val) {
tree.remove(val);
System.out.println("\n删除" + val + "AVL 树为");
System.out.println("\n删除" + val + "AVL 树为");
PrintUtil.printTree(tree.root);
}
@ -197,8 +197,8 @@ public class avl_tree {
/* 初始化空 AVL 树 */
AVLTree avlTree = new AVLTree();
/* 插入点 */
// 请关注插入点后AVL 树是如何保持平衡的
/* 插入点 */
// 请关注插入点后AVL 树是如何保持平衡的
testInsert(avlTree, 1);
testInsert(avlTree, 2);
testInsert(avlTree, 3);
@ -210,17 +210,17 @@ public class avl_tree {
testInsert(avlTree, 10);
testInsert(avlTree, 6);
/* 插入重复点 */
/* 插入重复点 */
testInsert(avlTree, 7);
/* 删除点 */
// 请关注删除点后AVL 树是如何保持平衡的
testRemove(avlTree, 8); // 删除度为 0
testRemove(avlTree, 5); // 删除度为 1
testRemove(avlTree, 4); // 删除度为 2
/* 删除点 */
// 请关注删除点后AVL 树是如何保持平衡的
testRemove(avlTree, 8); // 删除度为 0
testRemove(avlTree, 5); // 删除度为 1
testRemove(avlTree, 4); // 删除度为 2
/* 查询点 */
/* 查询点 */
TreeNode node = avlTree.search(7);
System.out.println("\n查找到的点对象为 " + node + "点值 = " + node.val);
System.out.println("\n查找到的点对象为 " + node + "点值 = " + node.val);
}
}

View File

@ -18,7 +18,7 @@ class BinarySearchTree {
root = buildTree(nums, 0, nums.length - 1); // 构建二叉搜索树
}
/* 获取二叉树根点 */
/* 获取二叉树根点 */
public TreeNode getRoot() {
return root;
}
@ -26,7 +26,7 @@ class BinarySearchTree {
/* 构建二叉搜索树 */
public TreeNode buildTree(int[] nums, int i, int j) {
if (i > j) return null;
// 将数组中间结点作为根结
// 将数组中间节点作为根节
int mid = (i + j) / 2;
TreeNode root = new TreeNode(nums[mid]);
// 递归建立左子树和右子树
@ -35,30 +35,30 @@ class BinarySearchTree {
return root;
}
/* 查找点 */
/* 查找点 */
public TreeNode search(int num) {
TreeNode cur = root;
// 循环查找越过叶点后跳出
// 循环查找越过叶点后跳出
while (cur != null) {
// 目标点在 cur 的右子树中
// 目标点在 cur 的右子树中
if (cur.val < num) cur = cur.right;
// 目标点在 cur 的左子树中
// 目标点在 cur 的左子树中
else if (cur.val > num) cur = cur.left;
// 找到目标跳出循环
// 找到目标跳出循环
else break;
}
// 返回目标
// 返回目标
return cur;
}
/* 插入点 */
/* 插入点 */
public TreeNode insert(int num) {
// 若树为空直接提前返回
if (root == null) return null;
TreeNode cur = root, pre = null;
// 循环查找越过叶点后跳出
// 循环查找越过叶点后跳出
while (cur != null) {
// 找到重复直接返回
// 找到重复直接返回
if (cur.val == num) return null;
pre = cur;
// 插入位置在 cur 的右子树中
@ -66,44 +66,44 @@ class BinarySearchTree {
// 插入位置在 cur 的左子树中
else cur = cur.left;
}
// 插入 val
// 插入 val
TreeNode node = new TreeNode(num);
if (pre.val < num) pre.right = node;
else pre.left = node;
return node;
}
/* 删除点 */
/* 删除点 */
public TreeNode remove(int num) {
// 若树为空直接提前返回
if (root == null) return null;
TreeNode cur = root, pre = null;
// 循环查找越过叶点后跳出
// 循环查找越过叶点后跳出
while (cur != null) {
// 找到待删除跳出循环
// 找到待删除跳出循环
if (cur.val == num) break;
pre = cur;
// 待删除点在 cur 的右子树中
// 待删除点在 cur 的右子树中
if (cur.val < num) cur = cur.right;
// 待删除点在 cur 的左子树中
// 待删除点在 cur 的左子树中
else cur = cur.left;
}
// 若无待删除则直接返回
// 若无待删除则直接返回
if (cur == null) return null;
// 点数量 = 0 or 1
// 点数量 = 0 or 1
if (cur.left == null || cur.right == null) {
// 当子点数量 = 0 / 1 child = null / 该子
// 当子点数量 = 0 / 1 child = null / 该子
TreeNode child = cur.left != null ? cur.left : cur.right;
// 删除 cur
// 删除 cur
if (pre.left == cur) pre.left = child;
else pre.right = child;
}
// 点数量 = 2
// 点数量 = 2
else {
// 获取中序遍历中 cur 的下一个
// 获取中序遍历中 cur 的下一个
TreeNode nex = getInOrderNext(cur.right);
int tmp = nex.val;
// 递归删除 nex
// 递归删除 nex
remove(nex.val);
// nex 的值复制给 cur
cur.val = tmp;
@ -111,10 +111,10 @@ class BinarySearchTree {
return cur;
}
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
/* 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) */
public TreeNode getInOrderNext(TreeNode root) {
if (root == null) return root;
// 循环访问左子结点直到叶结点时为最小结跳出
// 循环访问左子节点直到叶节点时为最小节跳出
while (root.left != null) {
root = root.left;
}
@ -130,24 +130,24 @@ public class binary_search_tree {
System.out.println("\n初始化的二叉树为\n");
PrintUtil.printTree(bst.getRoot());
/* 查找点 */
/* 查找点 */
TreeNode node = bst.search(7);
System.out.println("\n查找到的点对象为 " + node + "点值 = " + node.val);
System.out.println("\n查找到的点对象为 " + node + "点值 = " + node.val);
/* 插入点 */
/* 插入点 */
node = bst.insert(16);
System.out.println("\n插入点 16 后,二叉树为\n");
System.out.println("\n插入点 16 后,二叉树为\n");
PrintUtil.printTree(bst.getRoot());
/* 删除点 */
/* 删除点 */
bst.remove(1);
System.out.println("\n删除点 1 后,二叉树为\n");
System.out.println("\n删除点 1 后,二叉树为\n");
PrintUtil.printTree(bst.getRoot());
bst.remove(2);
System.out.println("\n删除点 2 后,二叉树为\n");
System.out.println("\n删除点 2 后,二叉树为\n");
PrintUtil.printTree(bst.getRoot());
bst.remove(4);
System.out.println("\n删除点 4 后,二叉树为\n");
System.out.println("\n删除点 4 后,二叉树为\n");
PrintUtil.printTree(bst.getRoot());
}
}

View File

@ -11,7 +11,7 @@ import include.*;
public class binary_tree {
public static void main(String[] args) {
/* 初始化二叉树 */
// 初始化
// 初始化
TreeNode n1 = new TreeNode(1);
TreeNode n2 = new TreeNode(2);
TreeNode n3 = new TreeNode(3);
@ -25,16 +25,16 @@ public class binary_tree {
System.out.println("\n初始化二叉树\n");
PrintUtil.printTree(n1);
/* 插入与删除点 */
/* 插入与删除点 */
TreeNode P = new TreeNode(0);
// n1 -> n2 中间插入 P
// n1 -> n2 中间插入 P
n1.left = P;
P.left = n2;
System.out.println("\n插入点 P 后\n");
System.out.println("\n插入点 P 后\n");
PrintUtil.printTree(n1);
// 删除 P
// 删除 P
n1.left = n2;
System.out.println("\n删除点 P 后\n");
System.out.println("\n删除点 P 后\n");
PrintUtil.printTree(n1);
}
}

View File

@ -12,17 +12,17 @@ import java.util.*;
public class binary_tree_bfs {
/* 层序遍历 */
static List<Integer> levelOrder(TreeNode root) {
// 初始化队列加入根
// 初始化队列加入根
Queue<TreeNode> queue = new LinkedList<>() {{ add(root); }};
// 初始化一个列表用于保存遍历序列
List<Integer> list = new ArrayList<>();
while (!queue.isEmpty()) {
TreeNode node = queue.poll(); // 队列出队
list.add(node.val); // 保存点值
list.add(node.val); // 保存点值
if (node.left != null)
queue.offer(node.left); // 左子点入队
queue.offer(node.left); // 左子点入队
if (node.right != null)
queue.offer(node.right); // 右子点入队
queue.offer(node.right); // 右子点入队
}
return list;
}
@ -36,6 +36,6 @@ public class binary_tree_bfs {
/* 层序遍历 */
List<Integer> list = levelOrder(root);
System.out.println("\n层序遍历的点打印序列 = " + list);
System.out.println("\n层序遍历的点打印序列 = " + list);
}
}

View File

@ -16,7 +16,7 @@ public class binary_tree_dfs {
/* 前序遍历 */
static void preOrder(TreeNode root) {
if (root == null) return;
// 访问优先级 -> 左子树 -> 右子树
// 访问优先级 -> 左子树 -> 右子树
list.add(root.val);
preOrder(root.left);
preOrder(root.right);
@ -25,7 +25,7 @@ public class binary_tree_dfs {
/* 中序遍历 */
static void inOrder(TreeNode root) {
if (root == null) return;
// 访问优先级左子树 -> -> 右子树
// 访问优先级左子树 -> -> 右子树
inOrder(root.left);
list.add(root.val);
inOrder(root.right);
@ -34,7 +34,7 @@ public class binary_tree_dfs {
/* 后序遍历 */
static void postOrder(TreeNode root) {
if (root == null) return;
// 访问优先级左子树 -> 右子树 ->
// 访问优先级左子树 -> 右子树 ->
postOrder(root.left);
postOrder(root.right);
list.add(root.val);
@ -50,16 +50,16 @@ public class binary_tree_dfs {
/* 前序遍历 */
list.clear();
preOrder(root);
System.out.println("\n前序遍历的点打印序列 = " + list);
System.out.println("\n前序遍历的点打印序列 = " + list);
/* 中序遍历 */
list.clear();
inOrder(root);
System.out.println("\n中序遍历的点打印序列 = " + list);
System.out.println("\n中序遍历的点打印序列 = " + list);
/* 后序遍历 */
list.clear();
postOrder(root);
System.out.println("\n后序遍历的点打印序列 = " + list);
System.out.println("\n后序遍历的点打印序列 = " + list);
}
}

View File

@ -12,10 +12,10 @@ import java.util.*;
* Definition for a binary tree node.
*/
public class TreeNode {
public int val; // 点值
public int height; // 点高度
public TreeNode left; // 左子点引用
public TreeNode right; // 右子点引用
public int val; // 点值
public int height; // 点高度
public TreeNode left; // 左子点引用
public TreeNode right; // 右子点引用
public TreeNode(int x) {
val = x;

View File

@ -7,14 +7,14 @@
const { printLinkedList } = require("../modules/PrintUtil");
const { ListNode } = require("../modules/ListNode");
/* 在链表的结点 n0 之后插入结点 P */
/* 在链表的节点 n0 之后插入节点 P */
function insert(n0, P) {
const n1 = n0.next;
P.next = n1;
n0.next = P;
}
/* 删除链表的结点 n0 之后的首个结点 */
/* 删除链表的节点 n0 之后的首个节点 */
function remove(n0) {
if (!n0.next)
return;
@ -24,7 +24,7 @@ function remove(n0) {
n0.next = n1;
}
/* 访问链表中索引为 index 的点 */
/* 访问链表中索引为 index 的点 */
function access(head, index) {
for (let i = 0; i < index; i++) {
if (!head) {
@ -35,7 +35,7 @@ function access(head, index) {
return head;
}
/* 在链表中查找值为 target 的首个点 */
/* 在链表中查找值为 target 的首个点 */
function find(head, target) {
let index = 0;
while (head !== null) {
@ -50,7 +50,7 @@ function find(head, target) {
/* Driver Code */
/* 初始化链表 */
// 初始化各个
// 初始化各个
const n0 = new ListNode(1);
const n1 = new ListNode(3);
const n2 = new ListNode(2);
@ -64,20 +64,20 @@ n3.next = n4;
console.log("初始化的链表为");
printLinkedList(n0);
/* 插入点 */
/* 插入点 */
insert(n0, new ListNode(0));
console.log("插入点后的链表为");
console.log("插入点后的链表为");
printLinkedList(n0);
/* 删除点 */
/* 删除点 */
remove(n0);
console.log("删除点后的链表为");
console.log("删除点后的链表为");
printLinkedList(n0);
/* 访问点 */
/* 访问点 */
const node = access(n0, 3);
console.log("链表中索引 3 处的点的值 = " + node.val);
console.log("链表中索引 3 处的点的值 = " + node.val);
/* 查找点 */
/* 查找点 */
const index = find(n0, 2);
console.log("链表中值为 2 的点的索引 = " + index);
console.log("链表中值为 2 的点的索引 = " + index);

View File

@ -14,23 +14,23 @@ class MaxHeap {
constructor(nums) {
// 将列表元素原封不动添加进堆
this.#maxHeap = nums === undefined ? [] : [...nums];
// 堆化除叶结点以外的其他所有结
// 堆化除叶节点以外的其他所有节
for (let i = this.#parent(this.size() - 1); i >= 0; i--) {
this.#siftDown(i);
}
}
/* 获取左子点索引 */
/* 获取左子点索引 */
#left(i) {
return 2 * i + 1;
}
/* 获取右子点索引 */
/* 获取右子点索引 */
#right(i) {
return 2 * i + 2;
}
/* 获取父点索引 */
/* 获取父点索引 */
#parent(i) {
return Math.floor((i - 1) / 2); // 向下整除
}
@ -61,20 +61,20 @@ class MaxHeap {
/* 元素入堆 */
push(val) {
// 添加
// 添加
this.#maxHeap.push(val);
// 从底至顶堆化
this.#siftUp(this.size() - 1);
}
/* 从点 i 开始,从底至顶堆化 */
/* 从点 i 开始,从底至顶堆化 */
#siftUp(i) {
while (true) {
// 获取结点 i 的父结
// 获取节点 i 的父节
const p = this.#parent(i);
// 当“越过根结点”或“结点无需修复”时,结束堆化
// 当“越过根节点”或“节点无需修复”时,结束堆化
if (p < 0 || this.#maxHeap[i] <= this.#maxHeap[p]) break;
// 交换两
// 交换两
this.#swap(i, p);
// 循环向上堆化
i = p;
@ -85,9 +85,9 @@ class MaxHeap {
pop() {
// 判空处理
if (this.isEmpty()) throw new Error("堆为空");
// 交换根结点与最右叶结点(即交换首元素与尾元素)
// 交换根节点与最右叶节点(即交换首元素与尾元素)
this.#swap(0, this.size() - 1);
// 删除
// 删除
const val = this.#maxHeap.pop();
// 从顶至底堆化
this.#siftDown(0);
@ -95,18 +95,18 @@ class MaxHeap {
return val;
}
/* 从点 i 开始,从顶至底堆化 */
/* 从点 i 开始,从顶至底堆化 */
#siftDown(i) {
while (true) {
// 判断结点 i, l, r 中值最大的结点,记为 ma
// 判断节点 i, l, r 中值最大的节点,记为 ma
const l = this.#left(i),
r = this.#right(i);
let ma = i;
if (l < this.size() && this.#maxHeap[l] > this.#maxHeap[ma]) ma = l;
if (r < this.size() && this.#maxHeap[r] > this.#maxHeap[ma]) ma = r;
// 若点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
// 若点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if (ma == i) break;
// 交换两
// 交换两
this.#swap(i, ma);
// 循环向下堆化
i = ma;

View File

@ -15,7 +15,7 @@ function hashingSearchArray(map, target) {
/* 哈希查找(链表) */
function hashingSearchLinkedList(map, target) {
// 哈希表的 key: 目标结点值value: 结点对象
// 哈希表的 key: 目标节点值value: 节点对象
// 若哈希表中无此 key ,返回 null
return map.has(target) ? map.get(target) : null;
}
@ -38,8 +38,8 @@ let head = arrToLinkedList(nums)
// 初始化哈希表
const map1 = new Map();
while (head != null) {
map1.set(head.val, head); // key: 结点值value: 结
map1.set(head.val, head); // key: 节点值value: 节
head = head.next;
}
const node = hashingSearchLinkedList(map1, target);
console.log("目标结点值 3 的对应结点对象为", node);
console.log("目标节点值 3 的对应节点对象为", node);

View File

@ -23,13 +23,13 @@ function linearSearchArray(nums, target) {
function linearSearchLinkedList(head, target) {
// 遍历链表
while(head) {
// 找到目标点,返回之
// 找到目标点,返回之
if(head.val === target) {
return head;
}
head = head.next;
}
// 未找到目标点,返回 null
// 未找到目标点,返回 null
return null;
}
@ -44,4 +44,4 @@ console.log("目标元素 3 的索引 = " + index);
/* 在链表中执行线性查找 */
const head = arrToLinkedList(nums);
const node = linearSearchLinkedList(head, target);
console.log("目标结点值 3 的对应结点对象为 ", node);
console.log("目标节点值 3 的对应节点对象为 ", node);

View File

@ -4,11 +4,11 @@
* Author: Zhuo Qinyue (1403450829@qq.com)
*/
/* 双向链表点 */
/* 双向链表点 */
class ListNode {
prev; // 前驱点引用 (指针)
next; // 后继点引用 (指针)
val; // 点值
prev; // 前驱点引用 (指针)
next; // 后继点引用 (指针)
val; // 点值
constructor(val) {
this.val = val;
@ -19,8 +19,8 @@ class ListNode {
/* 基于双向链表实现的双向队列 */
class LinkedListDeque {
#front; // 头点 front
#rear; // 尾点 rear
#front; // 头点 front
#rear; // 尾点 rear
#queSize; // 双向队列的长度
constructor() {
@ -40,7 +40,7 @@ class LinkedListDeque {
// 将 node 添加至链表尾部
this.#rear.next = node;
node.prev = this.#rear;
this.#rear = node; // 更新尾
this.#rear = node; // 更新尾
}
this.#queSize++;
}
@ -56,7 +56,7 @@ class LinkedListDeque {
// 将 node 添加至链表头部
this.#front.prev = node;
node.next = this.#front;
this.#front = node; // 更新头
this.#front = node; // 更新头
}
this.#queSize++;
}
@ -66,14 +66,14 @@ class LinkedListDeque {
if (this.#queSize === 0) {
return null;
}
const value = this.#rear.val; // 存储尾点值
// 删除尾
const value = this.#rear.val; // 存储尾点值
// 删除尾
let temp = this.#rear.prev;
if (temp !== null) {
temp.next = null;
this.#rear.prev = null;
}
this.#rear = temp; // 更新尾
this.#rear = temp; // 更新尾
this.#queSize--;
return value;
}
@ -83,14 +83,14 @@ class LinkedListDeque {
if (this.#queSize === 0) {
return null;
}
const value = this.#front.val; // 存储尾点值
// 删除头
const value = this.#front.val; // 存储尾点值
// 删除头
let temp = this.#front.next;
if (temp !== null) {
temp.prev = null;
this.#front.next = null;
}
this.#front = temp; // 更新头
this.#front = temp; // 更新头
this.#queSize--;
return value;
}

View File

@ -8,8 +8,8 @@ const { ListNode } = require("../modules/ListNode");
/* 基于链表实现的队列 */
class LinkedListQueue {
#front; // 头点 #front
#rear; // 尾点 #rear
#front; // 头点 #front
#rear; // 尾点 #rear
#queSize = 0;
constructor() {
@ -29,13 +29,13 @@ class LinkedListQueue {
/* 入队 */
push(num) {
// 尾点后添加 num
// 尾点后添加 num
const node = new ListNode(num);
// 如果队列为空,则令头、尾结点都指向该结
// 如果队列为空,则令头、尾节点都指向该节
if (!this.#front) {
this.#front = node;
this.#rear = node;
// 如果队列不为空,则将该结点添加到尾结点后
// 如果队列不为空,则将该节点添加到尾节点后
} else {
this.#rear.next = node;
this.#rear = node;
@ -46,7 +46,7 @@ class LinkedListQueue {
/* 出队 */
pop() {
const num = this.peek();
// 删除头
// 删除头
this.#front = this.#front.next;
this.#queSize--;
return num;

View File

@ -8,7 +8,7 @@ const { ListNode } = require("../modules/ListNode");
/* 基于链表实现的栈 */
class LinkedListStack {
#stackPeek; // 将头点作为栈顶
#stackPeek; // 将头点作为栈顶
#stkSize = 0; // 栈的长度
constructor() {

View File

@ -11,26 +11,26 @@ const { printTree } = require("../modules/PrintUtil");
class AVLTree {
/*构造方法*/
constructor() {
this.root = null; //根
this.root = null; //根
}
/* 获取点高度 */
/* 获取点高度 */
height(node) {
// 空结点高度为 -1 ,叶结点高度为 0
// 空节点高度为 -1 ,叶节点高度为 0
return node === null ? -1 : node.height;
}
/* 更新点高度 */
/* 更新点高度 */
#updateHeight(node) {
// 点高度等于最高子树高度 + 1
// 点高度等于最高子树高度 + 1
node.height = Math.max(this.height(node.left), this.height(node.right)) + 1;
}
/* 获取平衡因子 */
balanceFactor(node) {
// 空点平衡因子为 0
// 空点平衡因子为 0
if (node === null) return 0;
// 点平衡因子 = 左子树高度 - 右子树高度
// 点平衡因子 = 左子树高度 - 右子树高度
return this.height(node.left) - this.height(node.right);
}
@ -41,10 +41,10 @@ class AVLTree {
// 以 child 为原点,将 node 向右旋转
child.right = node;
node.left = grandChild;
// 更新点高度
// 更新点高度
this.#updateHeight(node);
this.#updateHeight(child);
// 返回旋转后子树的根
// 返回旋转后子树的根
return child;
}
@ -55,16 +55,16 @@ class AVLTree {
// 以 child 为原点,将 node 向左旋转
child.left = node;
node.right = grandChild;
// 更新点高度
// 更新点高度
this.#updateHeight(node);
this.#updateHeight(child);
// 返回旋转后子树的根
// 返回旋转后子树的根
return child;
}
/* 执行旋转操作,使该子树重新恢复平衡 */
#rotate(node) {
// 获取点 node 的平衡因子
// 获取点 node 的平衡因子
const balanceFactor = this.balanceFactor(node);
// 左偏树
if (balanceFactor > 1) {
@ -92,103 +92,103 @@ class AVLTree {
return node;
}
/* 插入点 */
/* 插入点 */
insert(val) {
this.root = this.#insertHelper(this.root, val);
return this.root;
}
/* 递归插入点(辅助方法) */
/* 递归插入点(辅助方法) */
#insertHelper(node, val) {
if (node === null) return new TreeNode(val);
/* 1. 查找插入位置,并插入点 */
/* 1. 查找插入位置,并插入点 */
if (val < node.val) node.left = this.#insertHelper(node.left, val);
else if (val > node.val) node.right = this.#insertHelper(node.right, val);
else return node; // 重复点不插入,直接返回
this.#updateHeight(node); // 更新点高度
else return node; // 重复点不插入,直接返回
this.#updateHeight(node); // 更新点高度
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
node = this.#rotate(node);
// 返回子树的根
// 返回子树的根
return node;
}
/* 删除点 */
/* 删除点 */
remove(val) {
this.root = this.#removeHelper(this.root, val);
return this.root;
}
/* 递归删除点(辅助方法) */
/* 递归删除点(辅助方法) */
#removeHelper(node, val) {
if (node === null) return null;
/* 1. 查找点,并删除之 */
/* 1. 查找点,并删除之 */
if (val < node.val) node.left = this.#removeHelper(node.left, val);
else if (val > node.val) node.right = this.#removeHelper(node.right, val);
else {
if (node.left === null || node.right === null) {
const child = node.left !== null ? node.left : node.right;
// 子点数量 = 0 ,直接删除 node 并返回
// 子点数量 = 0 ,直接删除 node 并返回
if (child === null) return null;
// 子点数量 = 1 ,直接删除 node
// 子点数量 = 1 ,直接删除 node
else node = child;
} else {
// 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结
// 子节点数量 = 2 ,则将中序遍历的下个节点删除,并用该节点替换当前节
const temp = this.#getInOrderNext(node.right);
node.right = this.#removeHelper(node.right, temp.val);
node.val = temp.val;
}
}
this.#updateHeight(node); // 更新点高度
this.#updateHeight(node); // 更新点高度
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
node = this.#rotate(node);
// 返回子树的根
// 返回子树的根
return node;
}
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
/* 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) */
#getInOrderNext(node) {
if (node === null) return node;
// 循环访问左子结点,直到叶结点时为最小结点,跳出
// 循环访问左子节点,直到叶节点时为最小节点,跳出
while (node.left !== null) {
node = node.left;
}
return node;
}
/* 查找点 */
/* 查找点 */
search(val) {
let cur = this.root;
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
while (cur !== null) {
// 目标点在 cur 的右子树中
// 目标点在 cur 的右子树中
if (cur.val < val) cur = cur.right;
// 目标点在 cur 的左子树中
// 目标点在 cur 的左子树中
else if (cur.val > val) cur = cur.left;
// 找到目标点,跳出循环
// 找到目标点,跳出循环
else break;
}
// 返回目标
// 返回目标
return cur;
}
}
function testInsert(tree, val) {
tree.insert(val);
console.log("\n插入点 " + val + " 后AVL 树为");
console.log("\n插入点 " + val + " 后AVL 树为");
printTree(tree.root);
}
function testRemove(tree, val) {
tree.remove(val);
console.log("\n删除点 " + val + " 后AVL 树为");
console.log("\n删除点 " + val + " 后AVL 树为");
printTree(tree.root);
}
/* Driver Code */
/* 初始化空 AVL 树 */
const avlTree = new AVLTree();
/* 插入点 */
// 请关注插入点后AVL 树是如何保持平衡的
/* 插入点 */
// 请关注插入点后AVL 树是如何保持平衡的
testInsert(avlTree, 1);
testInsert(avlTree, 2);
testInsert(avlTree, 3);
@ -200,15 +200,15 @@ testInsert(avlTree, 9);
testInsert(avlTree, 10);
testInsert(avlTree, 6);
/* 插入重复点 */
/* 插入重复点 */
testInsert(avlTree, 7);
/* 删除点 */
// 请关注删除点后AVL 树是如何保持平衡的
testRemove(avlTree, 8); // 删除度为 0 的
testRemove(avlTree, 5); // 删除度为 1 的
testRemove(avlTree, 4); // 删除度为 2 的
/* 删除点 */
// 请关注删除点后AVL 树是如何保持平衡的
testRemove(avlTree, 8); // 删除度为 0 的
testRemove(avlTree, 5); // 删除度为 1 的
testRemove(avlTree, 4); // 删除度为 2 的
/* 查询点 */
/* 查询点 */
const node = avlTree.search(7);
console.log("\n查找到的结点对象为", node, ",结点值 = " + node.val);
console.log("\n查找到的节点对象为", node, ",节点值 = " + node.val);

View File

@ -15,7 +15,7 @@ function BinarySearchTree(nums) {
root = buildTree(nums, 0, nums.length - 1); // 构建二叉搜索树
}
/* 获取二叉树根点 */
/* 获取二叉树根点 */
function getRoot() {
return root;
}
@ -23,7 +23,7 @@ function getRoot() {
/* 构建二叉搜索树 */
function buildTree(nums, i, j) {
if (i > j) return null;
// 将数组中间结点作为根结
// 将数组中间节点作为根节
let mid = Math.floor((i + j) / 2);
let root = new TreeNode(nums[mid]);
// 递归建立左子树和右子树
@ -32,30 +32,30 @@ function buildTree(nums, i, j) {
return root;
}
/* 查找点 */
/* 查找点 */
function search(num) {
let cur = root;
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
while (cur !== null) {
// 目标点在 cur 的右子树中
// 目标点在 cur 的右子树中
if (cur.val < num) cur = cur.right;
// 目标点在 cur 的左子树中
// 目标点在 cur 的左子树中
else if (cur.val > num) cur = cur.left;
// 找到目标点,跳出循环
// 找到目标点,跳出循环
else break;
}
// 返回目标
// 返回目标
return cur;
}
/* 插入点 */
/* 插入点 */
function insert(num) {
// 若树为空,直接提前返回
if (root === null) return null;
let cur = root, pre = null;
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
while (cur !== null) {
// 找到重复点,直接返回
// 找到重复点,直接返回
if (cur.val === num) return null;
pre = cur;
// 插入位置在 cur 的右子树中
@ -63,44 +63,44 @@ function insert(num) {
// 插入位置在 cur 的左子树中
else cur = cur.left;
}
// 插入点 val
// 插入点 val
let node = new TreeNode(num);
if (pre.val < num) pre.right = node;
else pre.left = node;
return node;
}
/* 删除点 */
/* 删除点 */
function remove(num) {
// 若树为空,直接提前返回
if (root === null) return null;
let cur = root, pre = null;
// 循环查找,越过叶点后跳出
// 循环查找,越过叶点后跳出
while (cur !== null) {
// 找到待删除点,跳出循环
// 找到待删除点,跳出循环
if (cur.val === num) break;
pre = cur;
// 待删除点在 cur 的右子树中
// 待删除点在 cur 的右子树中
if (cur.val < num) cur = cur.right;
// 待删除点在 cur 的左子树中
// 待删除点在 cur 的左子树中
else cur = cur.left;
}
// 若无待删除点,则直接返回
// 若无待删除点,则直接返回
if (cur === null) return null;
// 子点数量 = 0 or 1
// 子点数量 = 0 or 1
if (cur.left === null || cur.right === null) {
// 当子结点数量 = 0 / 1 时, child = null / 该子结
// 当子节点数量 = 0 / 1 时, child = null / 该子节
let child = cur.left !== null ? cur.left : cur.right;
// 删除点 cur
// 删除点 cur
if (pre.left === cur) pre.left = child;
else pre.right = child;
}
// 子点数量 = 2
// 子点数量 = 2
else {
// 获取中序遍历中 cur 的下一个
// 获取中序遍历中 cur 的下一个
let nex = getInOrderNext(cur.right);
let tmp = nex.val;
// 递归删除点 nex
// 递归删除点 nex
remove(nex.val);
// 将 nex 的值复制给 cur
cur.val = tmp;
@ -108,10 +108,10 @@ function remove(num) {
return cur;
}
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
/* 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) */
function getInOrderNext(root) {
if (root === null) return root;
// 循环访问左子结点,直到叶结点时为最小结点,跳出
// 循环访问左子节点,直到叶节点时为最小节点,跳出
while (root.left !== null) {
root = root.left;
}
@ -125,22 +125,22 @@ BinarySearchTree(nums);
console.log("\n初始化的二叉树为\n");
printTree(getRoot());
/* 查找点 */
/* 查找点 */
let node = search(7);
console.log("\n查找到的结点对象为 " + node + ",结点值 = " + node.val);
console.log("\n查找到的节点对象为 " + node + ",节点值 = " + node.val);
/* 插入点 */
/* 插入点 */
node = insert(16);
console.log("\n插入点 16 后,二叉树为\n");
console.log("\n插入点 16 后,二叉树为\n");
printTree(getRoot());
/* 删除点 */
/* 删除点 */
remove(1);
console.log("\n删除点 1 后,二叉树为\n");
console.log("\n删除点 1 后,二叉树为\n");
printTree(getRoot());
remove(2);
console.log("\n删除点 2 后,二叉树为\n");
console.log("\n删除点 2 后,二叉树为\n");
printTree(getRoot());
remove(4);
console.log("\n删除点 4 后,二叉树为\n");
console.log("\n删除点 4 后,二叉树为\n");
printTree(getRoot());

View File

@ -8,7 +8,7 @@ const { TreeNode } = require("../modules/TreeNode");
const { printTree } = require("../modules/PrintUtil");
/* 初始化二叉树 */
// 初始化
// 初始化
let n1 = new TreeNode(1),
n2 = new TreeNode(2),
n3 = new TreeNode(3),
@ -22,14 +22,14 @@ n2.right = n5;
console.log("\n初始化二叉树\n");
printTree(n1);
/* 插入与删除点 */
/* 插入与删除点 */
const P = new TreeNode(0);
// 在 n1 -> n2 中间插入点 P
// 在 n1 -> n2 中间插入点 P
n1.left = P;
P.left = n2;
console.log("\n插入点 P 后\n");
console.log("\n插入点 P 后\n");
printTree(n1);
// 删除点 P
// 删除点 P
n1.left = n2;
console.log("\n删除点 P 后\n");
console.log("\n删除点 P 后\n");
printTree(n1);

View File

@ -9,17 +9,17 @@ const { printTree } = require("../modules/PrintUtil");
/* 层序遍历 */
function levelOrder(root) {
// 初始化队列,加入根
// 初始化队列,加入根
const queue = [root];
// 初始化一个列表,用于保存遍历序列
const list = [];
while (queue.length) {
let node = queue.shift(); // 队列出队
list.push(node.val); // 保存点值
list.push(node.val); // 保存点值
if (node.left)
queue.push(node.left); // 左子点入队
queue.push(node.left); // 左子点入队
if (node.right)
queue.push(node.right); // 右子点入队
queue.push(node.right); // 右子点入队
}
return list;
@ -34,4 +34,4 @@ printTree(root);
/* 层序遍历 */
const list = levelOrder(root);
console.log("\n层序遍历的点打印序列 = " + list);
console.log("\n层序遍历的点打印序列 = " + list);

View File

@ -13,7 +13,7 @@ const list = [];
/* 前序遍历 */
function preOrder(root) {
if (root === null) return;
// 访问优先级:根点 -> 左子树 -> 右子树
// 访问优先级:根点 -> 左子树 -> 右子树
list.push(root.val);
preOrder(root.left);
preOrder(root.right);
@ -22,7 +22,7 @@ function preOrder(root) {
/* 中序遍历 */
function inOrder(root) {
if (root === null) return;
// 访问优先级:左子树 -> 根点 -> 右子树
// 访问优先级:左子树 -> 根点 -> 右子树
inOrder(root.left);
list.push(root.val);
inOrder(root.right);
@ -31,7 +31,7 @@ function inOrder(root) {
/* 后序遍历 */
function postOrder(root) {
if (root === null) return;
// 访问优先级:左子树 -> 右子树 -> 根
// 访问优先级:左子树 -> 右子树 -> 根
postOrder(root.left);
postOrder(root.right);
list.push(root.val);
@ -47,14 +47,14 @@ printTree(root);
/* 前序遍历 */
list.length = 0;
preOrder(root);
console.log("\n前序遍历的点打印序列 = " + list);
console.log("\n前序遍历的点打印序列 = " + list);
/* 中序遍历 */
list.length = 0;
inOrder(root);
console.log("\n中序遍历的点打印序列 = " + list);
console.log("\n中序遍历的点打印序列 = " + list);
/* 后序遍历 */
list.length = 0;
postOrder(root);
console.log("\n后序遍历的点打印序列 = " + list);
console.log("\n后序遍历的点打印序列 = " + list);

View File

@ -8,10 +8,10 @@
* Definition for a binary tree node.
*/
class TreeNode {
val; // 点值
left; // 左子点指针
right; // 右子点指针
height; //点高度
val; // 点值
left; // 左子点指针
right; // 右子点指针
height; //点高度
constructor(val, left, right, height) {
this.val = val === undefined ? 0 : val;
this.left = left === undefined ? null : left;

View File

@ -9,13 +9,13 @@ sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__))))
from modules import *
def insert(n0: ListNode, P: ListNode) -> None:
""" 在链表的结点 n0 之后插入结点 P """
""" 在链表的节点 n0 之后插入节点 P """
n1 = n0.next
P.next = n1
n0.next = P
def remove(n0: ListNode) -> None:
""" 删除链表的结点 n0 之后的首个结"""
""" 删除链表的节点 n0 之后的首个节"""
if not n0.next:
return
# n0 -> P -> n1
@ -24,7 +24,7 @@ def remove(n0: ListNode) -> None:
n0.next = n1
def access(head: ListNode, index: int) -> ListNode | None:
""" 访问链表中索引为 index 的"""
""" 访问链表中索引为 index 的"""
for _ in range(index):
if not head:
return None
@ -32,7 +32,7 @@ def access(head: ListNode, index: int) -> ListNode | None:
return head
def find(head: ListNode, target: int) -> int:
""" 在链表中查找值为 target 的首个"""
""" 在链表中查找值为 target 的首个"""
index = 0
while head:
if head.val == target:
@ -45,7 +45,7 @@ def find(head: ListNode, target: int) -> int:
""" Driver Code """
if __name__ == "__main__":
""" 初始化链表 """
# 初始化各个
# 初始化各个
n0 = ListNode(1)
n1 = ListNode(3)
n2 = ListNode(2)
@ -59,20 +59,20 @@ if __name__ == "__main__":
print("初始化的链表为")
print_linked_list(n0)
""" 插入"""
""" 插入"""
insert(n0, ListNode(0))
print("插入点后的链表为")
print("插入点后的链表为")
print_linked_list(n0)
""" 删除"""
""" 删除"""
remove(n0)
print("删除点后的链表为")
print("删除点后的链表为")
print_linked_list(n0)
""" 访问"""
""" 访问"""
node: ListNode = access(n0, 3)
print("链表中索引 3 处的点的值 = {}".format(node.val))
print("链表中索引 3 处的点的值 = {}".format(node.val))
""" 查找"""
""" 查找"""
index: int = find(n0, 2)
print("链表中值为 2 的点的索引 = {}".format(index))
print("链表中值为 2 的点的索引 = {}".format(index))

View File

@ -14,20 +14,20 @@ class MaxHeap:
""" 构造方法 """
# 将列表元素原封不动添加进堆
self.max_heap = nums
# 堆化除叶结点以外的其他所有结
# 堆化除叶节点以外的其他所有节
for i in range(self.parent(self.size() - 1), -1, -1):
self.sift_down(i)
def left(self, i: int) -> int:
""" 获取左子点索引 """
""" 获取左子点索引 """
return 2 * i + 1
def right(self, i: int) -> int:
""" 获取右子点索引 """
""" 获取右子点索引 """
return 2 * i + 2
def parent(self, i: int) -> int:
""" 获取父点索引 """
""" 获取父点索引 """
return (i - 1) // 2 # 向下整除
def swap(self, i: int, j: int):
@ -49,20 +49,20 @@ class MaxHeap:
def push(self, val: int):
""" 元素入堆 """
# 添加
# 添加
self.max_heap.append(val)
# 从底至顶堆化
self.sift_up(self.size() - 1)
def sift_up(self, i: int):
"""点 i 开始,从底至顶堆化 """
"""点 i 开始,从底至顶堆化 """
while True:
# 获取结点 i 的父结
# 获取节点 i 的父节
p = self.parent(i)
# 当“越过根结点”或“结点无需修复”时,结束堆化
# 当“越过根节点”或“节点无需修复”时,结束堆化
if p < 0 or self.max_heap[i] <= self.max_heap[p]:
break
# 交换两
# 交换两
self.swap(i, p)
# 循环向上堆化
i = p
@ -71,9 +71,9 @@ class MaxHeap:
""" 元素出堆 """
# 判空处理
assert not self.is_empty()
# 交换根结点与最右叶结点(即交换首元素与尾元素)
# 交换根节点与最右叶节点(即交换首元素与尾元素)
self.swap(0, self.size() - 1)
# 删除
# 删除
val = self.max_heap.pop()
# 从顶至底堆化
self.sift_down(0)
@ -81,18 +81,18 @@ class MaxHeap:
return val
def sift_down(self, i: int):
"""点 i 开始,从顶至底堆化 """
"""点 i 开始,从顶至底堆化 """
while True:
# 判断结点 i, l, r 中值最大的结点,记为 ma
# 判断节点 i, l, r 中值最大的节点,记为 ma
l, r, ma = self.left(i), self.right(i), i
if l < self.size() and self.max_heap[l] > self.max_heap[ma]:
ma = l
if r < self.size() and self.max_heap[r] > self.max_heap[ma]:
ma = r
# 若点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
# 若点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if ma == i:
break
# 交换两
# 交换两
self.swap(i, ma)
# 循环向下堆化
i = ma

View File

@ -16,7 +16,7 @@ def hashing_search_array(mapp: dict[int, int], target: int) -> int:
def hashing_search_linkedlist(mapp: dict[int, ListNode], target: int) -> ListNode | None:
""" 哈希查找(链表) """
# 哈希表的 key: 目标元素value: 点对象
# 哈希表的 key: 目标元素value: 点对象
# 若哈希表中无此 key ,返回 None
return mapp.get(target, None)
@ -39,7 +39,7 @@ if __name__ == '__main__':
# 初始化哈希表
map1 = dict[int, ListNode]()
while head:
map1[head.val] = head # key: 结点值value: 结
map1[head.val] = head # key: 节点值value: 节
head = head.next
node: ListNode = hashing_search_linkedlist(map1, target)
print("目标结点值 3 的对应结点对象为", node)
print("目标节点值 3 的对应节点对象为", node)

View File

@ -20,10 +20,10 @@ def linear_search_linkedlist(head: ListNode, target: int) -> ListNode | None:
""" 线性查找(链表) """
# 遍历链表
while head:
if head.val == target: # 找到目标点,返回之
if head.val == target: # 找到目标点,返回之
return head
head = head.next
return None # 未找到目标点,返回 None
return None # 未找到目标点,返回 None
""" Driver Code """
@ -38,4 +38,4 @@ if __name__ == '__main__':
# 在链表中执行线性查找
head: ListNode = list_to_linked_list(nums)
node: ListNode | None = linear_search_linkedlist(head, target)
print("目标结点值 3 的对应结点对象为", node)
print("目标节点值 3 的对应节点对象为", node)

View File

@ -5,19 +5,19 @@ Author: Krahets (krahets@163.com)
"""
class ListNode:
""" 双向链表"""
""" 双向链表"""
def __init__(self, val: int) -> None:
""" 构造方法 """
self.val: int = val
self.next: ListNode | None = None # 后继点引用(指针)
self.prev: ListNode | None = None # 前驱点引用(指针)
self.next: ListNode | None = None # 后继点引用(指针)
self.prev: ListNode | None = None # 前驱点引用(指针)
class LinkedListDeque:
""" 基于双向链表实现的双向队列 """
def __init__(self) -> None:
""" 构造方法 """
self.front: ListNode | None = None # 头点 front
self.rear: ListNode | None = None # 尾点 rear
self.front: ListNode | None = None # 头点 front
self.rear: ListNode | None = None # 尾点 rear
self.__size: int = 0 # 双向队列的长度
def size(self) -> int:
@ -39,13 +39,13 @@ class LinkedListDeque:
# 将 node 添加至链表头部
self.front.prev = node
node.next = self.front
self.front = node # 更新头
self.front = node # 更新头
# 队尾入队操作
else:
# 将 node 添加至链表尾部
self.rear.next = node
node.prev = self.rear
self.rear = node # 更新尾
self.rear = node # 更新尾
self.__size += 1 # 更新队列长度
def push_first(self, num: int) -> None:
@ -63,22 +63,22 @@ class LinkedListDeque:
return None
# 队首出队操作
if is_front:
val: int = self.front.val # 暂存头点值
# 删除头
val: int = self.front.val # 暂存头点值
# 删除头
fnext: ListNode | None = self.front.next
if fnext != None:
fnext.prev = None
self.front.next = None
self.front = fnext # 更新头
self.front = fnext # 更新头
# 队尾出队操作
else:
val: int = self.rear.val # 暂存尾点值
# 删除尾
val: int = self.rear.val # 暂存尾点值
# 删除尾
rprev: ListNode | None = self.rear.prev
if rprev != None:
rprev.next = None
self.rear.prev = None
self.rear = rprev # 更新尾
self.rear = rprev # 更新尾
self.__size -= 1 # 更新队列长度
return val

View File

@ -12,8 +12,8 @@ class LinkedListQueue:
""" 基于链表实现的队列 """
def __init__(self):
""" 构造方法 """
self.__front: ListNode | None = None # 头点 front
self.__rear: ListNode | None = None # 尾点 rear
self.__front: ListNode | None = None # 头点 front
self.__rear: ListNode | None = None # 尾点 rear
self.__size: int = 0
def size(self) -> int:
@ -26,13 +26,13 @@ class LinkedListQueue:
def push(self, num: int) -> None:
""" 入队 """
# 尾点后添加 num
# 尾点后添加 num
node = ListNode(num)
# 如果队列为空,则令头、尾结点都指向该结
# 如果队列为空,则令头、尾节点都指向该节
if self.__front is None:
self.__front = node
self.__rear = node
# 如果队列不为空,则将该结点添加到尾结点后
# 如果队列不为空,则将该节点添加到尾节点后
else:
self.__rear.next = node
self.__rear = node
@ -41,7 +41,7 @@ class LinkedListQueue:
def pop(self) -> int:
""" 出队 """
num = self.peek()
# 删除头
# 删除头
self.__front = self.__front.next
self.__size -= 1
return num

View File

@ -19,23 +19,23 @@ class AVLTree:
return self.__root
def height(self, node: TreeNode | None) -> int:
""" 获取点高度 """
# 空结点高度为 -1 ,叶结点高度为 0
""" 获取点高度 """
# 空节点高度为 -1 ,叶节点高度为 0
if node is not None:
return node.height
return -1
def __update_height(self, node: TreeNode | None):
""" 更新点高度 """
# 点高度等于最高子树高度 + 1
""" 更新点高度 """
# 点高度等于最高子树高度 + 1
node.height = max([self.height(node.left), self.height(node.right)]) + 1
def balance_factor(self, node: TreeNode | None) -> int:
""" 获取平衡因子 """
# 空点平衡因子为 0
# 空点平衡因子为 0
if node is None:
return 0
# 点平衡因子 = 左子树高度 - 右子树高度
# 点平衡因子 = 左子树高度 - 右子树高度
return self.height(node.left) - self.height(node.right)
def __right_rotate(self, node: TreeNode | None) -> TreeNode | None:
@ -45,10 +45,10 @@ class AVLTree:
# 以 child 为原点,将 node 向右旋转
child.right = node
node.left = grand_child
# 更新点高度
# 更新点高度
self.__update_height(node)
self.__update_height(child)
# 返回旋转后子树的根
# 返回旋转后子树的根
return child
def __left_rotate(self, node: TreeNode | None) -> TreeNode | None:
@ -58,15 +58,15 @@ class AVLTree:
# 以 child 为原点,将 node 向左旋转
child.left = node
node.right = grand_child
# 更新点高度
# 更新点高度
self.__update_height(node)
self.__update_height(child)
# 返回旋转后子树的根
# 返回旋转后子树的根
return child
def __rotate(self, node: TreeNode | None) -> TreeNode | None:
""" 执行旋转操作,使该子树重新恢复平衡 """
# 获取点 node 的平衡因子
# 获取点 node 的平衡因子
balance_factor = self.balance_factor(node)
# 左偏树
if balance_factor > 1:
@ -90,37 +90,37 @@ class AVLTree:
return node
def insert(self, val) -> TreeNode:
""" 插入"""
""" 插入"""
self.__root = self.__insert_helper(self.__root, val)
return self.__root
def __insert_helper(self, node: TreeNode | None, val: int) -> TreeNode:
""" 递归插入点(辅助方法)"""
""" 递归插入点(辅助方法)"""
if node is None:
return TreeNode(val)
# 1. 查找插入位置,并插入
# 1. 查找插入位置,并插入
if val < node.val:
node.left = self.__insert_helper(node.left, val)
elif val > node.val:
node.right = self.__insert_helper(node.right, val)
else:
# 重复点不插入,直接返回
# 重复点不插入,直接返回
return node
# 更新点高度
# 更新点高度
self.__update_height(node)
# 2. 执行旋转操作,使该子树重新恢复平衡
return self.__rotate(node)
def remove(self, val: int) -> TreeNode | None:
""" 删除"""
""" 删除"""
self.__root = self.__remove_helper(self.__root, val)
return self.__root
def __remove_helper(self, node: TreeNode | None, val: int) -> TreeNode | None:
""" 递归删除点(辅助方法) """
""" 递归删除点(辅助方法) """
if node is None:
return None
# 1. 查找点,并删除之
# 1. 查找点,并删除之
if val < node.val:
node.left = self.__remove_helper(node.left, val)
elif val > node.val:
@ -128,45 +128,45 @@ class AVLTree:
else:
if node.left is None or node.right is None:
child = node.left or node.right
# 子点数量 = 0 ,直接删除 node 并返回
# 子点数量 = 0 ,直接删除 node 并返回
if child is None:
return None
# 子点数量 = 1 ,直接删除 node
# 子点数量 = 1 ,直接删除 node
else:
node = child
else: # 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结
else: # 子节点数量 = 2 ,则将中序遍历的下个节点删除,并用该节点替换当前节
temp = self.__get_inorder_next(node.right)
node.right = self.__remove_helper(node.right, temp.val)
node.val = temp.val
# 更新点高度
# 更新点高度
self.__update_height(node)
# 2. 执行旋转操作,使该子树重新恢复平衡
return self.__rotate(node)
def __get_inorder_next(self, node: TreeNode | None) -> TreeNode | None:
""" 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) """
""" 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) """
if node is None:
return None
# 循环访问左子结点,直到叶结点时为最小结点,跳出
# 循环访问左子节点,直到叶节点时为最小节点,跳出
while node.left is not None:
node = node.left
return node
def search(self, val: int) -> TreeNode | None:
""" 查找"""
""" 查找"""
cur = self.__root
# 循环查找,越过叶点后跳出
# 循环查找,越过叶点后跳出
while cur is not None:
# 目标点在 cur 的右子树中
# 目标点在 cur 的右子树中
if cur.val < val:
cur = cur.right
# 目标点在 cur 的左子树中
# 目标点在 cur 的左子树中
elif cur.val > val:
cur = cur.left
# 找到目标点,跳出循环
# 找到目标点,跳出循环
else:
break
# 返回目标
# 返回目标
return cur
@ -174,19 +174,19 @@ class AVLTree:
if __name__ == "__main__":
def test_insert(tree: AVLTree, val: int):
tree.insert(val)
print("\n插入{}AVL 树为".format(val))
print("\n插入{}AVL 树为".format(val))
print_tree(tree.root)
def test_remove(tree: AVLTree, val: int):
tree.remove(val)
print("\n删除{}AVL 树为".format(val))
print("\n删除{}AVL 树为".format(val))
print_tree(tree.root)
# 初始化空 AVL 树
avl_tree = AVLTree()
# 插入
# 请关注插入点后AVL 树是如何保持平衡的
# 插入
# 请关注插入点后AVL 树是如何保持平衡的
test_insert(avl_tree, 1)
test_insert(avl_tree, 2)
test_insert(avl_tree, 3)
@ -198,14 +198,14 @@ if __name__ == "__main__":
test_insert(avl_tree, 10)
test_insert(avl_tree, 6)
# 插入重复
# 插入重复
test_insert(avl_tree, 7)
# 删除
# 请关注删除点后AVL 树是如何保持平衡的
test_remove(avl_tree, 8) # 删除度为 0 的
test_remove(avl_tree, 5) # 删除度为 1 的
test_remove(avl_tree, 4) # 删除度为 2 的
# 删除
# 请关注删除点后AVL 树是如何保持平衡的
test_remove(avl_tree, 8) # 删除度为 0 的
test_remove(avl_tree, 5) # 删除度为 1 的
test_remove(avl_tree, 4) # 删除度为 2 的
result_node = avl_tree.search(7)
print("\n查找到的结点对象为 {},结点值 = {}".format(result_node, result_node.val))
print("\n查找到的节点对象为 {},节点值 = {}".format(result_node, result_node.val))

View File

@ -21,7 +21,7 @@ class BinarySearchTree:
if start_index > end_index:
return None
# 将数组中间结点作为根结
# 将数组中间节点作为根节
mid: int = (start_index + end_index) // 2
root = TreeNode(nums[mid])
# 递归建立左子树和右子树
@ -34,31 +34,31 @@ class BinarySearchTree:
return self.__root
def search(self, num: int) -> TreeNode | None:
""" 查找"""
""" 查找"""
cur: TreeNode | None = self.__root
# 循环查找,越过叶点后跳出
# 循环查找,越过叶点后跳出
while cur is not None:
# 目标点在 cur 的右子树中
# 目标点在 cur 的右子树中
if cur.val < num:
cur = cur.right
# 目标点在 cur 的左子树中
# 目标点在 cur 的左子树中
elif cur.val > num:
cur = cur.left
# 找到目标点,跳出循环
# 找到目标点,跳出循环
else:
break
return cur
def insert(self, num: int) -> TreeNode | None:
""" 插入"""
""" 插入"""
# 若树为空,直接提前返回
if self.__root is None:
return None
# 循环查找,越过叶点后跳出
# 循环查找,越过叶点后跳出
cur, pre = self.__root, None
while cur is not None:
# 找到重复点,直接返回
# 找到重复点,直接返回
if cur.val == num:
return None
pre = cur
@ -69,7 +69,7 @@ class BinarySearchTree:
else:
cur = cur.left
# 插入点 val
# 插入点 val
node = TreeNode(num)
if pre.val < num:
pre.right = node
@ -78,51 +78,51 @@ class BinarySearchTree:
return node
def remove(self, num: int) -> TreeNode | None:
""" 删除"""
""" 删除"""
# 若树为空,直接提前返回
if self.__root is None:
return None
# 循环查找,越过叶点后跳出
# 循环查找,越过叶点后跳出
cur, pre = self.__root, None
while cur is not None:
# 找到待删除点,跳出循环
# 找到待删除点,跳出循环
if cur.val == num:
break
pre = cur
if cur.val < num: # 待删除点在 cur 的右子树中
if cur.val < num: # 待删除点在 cur 的右子树中
cur = cur.right
else: # 待删除点在 cur 的左子树中
else: # 待删除点在 cur 的左子树中
cur = cur.left
# 若无待删除点,则直接返回
# 若无待删除点,则直接返回
if cur is None:
return None
# 子点数量 = 0 or 1
# 子点数量 = 0 or 1
if cur.left is None or cur.right is None:
# 当子结点数量 = 0 / 1 时, child = null / 该子结
# 当子节点数量 = 0 / 1 时, child = null / 该子节
child = cur.left or cur.right
# 删除点 cur
# 删除点 cur
if pre.left == cur:
pre.left = child
else:
pre.right = child
# 子点数量 = 2
# 子点数量 = 2
else:
# 获取中序遍历中 cur 的下一个
# 获取中序遍历中 cur 的下一个
nex: TreeNode = self.get_inorder_next(cur.right)
tmp: int = nex.val
# 递归删除点 nex
# 递归删除点 nex
self.remove(nex.val)
# 将 nex 的值复制给 cur
cur.val = tmp
return cur
def get_inorder_next(self, root: TreeNode | None) -> TreeNode | None:
""" 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) """
""" 获取中序遍历中的下一个节点(仅适用于 root 有左子节点的情况) """
if root is None:
return root
# 循环访问左子结点,直到叶结点时为最小结点,跳出
# 循环访问左子节点,直到叶节点时为最小节点,跳出
while root.left is not None:
root = root.left
return root
@ -136,24 +136,24 @@ if __name__ == "__main__":
print("\n初始化的二叉树为\n")
print_tree(bst.root)
# 查找
# 查找
node = bst.search(7)
print("\n查找到的结点对象为: {},结点值 = {}".format(node, node.val))
print("\n查找到的节点对象为: {},节点值 = {}".format(node, node.val))
# 插入
# 插入
node = bst.insert(16)
print("\n插入点 16 后,二叉树为\n")
print("\n插入点 16 后,二叉树为\n")
print_tree(bst.root)
# 删除
# 删除
bst.remove(1)
print("\n删除点 1 后,二叉树为\n")
print("\n删除点 1 后,二叉树为\n")
print_tree(bst.root)
bst.remove(2)
print("\n删除点 2 后,二叉树为\n")
print("\n删除点 2 后,二叉树为\n")
print_tree(bst.root)
bst.remove(4)
print("\n删除点 4 后,二叉树为\n")
print("\n删除点 4 后,二叉树为\n")
print_tree(bst.root)

Some files were not shown because too many files have changed in this diff Show More