mirror of
https://github.com/krahets/hello-algo.git
synced 2024-12-25 00:16:28 +08:00
Merge branch 'master' into binary_search_tree
This commit is contained in:
commit
daa28be3e4
215 changed files with 5618 additions and 1642 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -4,6 +4,7 @@
|
|||
# Editor
|
||||
.vscode/
|
||||
.idea/
|
||||
hello-algo.iml
|
||||
|
||||
# mkdocs files
|
||||
site/
|
||||
|
@ -13,6 +14,3 @@ docs/overrides/
|
|||
|
||||
# python files
|
||||
__pycache__
|
||||
|
||||
# iml
|
||||
hello-algo.iml
|
||||
|
|
4
.prettierrc
Normal file
4
.prettierrc
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"tabWidth": 4,
|
||||
"useTabs": false
|
||||
}
|
112
codes/c/chapter_array_and_linkedlist/array.c
Normal file
112
codes/c/chapter_array_and_linkedlist/array.c
Normal file
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
* File: array.c
|
||||
* Created Time: 2022-12-20
|
||||
* Author: MolDuM (moldum@163.com)
|
||||
*/
|
||||
|
||||
#include "../include/include.h"
|
||||
|
||||
/* 随机返回一个数组元素 */
|
||||
int randomAccess(int* nums, int size) {
|
||||
// 在区间 [0, size) 中随机抽取一个数字
|
||||
int randomIndex = rand() % size;
|
||||
// 获取并返回随机元素
|
||||
int randomNum = nums[randomIndex];
|
||||
return randomNum;
|
||||
}
|
||||
|
||||
/* 扩展数组长度 */
|
||||
int* extend(int* nums, int size, int enlarge) {
|
||||
// 初始化一个扩展长度后的数组
|
||||
int* res = (int *)malloc(sizeof(int) * (size + enlarge));
|
||||
// 将原数组中的所有元素复制到新数组
|
||||
for (int i = 0; i < size; i++) {
|
||||
res[i] = nums[i];
|
||||
}
|
||||
// 初始化扩展后的空间
|
||||
for (int i = size; i < size + enlarge; i++) {
|
||||
res[i] = 0;
|
||||
}
|
||||
// 返回扩展后的新数组
|
||||
return res;
|
||||
}
|
||||
|
||||
/* 在数组的索引 index 处插入元素 num */
|
||||
void insert(int* nums, int size, int num, int index) {
|
||||
// 把索引 index 以及之后的所有元素向后移动一位
|
||||
for (int i = size - 1; i > index; i--) {
|
||||
nums[i] = nums[i - 1];
|
||||
}
|
||||
// 将 num 赋给 index 处元素
|
||||
nums[index] = num;
|
||||
}
|
||||
|
||||
/* 删除索引 index 处元素 */
|
||||
void removeItem(int* nums, int size, int index) {
|
||||
// 把索引 index 之后的所有元素向前移动一位
|
||||
for (int i = index; i < size - 1; i++) {
|
||||
nums[i] = nums[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
/* 遍历数组 */
|
||||
void traverse(int* nums, int size) {
|
||||
int count = 0;
|
||||
// 通过索引遍历数组
|
||||
for (int i = 0; i < size; i++) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* 在数组中查找指定元素 */
|
||||
int find(int* nums, int size, int target) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (nums[i] == target)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Driver Code */
|
||||
int main() {
|
||||
/* 初始化数组 */
|
||||
int size = 5;
|
||||
int arr[5];
|
||||
printf("数组 arr = ");
|
||||
printArray(arr, size);
|
||||
|
||||
int nums[5] = { 1, 3, 2, 5, 4 };
|
||||
printf("数组 nums = ");
|
||||
printArray(nums, size);
|
||||
|
||||
/* 随机访问 */
|
||||
int randomNum = randomAccess(nums, size);
|
||||
printf("在 nums 中获取随机元素 %d", randomNum);
|
||||
|
||||
/* 长度扩展 */
|
||||
int enlarge = 3;
|
||||
int* res = extend(nums, size, enlarge);
|
||||
size += enlarge;
|
||||
printf("将数组长度扩展至 8 ,得到 nums = ");
|
||||
printArray(res, size);
|
||||
|
||||
/* 插入元素 */
|
||||
insert(res, size, 6, 3);
|
||||
printf("在索引 3 处插入数字 6 ,得到 nums = ");
|
||||
printArray(res, size);
|
||||
|
||||
/* 删除元素 */
|
||||
removeItem(res, size, 2);
|
||||
printf("删除索引 2 处的元素,得到 nums = ");
|
||||
printArray(res, size);
|
||||
|
||||
/* 遍历数组 */
|
||||
traverse(res, size);
|
||||
|
||||
/* 查找元素 */
|
||||
int index = find(res, size, 3);
|
||||
printf("在 res 中查找元素 3 ,得到索引 = %d\n", index);
|
||||
|
||||
return 0;
|
||||
}
|
174
codes/c/chapter_computational_complexity/time_complexity.c
Normal file
174
codes/c/chapter_computational_complexity/time_complexity.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
/**
|
||||
* File: time_complexity.c
|
||||
* Created Time: 2023-01-03
|
||||
* Author: sjinzh (sjinzh@gmail.com)
|
||||
*/
|
||||
|
||||
#include "../include/include.h"
|
||||
|
||||
/* 常数阶 */
|
||||
int constant(int n) {
|
||||
int count = 0;
|
||||
int size = 100000;
|
||||
int i = 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
count ++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* 线性阶 */
|
||||
int linear(int n) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
count ++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* 线性阶(遍历数组) */
|
||||
int arrayTraversal(int *nums, int n) {
|
||||
int count = 0;
|
||||
// 循环次数与数组长度成正比
|
||||
for (int i = 0; i < n; i++) {
|
||||
count ++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* 平方阶 */
|
||||
int quadratic(int n)
|
||||
{
|
||||
int count = 0;
|
||||
// 循环次数与数组长度成平方关系
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
count ++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* 平方阶(冒泡排序) */
|
||||
int bubbleSort(int *nums, int n) {
|
||||
int count = 0; // 计数器
|
||||
// 外循环:待排序元素数量为 n-1, n-2, ..., 1
|
||||
for (int i = n - 1; i > 0; i--) {
|
||||
// 内循环:冒泡操作
|
||||
for (int j = 0; j < i; j++) {
|
||||
// 交换 nums[j] 与 nums[j + 1]
|
||||
int tmp = nums[j];
|
||||
nums[j] = nums[j + 1];
|
||||
nums[j + 1] = tmp;
|
||||
count += 3; // 元素交换包含 3 个单元操作
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* 指数阶(循环实现) */
|
||||
int exponential(int n) {
|
||||
int count = 0;
|
||||
int bas = 1;
|
||||
// cell 每轮一分为二,形成数列 1, 2, 4, 8, ..., 2^(n-1)
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < bas; j++) {
|
||||
count++;
|
||||
}
|
||||
bas *= 2;
|
||||
}
|
||||
// count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1
|
||||
return count;
|
||||
}
|
||||
|
||||
/* 指数阶(递归实现) */
|
||||
int expRecur(int n) {
|
||||
if (n == 1) return 1;
|
||||
return expRecur(n - 1) + expRecur(n - 1) + 1;
|
||||
}
|
||||
|
||||
/* 对数阶(循环实现) */
|
||||
int logarithmic(float n) {
|
||||
int count = 0;
|
||||
while (n > 1) {
|
||||
n = n / 2;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* 对数阶(递归实现) */
|
||||
int logRecur(float n) {
|
||||
if (n <= 1) return 0;
|
||||
return logRecur(n / 2) + 1;
|
||||
}
|
||||
|
||||
/* 线性对数阶 */
|
||||
int linearLogRecur(float n) {
|
||||
if (n <= 1) return 1;
|
||||
int count = linearLogRecur(n / 2) +
|
||||
linearLogRecur(n / 2);
|
||||
for (int i = 0; i < n; i++) {
|
||||
count ++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* 阶乘阶(递归实现) */
|
||||
int factorialRecur(int n) {
|
||||
if (n == 0) return 1;
|
||||
int count = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
count += factorialRecur(n - 1);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
int main(int argc, char *argv[]) {
|
||||
// 可以修改 n 运行,体会一下各种复杂度的操作数量变化趋势
|
||||
int n = 8;
|
||||
printf("输入数据大小 n = %d\n", n);
|
||||
|
||||
int count = constant(n);
|
||||
printf("常数阶的计算操作数量 = %d\n", count);
|
||||
|
||||
count = linear(n);
|
||||
printf("线性阶的计算操作数量 = %d\n", count);
|
||||
// 分配堆区内存(创建一维可变长数组:数组中元素数量为n,元素类型为int)
|
||||
int *nums = (int *)malloc(n * sizeof(int));
|
||||
count = arrayTraversal(nums, n);
|
||||
printf("线性阶(遍历数组)的计算操作数量 = %d\n", count);
|
||||
|
||||
count = quadratic(n);
|
||||
printf("平方阶的计算操作数量 = %d\n", count);
|
||||
for (int i = 0; i < n; i++) {
|
||||
nums[i] = n - i; // [n,n-1,...,2,1]
|
||||
}
|
||||
count = bubbleSort(nums, n);
|
||||
printf("平方阶(冒泡排序)的计算操作数量 = %d\n", count);
|
||||
|
||||
count = exponential(n);
|
||||
printf("指数阶(循环实现)的计算操作数量 = %d\n", count);
|
||||
count = expRecur(n);
|
||||
printf("指数阶(递归实现)的计算操作数量 = %d\n", count);
|
||||
|
||||
count = logarithmic(n);
|
||||
printf("对数阶(循环实现)的计算操作数量 = %d\n", count);
|
||||
count = logRecur(n);
|
||||
printf("对数阶(递归实现)的计算操作数量 = %d\n", count);
|
||||
|
||||
count = linearLogRecur(n);
|
||||
printf("线性对数阶(递归实现)的计算操作数量 = %d\n", count);
|
||||
|
||||
count = factorialRecur(n);
|
||||
printf("阶乘阶(递归实现)的计算操作数量 = %d\n", count);
|
||||
|
||||
// 释放堆区内存
|
||||
if (nums != NULL) {
|
||||
free(nums);
|
||||
nums = NULL;
|
||||
}
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* File: worst_best_time_complexity.c
|
||||
* Created Time: 2023-01-03
|
||||
* Author: sjinzh (sjinzh@gmail.com)
|
||||
*/
|
||||
|
||||
#include "../include/include.h"
|
||||
|
||||
/* 生成一个数组,元素为 { 1, 2, ..., n },顺序被打乱 */
|
||||
int *randomNumbers(int n) {
|
||||
// 分配堆区内存(创建一维可变长数组:数组中元素数量为n,元素类型为int)
|
||||
int *nums = (int *)malloc(n * sizeof(int));
|
||||
// 生成数组 nums = { 1, 2, 3, ..., n }
|
||||
for (int i = 0; i < n; i++) {
|
||||
nums[i] = i + 1;
|
||||
}
|
||||
// 随机打乱数组元素
|
||||
for (int i = n - 1; i > 0; i--) {
|
||||
int j = rand() % (i + 1);
|
||||
int temp = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = temp;
|
||||
}
|
||||
return nums;
|
||||
}
|
||||
|
||||
/* 查找数组 nums 中数字 1 所在索引 */
|
||||
int findOne(int *nums, int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (nums[i] == 1) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
int main(int argc, char *argv[]) {
|
||||
// 初始化随机数种子
|
||||
srand((unsigned int)time(NULL));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int n = 100;
|
||||
int *nums = randomNumbers(n);
|
||||
int index = findOne(nums, n);
|
||||
printf("\n数组 [ 1, 2, ..., n ] 被打乱后 = ");
|
||||
printArray(nums, n);
|
||||
printf("数字 1 的索引为 %d\n", index);
|
||||
// 释放堆区内存
|
||||
if (nums != NULL) {
|
||||
free(nums);
|
||||
nums = NULL;
|
||||
}
|
||||
}
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
|
@ -7,8 +7,7 @@
|
|||
#include "../include/include.h"
|
||||
|
||||
/* 冒泡排序 */
|
||||
void bubble_sort(int nums[], int size)
|
||||
{
|
||||
void bubble_sort(int nums[], int size) {
|
||||
// 外循环:待排序元素数量为 n-1, n-2, ..., 1
|
||||
for (int i = 0; i < size - 1; i++)
|
||||
{
|
||||
|
@ -26,8 +25,7 @@ void bubble_sort(int nums[], int size)
|
|||
}
|
||||
|
||||
/* 冒泡排序(标志优化)*/
|
||||
void bubble_sort_with_flag(int nums[], int size)
|
||||
{
|
||||
void bubble_sort_with_flag(int nums[], int size) {
|
||||
// 外循环:待排序元素数量为 n-1, n-2, ..., 1
|
||||
for (int i = 0; i < size - 1; i++)
|
||||
{
|
||||
|
@ -50,8 +48,7 @@ void bubble_sort_with_flag(int nums[], int size)
|
|||
|
||||
|
||||
/* Driver Code */
|
||||
int main()
|
||||
{
|
||||
int main() {
|
||||
int nums[6] = {4, 1, 3, 1, 5, 2};
|
||||
printf("冒泡排序后:\n");
|
||||
bubble_sort(nums, 6);
|
||||
|
@ -69,4 +66,4 @@ int main()
|
|||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
39
codes/c/chapter_sorting/insertion_sort.c
Normal file
39
codes/c/chapter_sorting/insertion_sort.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* File: insertion_sort.c
|
||||
* Created Time: 2022-12-29
|
||||
* Author: Listening (https://github.com/L-Super)
|
||||
*/
|
||||
|
||||
#include "../include/include.h"
|
||||
|
||||
/* 插入排序 */
|
||||
void insertionSort(int nums[], int size) {
|
||||
// 外循环:base = nums[1], nums[2], ..., nums[n-1]
|
||||
for (int i = 1; i < size; i++)
|
||||
{
|
||||
int base = nums[i], j = i - 1;
|
||||
// 内循环:将 base 插入到左边的正确位置
|
||||
while (j >= 0 && nums[j] > base)
|
||||
{
|
||||
// 1. 将 nums[j] 向右移动一位
|
||||
nums[j + 1] = nums[j];
|
||||
j--;
|
||||
}
|
||||
// 2. 将 base 赋值到正确位置
|
||||
nums[j + 1] = base;
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
int main() {
|
||||
int nums[] = {4, 1, 3, 1, 5, 2};
|
||||
insertionSort(nums, 6);
|
||||
printf("插入排序完成后 nums = \n");
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
printf("%d ", nums[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
28
codes/c/include/PrintUtil.h
Normal file
28
codes/c/include/PrintUtil.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* File: PrintUtil.h
|
||||
* Created Time: 2022-12-21
|
||||
* Author: MolDum (moldum@163.com)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// #include "ListNode.h"
|
||||
// #include "TreeNode.h"
|
||||
|
||||
/**
|
||||
* @brief Print an Array
|
||||
*
|
||||
* @param arr
|
||||
* @param n
|
||||
*/
|
||||
|
||||
static void printArray(int* arr, int n)
|
||||
{
|
||||
printf("[");
|
||||
for (int i = 0; i < n - 1; i++) {
|
||||
printf("%d, ", arr[i]);
|
||||
}
|
||||
printf("%d]\n", arr[n-1]);
|
||||
}
|
|
@ -1,2 +1,13 @@
|
|||
/**
|
||||
* File: include.h
|
||||
* Created Time: 2022-12-20
|
||||
* Author: MolDuM (moldum@163.com)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "PrintUtil.h"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: array.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: linked_list.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
@ -21,14 +21,16 @@ void remove(ListNode* n0) {
|
|||
ListNode* P = n0->next;
|
||||
ListNode* n1 = P->next;
|
||||
n0->next = n1;
|
||||
// 释放内存
|
||||
delete P;
|
||||
}
|
||||
|
||||
/* 访问链表中索引为 index 的结点 */
|
||||
ListNode* access(ListNode* head, int index) {
|
||||
for (int i = 0; i < index; i++) {
|
||||
head = head->next;
|
||||
if (head == nullptr)
|
||||
return nullptr;
|
||||
head = head->next;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: list.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: my_list.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: leetcode_two_sum.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: space_complexity.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: time_complexity.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: worst_best_time_complexity.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: array_hash_map.cpp
|
||||
* Created Time: 2022-12-14
|
||||
* Author: msk397 (machangxinq@gmail.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: hash_map.cpp
|
||||
* Created Time: 2022-12-14
|
||||
* Author: msk397 (machangxinq@gmail.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: binary_search.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: hashing_search.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: linear_search.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: bubble_sort.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: insertion_sort.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: merge_sort.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
@ -25,10 +25,10 @@ void merge(vector<int>& nums, int left, int mid, int right) {
|
|||
// 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++
|
||||
if (i > leftEnd)
|
||||
nums[k] = tmp[j++];
|
||||
// 否则,若“右子数组已全部合并完”或“左子数组元素 < 右子数组元素”,则选取左子数组元素,并且 i++
|
||||
// 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++
|
||||
else if (j > rightEnd || tmp[i] <= tmp[j])
|
||||
nums[k] = tmp[i++];
|
||||
// 否则,若“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
|
||||
// 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
|
||||
else
|
||||
nums[k] = tmp[j++];
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: quick_sort.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: array_queue.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
@ -50,11 +50,10 @@ public:
|
|||
}
|
||||
|
||||
/* 出队 */
|
||||
int poll() {
|
||||
void poll() {
|
||||
int num = peek();
|
||||
// 队头指针向后移动一位,若越过尾部则返回到数组头部
|
||||
front = (front + 1) % capacity();
|
||||
return num;
|
||||
}
|
||||
|
||||
/* 访问队首元素 */
|
||||
|
@ -98,8 +97,8 @@ int main() {
|
|||
cout << "队首元素 peek = " << peek << endl;
|
||||
|
||||
/* 元素出队 */
|
||||
int poll = queue->poll();
|
||||
cout << "出队元素 poll = " << poll << ",出队后 queue = ";
|
||||
queue->poll();
|
||||
cout << "出队元素 poll = " << peek << ",出队后 queue = ";
|
||||
PrintUtil::printVector(queue->toVector());
|
||||
|
||||
/* 获取队列的长度 */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: array_stack.cpp
|
||||
* Created Time: 2022-11-28
|
||||
* Author: qualifier1024 (2539244001@qq.com)
|
||||
|
@ -28,10 +28,9 @@ public:
|
|||
}
|
||||
|
||||
/* 出栈 */
|
||||
int pop() {
|
||||
void pop() {
|
||||
int oldTop = top();
|
||||
stack.pop_back();
|
||||
return oldTop;
|
||||
}
|
||||
|
||||
/* 访问栈顶元素 */
|
||||
|
@ -67,8 +66,8 @@ int main() {
|
|||
cout << "栈顶元素 top = " << top << endl;
|
||||
|
||||
/* 元素出栈 */
|
||||
int pop = stack->pop();
|
||||
cout << "出栈元素 pop = " << pop << ",出栈后 stack = ";
|
||||
stack->pop();
|
||||
cout << "出栈元素 pop = " << top << ",出栈后 stack = ";
|
||||
PrintUtil::printVector(stack->toVector());
|
||||
|
||||
/* 获取栈的长度 */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: deque.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: linkedlist_queue.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
@ -47,12 +47,14 @@ public:
|
|||
}
|
||||
|
||||
/* 出队 */
|
||||
int poll() {
|
||||
void poll() {
|
||||
int num = peek();
|
||||
// 删除头结点
|
||||
ListNode *tmp = front;
|
||||
front = front->next;
|
||||
// 释放内存
|
||||
delete tmp;
|
||||
queSize--;
|
||||
return num;
|
||||
}
|
||||
|
||||
/* 访问队首元素 */
|
||||
|
@ -94,8 +96,8 @@ int main() {
|
|||
cout << "队首元素 peek = " << peek << endl;
|
||||
|
||||
/* 元素出队 */
|
||||
int poll = queue->poll();
|
||||
cout << "出队元素 poll = " << poll << ",出队后 queue = ";
|
||||
queue->poll();
|
||||
cout << "出队元素 poll = " << peek << ",出队后 queue = ";
|
||||
PrintUtil::printVector(queue->toVector());
|
||||
|
||||
/* 获取队列的长度 */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: linkedlist_stack.cpp
|
||||
* Created Time: 2022-11-28
|
||||
* Author: qualifier1024 (2539244001@qq.com)
|
||||
|
@ -37,11 +37,13 @@ public:
|
|||
}
|
||||
|
||||
/* 出栈 */
|
||||
int pop() {
|
||||
void pop() {
|
||||
int num = top();
|
||||
ListNode *tmp = stackTop;
|
||||
stackTop = stackTop->next;
|
||||
// 释放内存
|
||||
delete tmp;
|
||||
stkSize--;
|
||||
return num;
|
||||
}
|
||||
|
||||
/* 访问栈顶元素 */
|
||||
|
@ -83,8 +85,8 @@ int main() {
|
|||
cout << "栈顶元素 top = " << top << endl;
|
||||
|
||||
/* 元素出栈 */
|
||||
int pop = stack->pop();
|
||||
cout << "出栈元素 pop = " << pop << ",出栈后 stack = ";
|
||||
stack->pop();
|
||||
cout << "出栈元素 pop = " << top << ",出栈后 stack = ";
|
||||
PrintUtil::printVector(stack->toVector());
|
||||
|
||||
/* 获取栈的长度 */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: queue.cpp
|
||||
* Created Time: 2022-11-28
|
||||
* Author: qualifier1024 (2539244001@qq.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: stack.cpp
|
||||
* Created Time: 2022-11-28
|
||||
* Author: qualifier1024 (2539244001@qq.com)
|
||||
|
|
|
@ -1,228 +0,0 @@
|
|||
/*
|
||||
* File: avl_tree.cpp
|
||||
* Created Time: 2022-12-2
|
||||
* Author: mgisr (maguagua0706@gmail.com)
|
||||
*/
|
||||
|
||||
#include "../include/include.hpp"
|
||||
|
||||
class AvlTree {
|
||||
private:
|
||||
TreeNode *root{};
|
||||
static bool isBalance(const TreeNode *p);
|
||||
static int getBalanceFactor(const TreeNode *p);
|
||||
static void updateHeight(TreeNode *p);
|
||||
void fixBalance(TreeNode *p);
|
||||
static bool isLeftChild(const TreeNode *p);
|
||||
static TreeNode *&fromParentTo(TreeNode *node);
|
||||
public:
|
||||
AvlTree() = default;
|
||||
AvlTree(const AvlTree &p) = default;
|
||||
const TreeNode *search(int val);
|
||||
bool insert(int val);
|
||||
bool remove(int val);
|
||||
void printTree();
|
||||
};
|
||||
|
||||
// 判断该结点是否平衡
|
||||
bool AvlTree::isBalance(const TreeNode *p) {
|
||||
int balance_factor = getBalanceFactor(p);
|
||||
if (-1 <= balance_factor && balance_factor <= 1) { return true; }
|
||||
else { return false; }
|
||||
}
|
||||
|
||||
// 获取当前结点的平衡因子
|
||||
int AvlTree::getBalanceFactor(const TreeNode *p) {
|
||||
if (p->left == nullptr && p->right == nullptr) { return 0; }
|
||||
else if (p->left == nullptr) { return (-1 - p->right->height); }
|
||||
else if (p->right == nullptr) { return p->left->height + 1; }
|
||||
else { return p->left->height - p->right->height; }
|
||||
}
|
||||
|
||||
// 更新结点高度
|
||||
void AvlTree::updateHeight(TreeNode *p) {
|
||||
if (p->left == nullptr && p->right == nullptr) { p->height = 0; }
|
||||
else if (p->left == nullptr) { p->height = p->right->height + 1; }
|
||||
else if (p->right == nullptr) { p->height = p->left->height + 1; }
|
||||
else { p->height = std::max(p->left->height, p->right->height) + 1; }
|
||||
}
|
||||
|
||||
void AvlTree::fixBalance(TreeNode *p) {
|
||||
// 左旋操作
|
||||
auto rotate_left = [&](TreeNode *node) -> TreeNode * {
|
||||
TreeNode *temp = node->right;
|
||||
temp->parent = p->parent;
|
||||
node->right = temp->left;
|
||||
if (temp->left != nullptr) {
|
||||
temp->left->parent = node;
|
||||
}
|
||||
temp->left = node;
|
||||
node->parent = temp;
|
||||
updateHeight(node);
|
||||
updateHeight(temp);
|
||||
return temp;
|
||||
};
|
||||
// 右旋操作
|
||||
auto rotate_right = [&](TreeNode *node) -> TreeNode * {
|
||||
TreeNode *temp = node->left;
|
||||
temp->parent = p->parent;
|
||||
node->left = temp->right;
|
||||
if (temp->right != nullptr) {
|
||||
temp->right->parent = node;
|
||||
}
|
||||
temp->right = node;
|
||||
node->parent = temp;
|
||||
updateHeight(node);
|
||||
updateHeight(temp);
|
||||
return temp;
|
||||
};
|
||||
// 根据规则选取旋转方式
|
||||
if (getBalanceFactor(p) > 1) {
|
||||
if (getBalanceFactor(p->left) > 0) {
|
||||
if (p->parent == nullptr) { root = rotate_right(p); }
|
||||
else { fromParentTo(p) = rotate_right(p); }
|
||||
} else {
|
||||
p->left = rotate_left(p->left);
|
||||
if (p->parent == nullptr) { root = rotate_right(p); }
|
||||
else { fromParentTo(p) = rotate_right(p); }
|
||||
}
|
||||
} else {
|
||||
if (getBalanceFactor(p->right) < 0) {
|
||||
if (p->parent == nullptr) { root = rotate_left(p); }
|
||||
else { fromParentTo(p) = rotate_left(p); }
|
||||
} else {
|
||||
p->right = rotate_right(p->right);
|
||||
if (p->parent == nullptr) { root = rotate_left(p); }
|
||||
else { fromParentTo(p) = rotate_left(p); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 判断当前结点是否为其父节点的左孩子
|
||||
bool AvlTree::isLeftChild(const TreeNode *p) {
|
||||
if (p->parent == nullptr) { return false; }
|
||||
return (p->parent->left == p);
|
||||
}
|
||||
|
||||
// 返回父节点指向当前结点指针的引用
|
||||
TreeNode *&AvlTree::fromParentTo(TreeNode *node) {
|
||||
if (isLeftChild(node)) { return node->parent->left; }
|
||||
else { return node->parent->right; }
|
||||
}
|
||||
|
||||
const TreeNode *AvlTree::search(int val) {
|
||||
TreeNode *p = root;
|
||||
while (p != nullptr) {
|
||||
if (p->val == val) { return p; }
|
||||
else if (p->val > val) { p = p->left; }
|
||||
else { p = p->right; }
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool AvlTree::insert(int val) {
|
||||
TreeNode *p = root;
|
||||
if (p == nullptr) {
|
||||
root = new TreeNode(val);
|
||||
return true;
|
||||
}
|
||||
for (;;) {
|
||||
if (p->val == val) { return false; }
|
||||
else if (p->val > val) {
|
||||
if (p->left == nullptr) {
|
||||
p->left = new TreeNode(val, p);
|
||||
break;
|
||||
} else {
|
||||
p = p->left;
|
||||
}
|
||||
} else {
|
||||
if (p->right == nullptr) {
|
||||
p->right = new TreeNode(val, p);
|
||||
break;
|
||||
} else {
|
||||
p = p->right;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; p != nullptr; p = p->parent) {
|
||||
if (!isBalance(p)) {
|
||||
fixBalance(p);
|
||||
break;
|
||||
} else { updateHeight(p); }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AvlTree::remove(int val) {
|
||||
TreeNode *p = root;
|
||||
if (p == nullptr) { return false; }
|
||||
while (p != nullptr) {
|
||||
if (p->val == val) {
|
||||
TreeNode *real_delete_node = p;
|
||||
TreeNode *next_node;
|
||||
if (p->left == nullptr) {
|
||||
next_node = p->right;
|
||||
if (p->parent == nullptr) { root = next_node; }
|
||||
else { fromParentTo(p) = next_node; }
|
||||
} else if (p->right == nullptr) {
|
||||
next_node = p->left;
|
||||
if (p->parent == nullptr) { root = next_node; }
|
||||
else { fromParentTo(p) = next_node; }
|
||||
} else {
|
||||
while (real_delete_node->left != nullptr) {
|
||||
real_delete_node = real_delete_node->left;
|
||||
}
|
||||
std::swap(p->val, real_delete_node->val);
|
||||
next_node = real_delete_node->right;
|
||||
if (real_delete_node->parent == p) { p->right = next_node; }
|
||||
else { real_delete_node->parent->left = next_node; }
|
||||
}
|
||||
if (next_node != nullptr) {
|
||||
next_node->parent = real_delete_node->parent;
|
||||
}
|
||||
for (p = real_delete_node; p != nullptr; p = p->parent) {
|
||||
if (!isBalance(p)) { fixBalance(p); }
|
||||
updateHeight(p);
|
||||
}
|
||||
delete real_delete_node;
|
||||
return true;
|
||||
} else if (p->val > val) {
|
||||
p = p->left;
|
||||
} else {
|
||||
p = p->right;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void inOrder(const TreeNode *root) {
|
||||
if (root == nullptr) return;
|
||||
inOrder(root->left);
|
||||
cout << root->val << ' ';
|
||||
inOrder(root->right);
|
||||
}
|
||||
|
||||
void AvlTree::printTree() {
|
||||
inOrder(root);
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
AvlTree tree = AvlTree();
|
||||
// tree.insert(13);
|
||||
// tree.insert(24);
|
||||
// tree.insert(37);
|
||||
// tree.insert(90);
|
||||
// tree.insert(53);
|
||||
|
||||
tree.insert(53);
|
||||
tree.insert(90);
|
||||
tree.insert(37);
|
||||
tree.insert(24);
|
||||
tree.insert(13);
|
||||
tree.remove(90);
|
||||
tree.printTree();
|
||||
const TreeNode *p = tree.search(37);
|
||||
cout << p->val;
|
||||
return 0;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: binary_search_tree.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
@ -96,11 +96,13 @@ public:
|
|||
// 删除结点 cur
|
||||
if (pre->left == cur) pre->left = child;
|
||||
else pre->right = child;
|
||||
// 释放内存
|
||||
delete cur;
|
||||
}
|
||||
// 子结点数量 = 2
|
||||
else {
|
||||
// 获取中序遍历中 cur 的下一个结点
|
||||
TreeNode* nex = min(cur->right);
|
||||
TreeNode* nex = getInOrderNext(cur->right);
|
||||
int tmp = nex->val;
|
||||
// 递归删除结点 nex
|
||||
remove(nex->val);
|
||||
|
@ -110,8 +112,8 @@ public:
|
|||
return cur;
|
||||
}
|
||||
|
||||
/* 获取最小结点 */
|
||||
TreeNode* min(TreeNode* root) {
|
||||
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
|
||||
TreeNode* getInOrderNext(TreeNode* root) {
|
||||
if (root == nullptr) return root;
|
||||
// 循环访问左子结点,直到叶结点时为最小结点,跳出
|
||||
while (root->left != nullptr) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: binary_tree.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
@ -33,6 +33,7 @@ int main() {
|
|||
PrintUtil::printTree(n1);
|
||||
// 删除结点 P
|
||||
n1->left = n2;
|
||||
delete P; // 释放内存
|
||||
cout << endl << "删除结点 P 后\n" << endl;
|
||||
PrintUtil::printTree(n1);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: binary_tree_bfs.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
@ -30,8 +30,7 @@ vector<int> hierOrder(TreeNode* root) {
|
|||
int main() {
|
||||
/* 初始化二叉树 */
|
||||
// 这里借助了一个从数组直接生成二叉树的函数
|
||||
TreeNode* root = vecToTree(vector<int>
|
||||
{ 1, 2, 3, 4, 5, 6, 7, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX });
|
||||
TreeNode* root = vecToTree(vector<int> { 1, 2, 3, 4, 5, 6, 7 });
|
||||
cout << endl << "初始化二叉树\n" << endl;
|
||||
PrintUtil::printTree(root);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: binary_tree_dfs.cpp
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
@ -41,8 +41,7 @@ void postOrder(TreeNode* root) {
|
|||
int main() {
|
||||
/* 初始化二叉树 */
|
||||
// 这里借助了一个从数组直接生成二叉树的函数
|
||||
TreeNode* root = vecToTree(vector<int>
|
||||
{ 1, 2, 3, 4, 5, 6, 7, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX});
|
||||
TreeNode* root = vecToTree(vector<int> { 1, 2, 3, 4, 5, 6, 7 });
|
||||
cout << endl << "初始化二叉树\n" << endl;
|
||||
PrintUtil::printTree(root);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: PrintUtil.hpp
|
||||
* Created Time: 2021-12-19
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: PrintUtil.hpp
|
||||
* Created Time: 2021-12-19
|
||||
* Author: Krahets (krahets@163.com), msk397 (machangxinq@gmail.com)
|
||||
|
@ -9,6 +9,7 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <climits>
|
||||
#include "ListNode.hpp"
|
||||
#include "TreeNode.hpp"
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: PrintUtil.hpp
|
||||
* Created Time: 2021-12-19
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
@ -27,23 +27,24 @@ struct TreeNode {
|
|||
* @return TreeNode*
|
||||
*/
|
||||
TreeNode *vecToTree(vector<int> list) {
|
||||
if (list.empty()) {
|
||||
if (list.empty())
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto *root = new TreeNode(list[0]);
|
||||
queue<TreeNode *> que;
|
||||
size_t n = list.size(), index = 1;
|
||||
while (index < n) {
|
||||
que.emplace(root);
|
||||
size_t n = list.size(), index = 0;
|
||||
while (!que.empty()) {
|
||||
auto node = que.front();
|
||||
que.pop();
|
||||
|
||||
if (++index >= n) break;
|
||||
if (index < n) {
|
||||
node->left = new TreeNode(list[index++]);
|
||||
node->left = new TreeNode(list[index]);
|
||||
que.emplace(node->left);
|
||||
}
|
||||
if (++index >= n) break;
|
||||
if (index < n) {
|
||||
node->right = new TreeNode(list[index++]);
|
||||
node->right = new TreeNode(list[index]);
|
||||
que.emplace(node->right);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: PrintUtil.hpp
|
||||
* Created Time: 2021-12-19
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -8,9 +8,7 @@ namespace hello_algo.chapter_array_and_linkedlist
|
|||
{
|
||||
public class Array
|
||||
{
|
||||
/// <summary>
|
||||
/// 随机返回一个数组元素
|
||||
/// </summary>
|
||||
/* 随机返回一个数组元素 */
|
||||
public static int RandomAccess(int[] nums)
|
||||
{
|
||||
Random random = new();
|
||||
|
@ -19,9 +17,7 @@ namespace hello_algo.chapter_array_and_linkedlist
|
|||
return randomNum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 扩展数组长度
|
||||
/// </summary>
|
||||
/* 扩展数组长度 */
|
||||
public static int[] Extend(int[] nums, int enlarge)
|
||||
{
|
||||
// 初始化一个扩展长度后的数组
|
||||
|
@ -35,9 +31,7 @@ namespace hello_algo.chapter_array_and_linkedlist
|
|||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在数组的索引 index 处插入元素 num
|
||||
/// </summary>
|
||||
/* 在数组的索引 index 处插入元素 num */
|
||||
public static void Insert(int[] nums, int num, int index)
|
||||
{
|
||||
// 把索引 index 以及之后的所有元素向后移动一位
|
||||
|
@ -49,9 +43,7 @@ namespace hello_algo.chapter_array_and_linkedlist
|
|||
nums[index] = num;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除索引 index 处元素
|
||||
/// </summary>
|
||||
/* 删除索引 index 处元素 */
|
||||
public static void Remove(int[] nums, int index)
|
||||
{
|
||||
// 把索引 index 之后的所有元素向前移动一位
|
||||
|
@ -61,9 +53,7 @@ namespace hello_algo.chapter_array_and_linkedlist
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 遍历数组
|
||||
/// </summary>
|
||||
/* 遍历数组 */
|
||||
public static void Traverse(int[] nums)
|
||||
{
|
||||
int count = 0;
|
||||
|
@ -79,9 +69,7 @@ namespace hello_algo.chapter_array_and_linkedlist
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在数组中查找指定元素
|
||||
/// </summary>
|
||||
/* 在数组中查找指定元素 */
|
||||
public static int Find(int[] nums, int target)
|
||||
{
|
||||
for (int i = 0; i < nums.Length; i++)
|
||||
|
@ -92,15 +80,13 @@ namespace hello_algo.chapter_array_and_linkedlist
|
|||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 辅助函数,数组转字符串
|
||||
/// </summary>
|
||||
/* 辅助函数,数组转字符串 */
|
||||
public static string ToString(int[] nums)
|
||||
{
|
||||
return string.Join(",", nums);
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
|
||||
[Test]
|
||||
public static void Test()
|
||||
{
|
||||
|
|
|
@ -9,9 +9,7 @@ namespace hello_algo.chapter_array_and_linkedlist
|
|||
{
|
||||
public class linked_list
|
||||
{
|
||||
/// <summary>
|
||||
/// 在链表的结点 n0 之后插入结点 P
|
||||
/// </summary>
|
||||
/* 在链表的结点 n0 之后插入结点 P */
|
||||
public static void Insert(ListNode n0, ListNode P)
|
||||
{
|
||||
ListNode? n1 = n0.next;
|
||||
|
@ -19,9 +17,7 @@ namespace hello_algo.chapter_array_and_linkedlist
|
|||
P.next = n1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除链表的结点 n0 之后的首个结点
|
||||
/// </summary>
|
||||
/* 删除链表的结点 n0 之后的首个结点 */
|
||||
public static void Remove(ListNode n0)
|
||||
{
|
||||
if (n0.next == null)
|
||||
|
@ -32,23 +28,19 @@ namespace hello_algo.chapter_array_and_linkedlist
|
|||
n0.next = n1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 访问链表中索引为 index 的结点
|
||||
/// </summary>
|
||||
/* 访问链表中索引为 index 的结点 */
|
||||
public static ListNode? Access(ListNode head, int index)
|
||||
{
|
||||
for (int i = 0; i < index; i++)
|
||||
{
|
||||
head = head.next;
|
||||
if (head == null)
|
||||
return null;
|
||||
head = head.next;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在链表中查找值为 target 的首个结点
|
||||
/// </summary>
|
||||
/* 在链表中查找值为 target 的首个结点 */
|
||||
public static int Find(ListNode head, int target)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -62,7 +54,7 @@ namespace hello_algo.chapter_array_and_linkedlist
|
|||
return -1;
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
|
||||
[Test]
|
||||
public void Test()
|
||||
{
|
||||
|
|
|
@ -31,10 +31,10 @@ namespace hello_algo.chapter_sorting
|
|||
// 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++
|
||||
if (i > leftEnd)
|
||||
nums[k] = tmp[j++];
|
||||
// 否则,若“右子数组已全部合并完”或“左子数组元素 < 右子数组元素”,则选取左子数组元素,并且 i++
|
||||
// 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++
|
||||
else if (j > rightEnd || tmp[i] <= tmp[j])
|
||||
nums[k] = tmp[i++];
|
||||
// 否则,若“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
|
||||
// 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
|
||||
else
|
||||
nums[k] = tmp[j++];
|
||||
}
|
||||
|
|
49
codes/csharp/chapter_stack_and_queue/deque.cs
Normal file
49
codes/csharp/chapter_stack_and_queue/deque.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* File: deque.cs
|
||||
* Created Time: 2022-12-30
|
||||
* Author: moonache (microin1301@outlook.com)
|
||||
*/
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace hello_algo.chapter_stack_and_queue
|
||||
{
|
||||
public class deque
|
||||
{
|
||||
[Test]
|
||||
public void Test()
|
||||
{
|
||||
/* 初始化双向队列 */
|
||||
// 在 C# 中,将链表 LinkedList 看作双向队列来使用
|
||||
LinkedList<int> deque = new LinkedList<int>();
|
||||
|
||||
/* 元素入队 */
|
||||
deque.AddLast(2); // 添加至队尾
|
||||
deque.AddLast(5);
|
||||
deque.AddLast(4);
|
||||
deque.AddFirst(3); // 添加至队首
|
||||
deque.AddFirst(1);
|
||||
Console.WriteLine("双向队列 deque = " + String.Join(",", deque.ToArray()));
|
||||
|
||||
/* 访问元素 */
|
||||
int peekFirst = deque.First.Value; // 队首元素
|
||||
Console.WriteLine("队首元素 peekFirst = " + peekFirst);
|
||||
int peekLast = deque.Last.Value; // 队尾元素
|
||||
Console.WriteLine("队尾元素 peekLast = " + peekLast);
|
||||
|
||||
/* 元素出队 */
|
||||
deque.RemoveFirst(); // 队首元素出队
|
||||
Console.WriteLine("队首元素出队后 deque = " + String.Join(",", deque.ToArray()));
|
||||
deque.RemoveLast(); // 队尾元素出队
|
||||
Console.WriteLine("队尾元素出队后 deque = " + String.Join(",", deque.ToArray()));
|
||||
|
||||
/* 获取双向队列的长度 */
|
||||
int size = deque.Count;
|
||||
Console.WriteLine("双向队列长度 size = " + size);
|
||||
|
||||
/* 判断双向队列是否为空 */
|
||||
bool isEmpty = deque.Count == 0;
|
||||
Console.WriteLine("双向队列是否为空 = " + isEmpty);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -162,7 +162,7 @@ namespace hello_algo.chapter_tree
|
|||
else
|
||||
{
|
||||
// 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点
|
||||
TreeNode? temp = minNode(node.right);
|
||||
TreeNode? temp = getInOrderNext(node.right);
|
||||
node.right = removeHelper(node.right, temp.val);
|
||||
node.val = temp.val;
|
||||
}
|
||||
|
@ -174,8 +174,8 @@ namespace hello_algo.chapter_tree
|
|||
return node;
|
||||
}
|
||||
|
||||
/* 获取最小结点 */
|
||||
private TreeNode? minNode(TreeNode? node)
|
||||
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
|
||||
private TreeNode? getInOrderNext(TreeNode? node)
|
||||
{
|
||||
if (node == null) return node;
|
||||
// 循环访问左子结点,直到叶结点时为最小结点,跳出
|
||||
|
|
|
@ -35,11 +35,7 @@ namespace hello_algo.chapter_tree
|
|||
return root;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找结点
|
||||
/// </summary>
|
||||
/// <param name="num"></param>
|
||||
/// <returns></returns>
|
||||
/* 查找结点 */
|
||||
public TreeNode? search(int num)
|
||||
{
|
||||
TreeNode? cur = root;
|
||||
|
@ -125,7 +121,7 @@ namespace hello_algo.chapter_tree
|
|||
else
|
||||
{
|
||||
// 获取中序遍历中 cur 的下一个结点
|
||||
TreeNode? nex = min(cur.right);
|
||||
TreeNode? nex = getInOrderNext(cur.right);
|
||||
if (nex != null)
|
||||
{
|
||||
int tmp = nex.val;
|
||||
|
@ -138,8 +134,8 @@ namespace hello_algo.chapter_tree
|
|||
return cur;
|
||||
}
|
||||
|
||||
/* 获取最小结点 */
|
||||
private TreeNode? min(TreeNode? root)
|
||||
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
|
||||
private TreeNode? getInOrderNext(TreeNode? root)
|
||||
{
|
||||
if (root == null) return root;
|
||||
// 循环访问左子结点,直到叶结点时为最小结点,跳出
|
||||
|
|
|
@ -12,11 +12,7 @@ namespace hello_algo.chapter_tree
|
|||
public class binary_tree_bfs
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 层序遍历
|
||||
/// </summary>
|
||||
/// <param name="root"></param>
|
||||
/// <returns></returns>
|
||||
/* 层序遍历 */
|
||||
public List<int> hierOrder(TreeNode root)
|
||||
{
|
||||
// 初始化队列,加入根结点
|
||||
|
@ -41,8 +37,7 @@ namespace hello_algo.chapter_tree
|
|||
{
|
||||
/* 初始化二叉树 */
|
||||
// 这里借助了一个从数组直接生成二叉树的函数
|
||||
TreeNode? root = TreeNode.ArrToTree(new int?[] {
|
||||
1, 2, 3, 4, 5, 6, 7, null, null, null, null, null, null, null, null});
|
||||
TreeNode? root = TreeNode.ArrToTree(new int?[] { 1, 2, 3, 4, 5, 6, 7 });
|
||||
Console.WriteLine("\n初始化二叉树\n");
|
||||
PrintUtil.PrintTree(root);
|
||||
|
||||
|
|
|
@ -13,10 +13,7 @@ namespace hello_algo.chapter_tree
|
|||
{
|
||||
List<int> list = new();
|
||||
|
||||
/// <summary>
|
||||
/// 前序遍历
|
||||
/// </summary>
|
||||
/// <param name="root"></param>
|
||||
/* 前序遍历 */
|
||||
void preOrder(TreeNode? root)
|
||||
{
|
||||
if (root == null) return;
|
||||
|
@ -26,10 +23,7 @@ namespace hello_algo.chapter_tree
|
|||
preOrder(root.right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 中序遍历
|
||||
/// </summary>
|
||||
/// <param name="root"></param>
|
||||
/* 中序遍历 */
|
||||
void inOrder(TreeNode? root)
|
||||
{
|
||||
if (root == null) return;
|
||||
|
@ -39,10 +33,7 @@ namespace hello_algo.chapter_tree
|
|||
inOrder(root.right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 后序遍历
|
||||
/// </summary>
|
||||
/// <param name="root"></param>
|
||||
/* 后序遍历 */
|
||||
void postOrder(TreeNode? root)
|
||||
{
|
||||
if (root == null) return;
|
||||
|
@ -57,8 +48,7 @@ namespace hello_algo.chapter_tree
|
|||
{
|
||||
/* 初始化二叉树 */
|
||||
// 这里借助了一个从数组直接生成二叉树的函数
|
||||
TreeNode? root = TreeNode.ArrToTree(new int?[] {
|
||||
1, 2, 3, 4, 5, 6, 7, null, null, null, null, null, null, null, null});
|
||||
TreeNode? root = TreeNode.ArrToTree(new int?[] { 1, 2, 3, 4, 5, 6, 7 });
|
||||
Console.WriteLine("\n初始化二叉树\n");
|
||||
PrintUtil.PrintTree(root);
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace hello_algo.include
|
|||
}
|
||||
|
||||
/**
|
||||
* Generate a binary tree with an array
|
||||
* Generate a binary tree given an array
|
||||
* @param arr
|
||||
* @return
|
||||
*/
|
||||
|
@ -31,22 +31,22 @@ namespace hello_algo.include
|
|||
TreeNode root = new TreeNode((int) arr[0]);
|
||||
Queue<TreeNode> queue = new Queue<TreeNode>();
|
||||
queue.Enqueue(root);
|
||||
int i = 1;
|
||||
while (queue.Count!=0)
|
||||
int i = 0;
|
||||
while (queue.Count != 0)
|
||||
{
|
||||
TreeNode node = queue.Dequeue();
|
||||
if (++i >= arr.Length) break;
|
||||
if (arr[i] != null)
|
||||
{
|
||||
node.left = new TreeNode((int) arr[i]);
|
||||
queue.Enqueue(node.left);
|
||||
}
|
||||
i++;
|
||||
if (++i >= arr.Length) break;
|
||||
if (arr[i] != null)
|
||||
{
|
||||
node.right = new TreeNode((int) arr[i]);
|
||||
queue.Enqueue(node.right);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
|
74
codes/go/chapter_array_and_linkedlist/array.go
Normal file
74
codes/go/chapter_array_and_linkedlist/array.go
Normal file
|
@ -0,0 +1,74 @@
|
|||
// File: array.go
|
||||
// Created Time: 2022-12-29
|
||||
// Author: GuoWei (gongguowei01@gmail.com), cathay (cathaycchen@gmail.com)
|
||||
|
||||
package chapter_array_and_linkedlist
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
/* 随机返回一个数组元素 */
|
||||
func randomAccess(nums []int) (randomNum int) {
|
||||
// 在区间 [0, nums.length) 中随机抽取一个数字
|
||||
randomIndex := rand.Intn(len(nums))
|
||||
// 获取并返回随机元素
|
||||
randomNum = nums[randomIndex]
|
||||
return
|
||||
}
|
||||
|
||||
/* 扩展数组长度 */
|
||||
func extend(nums []int, enlarge int) []int {
|
||||
// 初始化一个扩展长度后的数组
|
||||
res := make([]int, len(nums)+enlarge)
|
||||
// 将原数组中的所有元素复制到新数组
|
||||
for i, num := range nums {
|
||||
res[i] = num
|
||||
}
|
||||
// 返回扩展后的新数组
|
||||
return res
|
||||
}
|
||||
|
||||
/* 在数组的索引 index 处插入元素 num */
|
||||
func insert(nums []int, num int, index int) {
|
||||
// 把索引 index 以及之后的所有元素向后移动一位
|
||||
for i := len(nums) - 1; i > index; i-- {
|
||||
nums[i] = nums[i-1]
|
||||
}
|
||||
// 将 num 赋给 index 处元素
|
||||
nums[index] = num
|
||||
}
|
||||
|
||||
/* 删除索引 index 处元素 */
|
||||
func remove(nums []int, index int) {
|
||||
// 把索引 index 之后的所有元素向前移动一位
|
||||
for i := index; i < len(nums)-1; i++ {
|
||||
nums[i] = nums[i+1]
|
||||
}
|
||||
}
|
||||
|
||||
/* 遍历数组 */
|
||||
func traverse(nums []int) {
|
||||
count := 0
|
||||
// 通过索引遍历数组
|
||||
for i := 0; i < len(nums); i++ {
|
||||
count++
|
||||
}
|
||||
count = 0
|
||||
// 直接遍历数组
|
||||
for range nums {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
/* 在数组中查找指定元素 */
|
||||
func find(nums []int, target int) (index int) {
|
||||
index = -1
|
||||
for i := 0; i < len(nums); i++ {
|
||||
if nums[i] == target {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
50
codes/go/chapter_array_and_linkedlist/array_test.go
Normal file
50
codes/go/chapter_array_and_linkedlist/array_test.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
// File: array_test.go
|
||||
// Created Time: 2022-12-29
|
||||
// Author: GuoWei (gongguowei01@gmail.com), cathay (cathaycchen@gmail.com)
|
||||
|
||||
package chapter_array_and_linkedlist
|
||||
|
||||
/**
|
||||
我们将 Go 中的 Slice 切片看作 Array 数组。因为这样可以
|
||||
降低理解成本,利于我们将关注点放在数据结构与算法上。
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
/* Driver Code */
|
||||
func TestArray(t *testing.T) {
|
||||
/* 初始化数组 */
|
||||
var arr [5]int
|
||||
fmt.Println("数组 arr =", arr)
|
||||
// 在 Go 中,指定长度时([5]int)为数组,不指定长度时([]int)为切片
|
||||
// 由于 Go 的数组被设计为在编译期确定长度,因此只能使用常量来指定长度
|
||||
// 为了方便实现扩容 extend() 方法,以下将切片(Slice)看作数组(Array)
|
||||
nums := []int{1, 3, 2, 5, 4}
|
||||
fmt.Println("数组 nums =", nums)
|
||||
|
||||
/* 随机访问 */
|
||||
randomNum := randomAccess(nums)
|
||||
fmt.Println("在 nums 中获取随机元素", randomNum)
|
||||
|
||||
/* 长度扩展 */
|
||||
nums = extend(nums, 3)
|
||||
fmt.Println("将数组长度扩展至 8 ,得到 nums =", nums)
|
||||
|
||||
/* 插入元素 */
|
||||
insert(nums, 6, 3)
|
||||
fmt.Println("在索引 3 处插入数字 6 ,得到 nums =", nums)
|
||||
|
||||
/* 删除元素 */
|
||||
remove(nums, 2)
|
||||
fmt.Println("删除索引 2 处的元素,得到 nums =", nums)
|
||||
|
||||
/* 遍历数组 */
|
||||
traverse(nums)
|
||||
|
||||
/* 查找元素 */
|
||||
index := find(nums, 3)
|
||||
fmt.Println("在 nums 中查找元素 3 ,得到索引 =", index)
|
||||
}
|
51
codes/go/chapter_array_and_linkedlist/linked_list.go
Normal file
51
codes/go/chapter_array_and_linkedlist/linked_list.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
// File: linked_list.go
|
||||
// Created Time: 2022-12-29
|
||||
// Author: cathay (cathaycchen@gmail.com)
|
||||
|
||||
package chapter_array_and_linkedlist
|
||||
|
||||
import (
|
||||
. "github.com/krahets/hello-algo/pkg"
|
||||
)
|
||||
|
||||
/* 在链表的结点 n0 之后插入结点 P */
|
||||
func insertNode(n0 *ListNode, P *ListNode) {
|
||||
n1 := n0.Next
|
||||
n0.Next = P
|
||||
P.Next = n1
|
||||
}
|
||||
|
||||
/* 删除链表的结点 n0 之后的首个结点 */
|
||||
func removeNode(n0 *ListNode) {
|
||||
if n0.Next == nil {
|
||||
return
|
||||
}
|
||||
// n0 -> P -> n1
|
||||
P := n0.Next
|
||||
n1 := P.Next
|
||||
n0.Next = n1
|
||||
}
|
||||
|
||||
/* 访问链表中索引为 index 的结点 */
|
||||
func access(head *ListNode, index int) *ListNode {
|
||||
for i := 0; i < index; i++ {
|
||||
if head == nil {
|
||||
return nil
|
||||
}
|
||||
head = head.Next
|
||||
}
|
||||
return head
|
||||
}
|
||||
|
||||
/* 在链表中查找值为 target 的首个结点 */
|
||||
func findNode(head *ListNode, target int) int {
|
||||
index := 0
|
||||
for head != nil {
|
||||
if head.Val == target {
|
||||
return index
|
||||
}
|
||||
head = head.Next
|
||||
index++
|
||||
}
|
||||
return -1
|
||||
}
|
48
codes/go/chapter_array_and_linkedlist/linked_list_test.go
Normal file
48
codes/go/chapter_array_and_linkedlist/linked_list_test.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
// File: linked_list_test.go
|
||||
// Created Time: 2022-12-29
|
||||
// Author: cathay (cathaycchen@gmail.com)
|
||||
|
||||
package chapter_array_and_linkedlist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
. "github.com/krahets/hello-algo/pkg"
|
||||
)
|
||||
|
||||
func TestLikedList(t *testing.T) {
|
||||
/* 初始化链表 1 -> 3 -> 2 -> 5 -> 4 */
|
||||
// 初始化各个结点
|
||||
n0 := NewListNode(1)
|
||||
n1 := NewListNode(3)
|
||||
n2 := NewListNode(2)
|
||||
n3 := NewListNode(5)
|
||||
n4 := NewListNode(4)
|
||||
|
||||
// 构建引用指向
|
||||
n0.Next = n1
|
||||
n1.Next = n2
|
||||
n2.Next = n3
|
||||
n3.Next = n4
|
||||
fmt.Println("初始化的链表为")
|
||||
PrintLinkedList(n0)
|
||||
|
||||
/* 插入结点 */
|
||||
insertNode(n0, NewListNode(0))
|
||||
fmt.Println("插入结点后的链表为")
|
||||
PrintLinkedList(n0)
|
||||
|
||||
/* 删除结点 */
|
||||
removeNode(n0)
|
||||
fmt.Println("删除结点后的链表为")
|
||||
PrintLinkedList(n0)
|
||||
|
||||
/* 访问结点 */
|
||||
node := access(n0, 3)
|
||||
fmt.Println("链表中索引 3 处的结点的值 =", node)
|
||||
|
||||
/* 查找结点 */
|
||||
index := findNode(n0, 2)
|
||||
fmt.Println("链表中值为 2 的结点的索引 =", index)
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
package chapter_array_and_linkedlist
|
||||
|
||||
/* 列表类简易实现 */
|
||||
type MyList struct {
|
||||
type myList struct {
|
||||
numsCapacity int
|
||||
nums []int
|
||||
numsSize int
|
||||
|
@ -13,8 +13,8 @@ type MyList struct {
|
|||
}
|
||||
|
||||
/* 构造函数 */
|
||||
func newMyList() *MyList {
|
||||
return &MyList{
|
||||
func newMyList() *myList {
|
||||
return &myList{
|
||||
numsCapacity: 10, // 列表容量
|
||||
nums: make([]int, 10), // 数组(存储列表元素)
|
||||
numsSize: 0, // 列表长度(即当前元素数量)
|
||||
|
@ -23,17 +23,17 @@ func newMyList() *MyList {
|
|||
}
|
||||
|
||||
/* 获取列表长度(即当前元素数量) */
|
||||
func (l *MyList) size() int {
|
||||
func (l *myList) size() int {
|
||||
return l.numsSize
|
||||
}
|
||||
|
||||
/* 获取列表容量 */
|
||||
func (l *MyList) capacity() int {
|
||||
func (l *myList) capacity() int {
|
||||
return l.numsCapacity
|
||||
}
|
||||
|
||||
/* 访问元素 */
|
||||
func (l *MyList) get(index int) int {
|
||||
func (l *myList) get(index int) int {
|
||||
// 索引如果越界则抛出异常,下同
|
||||
if index >= l.numsSize {
|
||||
panic("索引越界")
|
||||
|
@ -42,7 +42,7 @@ func (l *MyList) get(index int) int {
|
|||
}
|
||||
|
||||
/* 更新元素 */
|
||||
func (l *MyList) set(num, index int) {
|
||||
func (l *myList) set(num, index int) {
|
||||
if index >= l.numsSize {
|
||||
panic("索引越界")
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ func (l *MyList) set(num, index int) {
|
|||
}
|
||||
|
||||
/* 尾部添加元素 */
|
||||
func (l *MyList) add(num int) {
|
||||
func (l *myList) add(num int) {
|
||||
// 元素数量超出容量时,触发扩容机制
|
||||
if l.numsSize == l.numsCapacity {
|
||||
l.extendCapacity()
|
||||
|
@ -61,7 +61,7 @@ func (l *MyList) add(num int) {
|
|||
}
|
||||
|
||||
/* 中间插入元素 */
|
||||
func (l *MyList) insert(num, index int) {
|
||||
func (l *myList) insert(num, index int) {
|
||||
if index >= l.numsSize {
|
||||
panic("索引越界")
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ func (l *MyList) insert(num, index int) {
|
|||
}
|
||||
|
||||
/* 删除元素 */
|
||||
func (l *MyList) remove(index int) int {
|
||||
func (l *myList) remove(index int) int {
|
||||
if index >= l.numsSize {
|
||||
panic("索引越界")
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ func (l *MyList) remove(index int) int {
|
|||
}
|
||||
|
||||
/* 列表扩容 */
|
||||
func (l *MyList) extendCapacity() {
|
||||
func (l *myList) extendCapacity() {
|
||||
// 新建一个长度为 self.__size 的数组,并将原数组拷贝到新数组
|
||||
l.nums = append(l.nums, make([]int, l.numsCapacity*(l.extendRatio-1))...)
|
||||
// 更新列表容量
|
||||
|
@ -103,7 +103,7 @@ func (l *MyList) extendCapacity() {
|
|||
}
|
||||
|
||||
/* 返回有效长度的列表 */
|
||||
func (l *MyList) toArray() []int {
|
||||
func (l *myList) toArray() []int {
|
||||
// 仅转换有效长度范围内的列表元素
|
||||
return l.nums[:l.numsSize]
|
||||
}
|
||||
|
|
|
@ -9,31 +9,31 @@ import (
|
|||
"strconv"
|
||||
)
|
||||
|
||||
/* Node 结构体 */
|
||||
type Node struct {
|
||||
/* 结构体 */
|
||||
type node struct {
|
||||
val int
|
||||
next *Node
|
||||
next *node
|
||||
}
|
||||
|
||||
/* TreeNode 二叉树 */
|
||||
type TreeNode struct {
|
||||
/* treeNode 二叉树 */
|
||||
type treeNode struct {
|
||||
val int
|
||||
left *TreeNode
|
||||
right *TreeNode
|
||||
left *treeNode
|
||||
right *treeNode
|
||||
}
|
||||
|
||||
/* 创建 Node 结构体 */
|
||||
func newNode(val int) *Node {
|
||||
return &Node{val: val}
|
||||
/* 创建 node 结构体 */
|
||||
func newNode(val int) *node {
|
||||
return &node{val: val}
|
||||
}
|
||||
|
||||
/* 创建 TreeNode 结构体 */
|
||||
func newTreeNode(val int) *TreeNode {
|
||||
return &TreeNode{val: val}
|
||||
/* 创建 treeNode 结构体 */
|
||||
func newTreeNode(val int) *treeNode {
|
||||
return &treeNode{val: val}
|
||||
}
|
||||
|
||||
/* 输出二叉树 */
|
||||
func printTree(root *TreeNode) {
|
||||
func printTree(root *treeNode) {
|
||||
if root == nil {
|
||||
return
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ func spaceLinear(n int) {
|
|||
// 长度为 n 的数组占用 O(n) 空间
|
||||
_ = make([]int, n)
|
||||
// 长度为 n 的列表占用 O(n) 空间
|
||||
var nodes []*Node
|
||||
var nodes []*node
|
||||
for i := 0; i < n; i++ {
|
||||
nodes = append(nodes, newNode(i))
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ func spaceQuadraticRecur(n int) int {
|
|||
}
|
||||
|
||||
/* 指数阶(建立满二叉树) */
|
||||
func buildTree(n int) *TreeNode {
|
||||
func buildTree(n int) *treeNode {
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,30 +7,30 @@ package chapter_hashing
|
|||
import "fmt"
|
||||
|
||||
/* 键值对 int->String */
|
||||
type Entry struct {
|
||||
type entry struct {
|
||||
key int
|
||||
val string
|
||||
}
|
||||
|
||||
/* 基于数组简易实现的哈希表 */
|
||||
type ArrayHashMap struct {
|
||||
bucket []*Entry
|
||||
type arrayHashMap struct {
|
||||
bucket []*entry
|
||||
}
|
||||
|
||||
func newArrayHashMap() *ArrayHashMap {
|
||||
func newArrayHashMap() *arrayHashMap {
|
||||
// 初始化一个长度为 100 的桶(数组)
|
||||
bucket := make([]*Entry, 100)
|
||||
return &ArrayHashMap{bucket: bucket}
|
||||
bucket := make([]*entry, 100)
|
||||
return &arrayHashMap{bucket: bucket}
|
||||
}
|
||||
|
||||
/* 哈希函数 */
|
||||
func (a *ArrayHashMap) hashFunc(key int) int {
|
||||
func (a *arrayHashMap) hashFunc(key int) int {
|
||||
index := key % 100
|
||||
return index
|
||||
}
|
||||
|
||||
/* 查询操作 */
|
||||
func (a *ArrayHashMap) get(key int) string {
|
||||
func (a *arrayHashMap) get(key int) string {
|
||||
index := a.hashFunc(key)
|
||||
pair := a.bucket[index]
|
||||
if pair == nil {
|
||||
|
@ -40,22 +40,22 @@ func (a *ArrayHashMap) get(key int) string {
|
|||
}
|
||||
|
||||
/* 添加操作 */
|
||||
func (a *ArrayHashMap) put(key int, val string) {
|
||||
pair := &Entry{key: key, val: val}
|
||||
func (a *arrayHashMap) put(key int, val string) {
|
||||
pair := &entry{key: key, val: val}
|
||||
index := a.hashFunc(key)
|
||||
a.bucket[index] = pair
|
||||
}
|
||||
|
||||
/* 删除操作 */
|
||||
func (a *ArrayHashMap) remove(key int) {
|
||||
func (a *arrayHashMap) remove(key int) {
|
||||
index := a.hashFunc(key)
|
||||
// 置为 nil ,代表删除
|
||||
a.bucket[index] = nil
|
||||
}
|
||||
|
||||
/* 获取所有键对 */
|
||||
func (a *ArrayHashMap) entrySet() []*Entry {
|
||||
var pairs []*Entry
|
||||
func (a *arrayHashMap) entrySet() []*entry {
|
||||
var pairs []*entry
|
||||
for _, pair := range a.bucket {
|
||||
if pair != nil {
|
||||
pairs = append(pairs, pair)
|
||||
|
@ -65,7 +65,7 @@ func (a *ArrayHashMap) entrySet() []*Entry {
|
|||
}
|
||||
|
||||
/* 获取所有键 */
|
||||
func (a *ArrayHashMap) keySet() []int {
|
||||
func (a *arrayHashMap) keySet() []int {
|
||||
var keys []int
|
||||
for _, pair := range a.bucket {
|
||||
if pair != nil {
|
||||
|
@ -76,7 +76,7 @@ func (a *ArrayHashMap) keySet() []int {
|
|||
}
|
||||
|
||||
/* 获取所有值 */
|
||||
func (a *ArrayHashMap) valueSet() []string {
|
||||
func (a *arrayHashMap) valueSet() []string {
|
||||
var values []string
|
||||
for _, pair := range a.bucket {
|
||||
if pair != nil {
|
||||
|
@ -87,7 +87,7 @@ func (a *ArrayHashMap) valueSet() []string {
|
|||
}
|
||||
|
||||
/* 打印哈希表 */
|
||||
func (a *ArrayHashMap) print() {
|
||||
func (a *arrayHashMap) print() {
|
||||
for _, pair := range a.bucket {
|
||||
if pair != nil {
|
||||
fmt.Println(pair.key, "->", pair.val)
|
||||
|
|
|
@ -6,8 +6,9 @@ package chapter_searching
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
. "github.com/krahets/hello-algo/pkg"
|
||||
"testing"
|
||||
|
||||
. "github.com/krahets/hello-algo/pkg"
|
||||
)
|
||||
|
||||
func TestHashingSearch(t *testing.T) {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Created Time: 2022-12-06
|
||||
// Author: Slone123c (274325721@qq.com)
|
||||
|
||||
package bubble_sort
|
||||
package chapter_sorting
|
||||
|
||||
/* 冒泡排序 */
|
||||
func bubbleSort(nums []int) {
|
|
@ -2,7 +2,7 @@
|
|||
// Created Time: 2022-12-06
|
||||
// Author: Slone123c (274325721@qq.com)
|
||||
|
||||
package bubble_sort
|
||||
package chapter_sorting
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -2,7 +2,7 @@
|
|||
// Created Time: 2022-12-12
|
||||
// Author: msk397 (machangxinq@gmail.com)
|
||||
|
||||
package insertion_sort
|
||||
package chapter_sorting
|
||||
|
||||
func insertionSort(nums []int) {
|
||||
// 外循环:待排序元素数量为 n-1, n-2, ..., 1
|
|
@ -2,7 +2,7 @@
|
|||
// Created Time: 2022-12-12
|
||||
// Author: msk397 (machangxinq@gmail.com)
|
||||
|
||||
package insertion_sort
|
||||
package chapter_sorting
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -2,34 +2,34 @@
|
|||
// Created Time: 2022-12-13
|
||||
// Author: msk397 (machangxinq@gmail.com)
|
||||
|
||||
package merge_sort
|
||||
package chapter_sorting
|
||||
|
||||
// 合并左子数组和右子数组
|
||||
// 左子数组区间 [left, mid]
|
||||
// 右子数组区间 [mid + 1, right]
|
||||
func merge(nums []int, left, mid, right int) {
|
||||
// 初始化辅助数组 借助 copy模块
|
||||
// 初始化辅助数组 借助 copy 模块
|
||||
tmp := make([]int, right-left+1)
|
||||
for i := left; i <= right; i++ {
|
||||
tmp[i-left] = nums[i]
|
||||
}
|
||||
// 左子数组的起始索引和结束索引
|
||||
left_start, left_end := left-left, mid-left
|
||||
leftStart, leftEnd := left-left, mid-left
|
||||
// 右子数组的起始索引和结束索引
|
||||
right_start, right_end := mid+1-left, right-left
|
||||
rightStart, rightEnd := mid+1-left, right-left
|
||||
// i, j 分别指向左子数组、右子数组的首元素
|
||||
i, j := left_start, right_start
|
||||
i, j := leftStart, rightStart
|
||||
// 通过覆盖原数组 nums 来合并左子数组和右子数组
|
||||
for k := left; k <= right; k++ {
|
||||
// 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++
|
||||
if i > left_end {
|
||||
if i > leftEnd {
|
||||
nums[k] = tmp[j]
|
||||
j++
|
||||
// 否则,若“右子数组已全部合并完”或“左子数组元素 < 右子数组元素”,则选取左子数组元素,并且 i++
|
||||
} else if j > right_end || tmp[i] <= tmp[j] {
|
||||
// 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++
|
||||
} else if j > rightEnd || tmp[i] <= tmp[j] {
|
||||
nums[k] = tmp[i]
|
||||
i++
|
||||
// 否则,若“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
|
||||
// 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
|
||||
} else {
|
||||
nums[k] = tmp[j]
|
||||
j++
|
|
@ -1,8 +1,9 @@
|
|||
package merge_sort
|
||||
// File: merge_sort_test.go
|
||||
// Created Time: 2022-12-13
|
||||
// Author: msk397 (machangxinq@gmail.com)
|
||||
|
||||
package chapter_sorting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
|
@ -2,19 +2,19 @@
|
|||
// Created Time: 2022-12-12
|
||||
// Author: msk397 (machangxinq@gmail.com)
|
||||
|
||||
package quick_sort
|
||||
package chapter_sorting
|
||||
|
||||
// 快速排序
|
||||
type QuickSort struct{}
|
||||
type quickSort struct{}
|
||||
|
||||
// 快速排序(中位基准数优化)
|
||||
type QuickSortMedian struct{}
|
||||
type quickSortMedian struct{}
|
||||
|
||||
// 快速排序(尾递归优化)
|
||||
type QuickSortTailCall struct{}
|
||||
type quickSortTailCall struct{}
|
||||
|
||||
/* 哨兵划分 */
|
||||
func (q *QuickSort) partition(nums []int, left, right int) int {
|
||||
func (q *quickSort) partition(nums []int, left, right int) int {
|
||||
// 以 nums[left] 作为基准数
|
||||
i, j := left, right
|
||||
for i < j {
|
||||
|
@ -33,7 +33,7 @@ func (q *QuickSort) partition(nums []int, left, right int) int {
|
|||
}
|
||||
|
||||
/* 快速排序 */
|
||||
func (q *QuickSort) quickSort(nums []int, left, right int) {
|
||||
func (q *quickSort) quickSort(nums []int, left, right int) {
|
||||
// 子数组长度为 1 时终止递归
|
||||
if left >= right {
|
||||
return
|
||||
|
@ -46,7 +46,7 @@ func (q *QuickSort) quickSort(nums []int, left, right int) {
|
|||
}
|
||||
|
||||
/* 选取三个元素的中位数 */
|
||||
func (q *QuickSortMedian) medianThree(nums []int, left, mid, right int) int {
|
||||
func (q *quickSortMedian) medianThree(nums []int, left, mid, right int) int {
|
||||
if (nums[left] > nums[mid]) != (nums[left] > nums[right]) {
|
||||
return left
|
||||
} else if (nums[mid] < nums[left]) != (nums[mid] > nums[right]) {
|
||||
|
@ -56,7 +56,7 @@ func (q *QuickSortMedian) medianThree(nums []int, left, mid, right int) int {
|
|||
}
|
||||
|
||||
/* 哨兵划分(三数取中值)*/
|
||||
func (q *QuickSortMedian) partition(nums []int, left, right int) int {
|
||||
func (q *quickSortMedian) partition(nums []int, left, right int) int {
|
||||
// 以 nums[left] 作为基准数
|
||||
med := q.medianThree(nums, left, (left+right)/2, right)
|
||||
// 将中位数交换至数组最左端
|
||||
|
@ -79,7 +79,7 @@ func (q *QuickSortMedian) partition(nums []int, left, right int) int {
|
|||
}
|
||||
|
||||
/* 快速排序 */
|
||||
func (q *QuickSortMedian) quickSort(nums []int, left, right int) {
|
||||
func (q *quickSortMedian) quickSort(nums []int, left, right int) {
|
||||
// 子数组长度为 1 时终止递归
|
||||
if left >= right {
|
||||
return
|
||||
|
@ -92,7 +92,7 @@ func (q *QuickSortMedian) quickSort(nums []int, left, right int) {
|
|||
}
|
||||
|
||||
/* 哨兵划分 */
|
||||
func (q *QuickSortTailCall) partition(nums []int, left, right int) int {
|
||||
func (q *quickSortTailCall) partition(nums []int, left, right int) int {
|
||||
// 以 nums[left] 作为基准数
|
||||
i, j := left, right
|
||||
for i < j {
|
||||
|
@ -111,7 +111,7 @@ func (q *QuickSortTailCall) partition(nums []int, left, right int) int {
|
|||
}
|
||||
|
||||
/* 快速排序(尾递归优化)*/
|
||||
func (q *QuickSortTailCall) quickSort(nums []int, left, right int) {
|
||||
func (q *quickSortTailCall) quickSort(nums []int, left, right int) {
|
||||
// 子数组长度为 1 时终止
|
||||
for left < right {
|
||||
// 哨兵划分操作
|
|
@ -2,7 +2,7 @@
|
|||
// Created Time: 2022-12-12
|
||||
// Author: msk397 (machangxinq@gmail.com)
|
||||
|
||||
package quick_sort
|
||||
package chapter_sorting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
// 快速排序
|
||||
func TestQuickSort(t *testing.T) {
|
||||
q := QuickSort{}
|
||||
q := quickSort{}
|
||||
nums := []int{4, 1, 3, 1, 5, 2}
|
||||
q.quickSort(nums, 0, len(nums)-1)
|
||||
fmt.Println("快速排序完成后 nums = ", nums)
|
||||
|
@ -19,7 +19,7 @@ func TestQuickSort(t *testing.T) {
|
|||
|
||||
// 快速排序(中位基准数优化)
|
||||
func TestQuickSortMedian(t *testing.T) {
|
||||
q := QuickSortMedian{}
|
||||
q := quickSortMedian{}
|
||||
nums := []int{4, 1, 3, 1, 5, 2}
|
||||
q.quickSort(nums, 0, len(nums)-1)
|
||||
fmt.Println("快速排序(中位基准数优化)完成后 nums = ", nums)
|
||||
|
@ -27,7 +27,7 @@ func TestQuickSortMedian(t *testing.T) {
|
|||
|
||||
// 快速排序(尾递归优化)
|
||||
func TestQuickSortTailCall(t *testing.T) {
|
||||
q := QuickSortTailCall{}
|
||||
q := quickSortTailCall{}
|
||||
nums := []int{4, 1, 3, 1, 5, 2}
|
||||
q.quickSort(nums, 0, len(nums)-1)
|
||||
fmt.Println("快速排序(尾递归优化)完成后 nums = ", nums)
|
|
@ -5,16 +5,16 @@
|
|||
package chapter_stack_and_queue
|
||||
|
||||
/* 基于环形数组实现的队列 */
|
||||
type ArrayQueue struct {
|
||||
type arrayQueue struct {
|
||||
data []int // 用于存储队列元素的数组
|
||||
capacity int // 队列容量(即最多容量的元素个数)
|
||||
front int // 头指针,指向队首
|
||||
rear int // 尾指针,指向队尾 + 1
|
||||
}
|
||||
|
||||
// NewArrayQueue 基于环形数组实现的队列
|
||||
func NewArrayQueue(capacity int) *ArrayQueue {
|
||||
return &ArrayQueue{
|
||||
// newArrayQueue 基于环形数组实现的队列
|
||||
func newArrayQueue(capacity int) *arrayQueue {
|
||||
return &arrayQueue{
|
||||
data: make([]int, capacity),
|
||||
capacity: capacity,
|
||||
front: 0,
|
||||
|
@ -22,21 +22,21 @@ func NewArrayQueue(capacity int) *ArrayQueue {
|
|||
}
|
||||
}
|
||||
|
||||
// Size 获取队列的长度
|
||||
func (q *ArrayQueue) Size() int {
|
||||
// size 获取队列的长度
|
||||
func (q *arrayQueue) size() int {
|
||||
size := (q.capacity + q.rear - q.front) % q.capacity
|
||||
return size
|
||||
}
|
||||
|
||||
// IsEmpty 判断队列是否为空
|
||||
func (q *ArrayQueue) IsEmpty() bool {
|
||||
// isEmpty 判断队列是否为空
|
||||
func (q *arrayQueue) isEmpty() bool {
|
||||
return q.rear-q.front == 0
|
||||
}
|
||||
|
||||
// Offer 入队
|
||||
func (q *ArrayQueue) Offer(v int) {
|
||||
// offer 入队
|
||||
func (q *arrayQueue) offer(v int) {
|
||||
// 当 rear == capacity 表示队列已满
|
||||
if q.Size() == q.capacity {
|
||||
if q.size() == q.capacity {
|
||||
return
|
||||
}
|
||||
// 尾结点后添加
|
||||
|
@ -45,9 +45,9 @@ func (q *ArrayQueue) Offer(v int) {
|
|||
q.rear = (q.rear + 1) % q.capacity
|
||||
}
|
||||
|
||||
// Poll 出队
|
||||
func (q *ArrayQueue) Poll() any {
|
||||
if q.IsEmpty() {
|
||||
// poll 出队
|
||||
func (q *arrayQueue) poll() any {
|
||||
if q.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
v := q.data[q.front]
|
||||
|
@ -56,9 +56,9 @@ func (q *ArrayQueue) Poll() any {
|
|||
return v
|
||||
}
|
||||
|
||||
// Peek 访问队首元素
|
||||
func (q *ArrayQueue) Peek() any {
|
||||
if q.IsEmpty() {
|
||||
// peek 访问队首元素
|
||||
func (q *arrayQueue) peek() any {
|
||||
if q.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
v := q.data[q.front]
|
||||
|
@ -66,6 +66,6 @@ func (q *ArrayQueue) Peek() any {
|
|||
}
|
||||
|
||||
// 获取 Slice 用于打印
|
||||
func (s *ArrayQueue) toSlice() []int {
|
||||
return s.data[s.front:s.rear]
|
||||
func (q *arrayQueue) toSlice() []int {
|
||||
return q.data[q.front:q.rear]
|
||||
}
|
||||
|
|
|
@ -5,47 +5,47 @@
|
|||
package chapter_stack_and_queue
|
||||
|
||||
/* 基于数组实现的栈 */
|
||||
type ArrayStack struct {
|
||||
type arrayStack struct {
|
||||
data []int // 数据
|
||||
}
|
||||
|
||||
func NewArrayStack() *ArrayStack {
|
||||
return &ArrayStack{
|
||||
func newArrayStack() *arrayStack {
|
||||
return &arrayStack{
|
||||
// 设置栈的长度为 0,容量为 16
|
||||
data: make([]int, 0, 16),
|
||||
}
|
||||
}
|
||||
|
||||
// Size 栈的长度
|
||||
func (s *ArrayStack) Size() int {
|
||||
// size 栈的长度
|
||||
func (s *arrayStack) size() int {
|
||||
return len(s.data)
|
||||
}
|
||||
|
||||
// IsEmpty 栈是否为空
|
||||
func (s *ArrayStack) IsEmpty() bool {
|
||||
return s.Size() == 0
|
||||
// isEmpty 栈是否为空
|
||||
func (s *arrayStack) isEmpty() bool {
|
||||
return s.size() == 0
|
||||
}
|
||||
|
||||
// Push 入栈
|
||||
func (s *ArrayStack) Push(v int) {
|
||||
// push 入栈
|
||||
func (s *arrayStack) push(v int) {
|
||||
// 切片会自动扩容
|
||||
s.data = append(s.data, v)
|
||||
}
|
||||
|
||||
// Pop 出栈
|
||||
func (s *ArrayStack) Pop() any {
|
||||
// pop 出栈
|
||||
func (s *arrayStack) pop() any {
|
||||
// 弹出栈前,先判断是否为空
|
||||
if s.IsEmpty() {
|
||||
if s.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
val := s.Peek()
|
||||
val := s.peek()
|
||||
s.data = s.data[:len(s.data)-1]
|
||||
return val
|
||||
}
|
||||
|
||||
// Peek 获取栈顶元素
|
||||
func (s *ArrayStack) Peek() any {
|
||||
if s.IsEmpty() {
|
||||
// peek 获取栈顶元素
|
||||
func (s *arrayStack) peek() any {
|
||||
if s.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
val := s.data[len(s.data)-1]
|
||||
|
@ -53,6 +53,6 @@ func (s *ArrayStack) Peek() any {
|
|||
}
|
||||
|
||||
// 获取 Slice 用于打印
|
||||
func (s *ArrayStack) toSlice() []int {
|
||||
func (s *arrayStack) toSlice() []int {
|
||||
return s.data
|
||||
}
|
||||
|
|
|
@ -51,48 +51,48 @@ func TestDeque(t *testing.T) {
|
|||
|
||||
func TestLinkedListDeque(t *testing.T) {
|
||||
// 初始化队列
|
||||
deque := NewLinkedListDeque()
|
||||
deque := newLinkedListDeque()
|
||||
|
||||
// 元素入队
|
||||
deque.OfferLast(2)
|
||||
deque.OfferLast(5)
|
||||
deque.OfferLast(4)
|
||||
deque.OfferFirst(3)
|
||||
deque.OfferFirst(1)
|
||||
deque.offerLast(2)
|
||||
deque.offerLast(5)
|
||||
deque.offerLast(4)
|
||||
deque.offerFirst(3)
|
||||
deque.offerFirst(1)
|
||||
fmt.Print("队列 deque = ")
|
||||
PrintList(deque.toList())
|
||||
|
||||
// 访问队首元素
|
||||
front := deque.PeekFirst()
|
||||
front := deque.peekFirst()
|
||||
fmt.Println("队首元素 front =", front)
|
||||
rear := deque.PeekLast()
|
||||
rear := deque.peekLast()
|
||||
fmt.Println("队尾元素 rear =", rear)
|
||||
|
||||
// 元素出队
|
||||
pollFirst := deque.PollFirst()
|
||||
pollFirst := deque.pollFirst()
|
||||
fmt.Print("队首出队元素 pollFirst = ", pollFirst, ",队首出队后 deque = ")
|
||||
PrintList(deque.toList())
|
||||
pollLast := deque.PollLast()
|
||||
pollLast := deque.pollLast()
|
||||
fmt.Print("队尾出队元素 pollLast = ", pollLast, ",队尾出队后 deque = ")
|
||||
PrintList(deque.toList())
|
||||
|
||||
// 获取队的长度
|
||||
size := deque.Size()
|
||||
size := deque.size()
|
||||
fmt.Println("队的长度 size =", size)
|
||||
|
||||
// 判断是否为空
|
||||
isEmpty := deque.IsEmpty()
|
||||
isEmpty := deque.isEmpty()
|
||||
fmt.Println("队是否为空 =", isEmpty)
|
||||
}
|
||||
|
||||
// BenchmarkArrayQueue 67.92 ns/op in Mac M1 Pro
|
||||
func BenchmarkLinkedListDeque(b *testing.B) {
|
||||
stack := NewLinkedListDeque()
|
||||
stack := newLinkedListDeque()
|
||||
// use b.N for looping
|
||||
for i := 0; i < b.N; i++ {
|
||||
stack.OfferLast(777)
|
||||
stack.offerLast(777)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
stack.PollFirst()
|
||||
stack.pollFirst()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,31 +8,31 @@ import (
|
|||
"container/list"
|
||||
)
|
||||
|
||||
// LinkedListDeque 基于链表实现的双端队列, 使用内置包 list 来实现栈
|
||||
type LinkedListDeque struct {
|
||||
// linkedListDeque 基于链表实现的双端队列, 使用内置包 list 来实现栈
|
||||
type linkedListDeque struct {
|
||||
data *list.List
|
||||
}
|
||||
|
||||
// NewLinkedListDeque 初始化双端队列
|
||||
func NewLinkedListDeque() *LinkedListDeque {
|
||||
return &LinkedListDeque{
|
||||
// newLinkedListDeque 初始化双端队列
|
||||
func newLinkedListDeque() *linkedListDeque {
|
||||
return &linkedListDeque{
|
||||
data: list.New(),
|
||||
}
|
||||
}
|
||||
|
||||
// OfferFirst 队首元素入队
|
||||
func (s *LinkedListDeque) OfferFirst(value any) {
|
||||
// offerFirst 队首元素入队
|
||||
func (s *linkedListDeque) offerFirst(value any) {
|
||||
s.data.PushFront(value)
|
||||
}
|
||||
|
||||
// OfferLast 队尾元素入队
|
||||
func (s *LinkedListDeque) OfferLast(value any) {
|
||||
// offerLast 队尾元素入队
|
||||
func (s *linkedListDeque) offerLast(value any) {
|
||||
s.data.PushBack(value)
|
||||
}
|
||||
|
||||
// PollFirst 队首元素出队
|
||||
func (s *LinkedListDeque) PollFirst() any {
|
||||
if s.IsEmpty() {
|
||||
// pollFirst 队首元素出队
|
||||
func (s *linkedListDeque) pollFirst() any {
|
||||
if s.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
e := s.data.Front()
|
||||
|
@ -40,9 +40,9 @@ func (s *LinkedListDeque) PollFirst() any {
|
|||
return e.Value
|
||||
}
|
||||
|
||||
// PollLast 队尾元素出队
|
||||
func (s *LinkedListDeque) PollLast() any {
|
||||
if s.IsEmpty() {
|
||||
// pollLast 队尾元素出队
|
||||
func (s *linkedListDeque) pollLast() any {
|
||||
if s.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
e := s.data.Back()
|
||||
|
@ -50,35 +50,35 @@ func (s *LinkedListDeque) PollLast() any {
|
|||
return e.Value
|
||||
}
|
||||
|
||||
// PeekFirst 访问队首元素
|
||||
func (s *LinkedListDeque) PeekFirst() any {
|
||||
if s.IsEmpty() {
|
||||
// peekFirst 访问队首元素
|
||||
func (s *linkedListDeque) peekFirst() any {
|
||||
if s.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
e := s.data.Front()
|
||||
return e.Value
|
||||
}
|
||||
|
||||
// PeekLast 访问队尾元素
|
||||
func (s *LinkedListDeque) PeekLast() any {
|
||||
if s.IsEmpty() {
|
||||
// peekLast 访问队尾元素
|
||||
func (s *linkedListDeque) peekLast() any {
|
||||
if s.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
e := s.data.Back()
|
||||
return e.Value
|
||||
}
|
||||
|
||||
// Size 获取队列的长度
|
||||
func (s *LinkedListDeque) Size() int {
|
||||
// size 获取队列的长度
|
||||
func (s *linkedListDeque) size() int {
|
||||
return s.data.Len()
|
||||
}
|
||||
|
||||
// IsEmpty 判断队列是否为空
|
||||
func (s *LinkedListDeque) IsEmpty() bool {
|
||||
// isEmpty 判断队列是否为空
|
||||
func (s *linkedListDeque) isEmpty() bool {
|
||||
return s.data.Len() == 0
|
||||
}
|
||||
|
||||
// 获取 List 用于打印
|
||||
func (s *LinkedListDeque) toList() *list.List {
|
||||
func (s *linkedListDeque) toList() *list.List {
|
||||
return s.data
|
||||
}
|
||||
|
|
|
@ -9,26 +9,26 @@ import (
|
|||
)
|
||||
|
||||
/* 基于链表实现的队列 */
|
||||
type LinkedListQueue struct {
|
||||
type linkedListQueue struct {
|
||||
// 使用内置包 list 来实现队列
|
||||
data *list.List
|
||||
}
|
||||
|
||||
// NewLinkedListQueue 初始化链表
|
||||
func NewLinkedListQueue() *LinkedListQueue {
|
||||
return &LinkedListQueue{
|
||||
// newLinkedListQueue 初始化链表
|
||||
func newLinkedListQueue() *linkedListQueue {
|
||||
return &linkedListQueue{
|
||||
data: list.New(),
|
||||
}
|
||||
}
|
||||
|
||||
// Offer 入队
|
||||
func (s *LinkedListQueue) Offer(value any) {
|
||||
// offer 入队
|
||||
func (s *linkedListQueue) offer(value any) {
|
||||
s.data.PushBack(value)
|
||||
}
|
||||
|
||||
// Poll 出队
|
||||
func (s *LinkedListQueue) Poll() any {
|
||||
if s.IsEmpty() {
|
||||
// poll 出队
|
||||
func (s *linkedListQueue) poll() any {
|
||||
if s.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
e := s.data.Front()
|
||||
|
@ -36,26 +36,26 @@ func (s *LinkedListQueue) Poll() any {
|
|||
return e.Value
|
||||
}
|
||||
|
||||
// Peek 访问队首元素
|
||||
func (s *LinkedListQueue) Peek() any {
|
||||
if s.IsEmpty() {
|
||||
// peek 访问队首元素
|
||||
func (s *linkedListQueue) peek() any {
|
||||
if s.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
e := s.data.Front()
|
||||
return e.Value
|
||||
}
|
||||
|
||||
// Size 获取队列的长度
|
||||
func (s *LinkedListQueue) Size() int {
|
||||
// size 获取队列的长度
|
||||
func (s *linkedListQueue) size() int {
|
||||
return s.data.Len()
|
||||
}
|
||||
|
||||
// IsEmpty 判断队列是否为空
|
||||
func (s *LinkedListQueue) IsEmpty() bool {
|
||||
// isEmpty 判断队列是否为空
|
||||
func (s *linkedListQueue) isEmpty() bool {
|
||||
return s.data.Len() == 0
|
||||
}
|
||||
|
||||
// 获取 List 用于打印
|
||||
func (s *LinkedListQueue) toList() *list.List {
|
||||
func (s *linkedListQueue) toList() *list.List {
|
||||
return s.data
|
||||
}
|
||||
|
|
|
@ -9,26 +9,26 @@ import (
|
|||
)
|
||||
|
||||
/* 基于链表实现的栈 */
|
||||
type LinkedListStack struct {
|
||||
type linkedListStack struct {
|
||||
// 使用内置包 list 来实现栈
|
||||
data *list.List
|
||||
}
|
||||
|
||||
// NewLinkedListStack 初始化链表
|
||||
func NewLinkedListStack() *LinkedListStack {
|
||||
return &LinkedListStack{
|
||||
// newLinkedListStack 初始化链表
|
||||
func newLinkedListStack() *linkedListStack {
|
||||
return &linkedListStack{
|
||||
data: list.New(),
|
||||
}
|
||||
}
|
||||
|
||||
// Push 入栈
|
||||
func (s *LinkedListStack) Push(value int) {
|
||||
// push 入栈
|
||||
func (s *linkedListStack) push(value int) {
|
||||
s.data.PushBack(value)
|
||||
}
|
||||
|
||||
// Pop 出栈
|
||||
func (s *LinkedListStack) Pop() any {
|
||||
if s.IsEmpty() {
|
||||
// pop 出栈
|
||||
func (s *linkedListStack) pop() any {
|
||||
if s.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
e := s.data.Back()
|
||||
|
@ -36,26 +36,26 @@ func (s *LinkedListStack) Pop() any {
|
|||
return e.Value
|
||||
}
|
||||
|
||||
// Peek 访问栈顶元素
|
||||
func (s *LinkedListStack) Peek() any {
|
||||
if s.IsEmpty() {
|
||||
// peek 访问栈顶元素
|
||||
func (s *linkedListStack) peek() any {
|
||||
if s.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
e := s.data.Back()
|
||||
return e.Value
|
||||
}
|
||||
|
||||
// Size 获取栈的长度
|
||||
func (s *LinkedListStack) Size() int {
|
||||
// size 获取栈的长度
|
||||
func (s *linkedListStack) size() int {
|
||||
return s.data.Len()
|
||||
}
|
||||
|
||||
// IsEmpty 判断栈是否为空
|
||||
func (s *LinkedListStack) IsEmpty() bool {
|
||||
// isEmpty 判断栈是否为空
|
||||
func (s *linkedListStack) isEmpty() bool {
|
||||
return s.data.Len() == 0
|
||||
}
|
||||
|
||||
// 获取 List 用于打印
|
||||
func (s *LinkedListStack) toList() *list.List {
|
||||
func (s *linkedListStack) toList() *list.List {
|
||||
return s.data
|
||||
}
|
||||
|
|
|
@ -48,87 +48,87 @@ func TestQueue(t *testing.T) {
|
|||
func TestArrayQueue(t *testing.T) {
|
||||
// 初始化队列,使用队列的通用接口
|
||||
capacity := 10
|
||||
queue := NewArrayQueue(capacity)
|
||||
queue := newArrayQueue(capacity)
|
||||
|
||||
// 元素入队
|
||||
queue.Offer(1)
|
||||
queue.Offer(3)
|
||||
queue.Offer(2)
|
||||
queue.Offer(5)
|
||||
queue.Offer(4)
|
||||
queue.offer(1)
|
||||
queue.offer(3)
|
||||
queue.offer(2)
|
||||
queue.offer(5)
|
||||
queue.offer(4)
|
||||
fmt.Print("队列 queue = ")
|
||||
PrintSlice(queue.toSlice())
|
||||
|
||||
// 访问队首元素
|
||||
peek := queue.Peek()
|
||||
peek := queue.peek()
|
||||
fmt.Println("队首元素 peek =", peek)
|
||||
|
||||
// 元素出队
|
||||
poll := queue.Poll()
|
||||
poll := queue.poll()
|
||||
fmt.Print("出队元素 poll = ", poll, ", 出队后 queue = ")
|
||||
PrintSlice(queue.toSlice())
|
||||
|
||||
// 获取队的长度
|
||||
size := queue.Size()
|
||||
size := queue.size()
|
||||
fmt.Println("队的长度 size =", size)
|
||||
|
||||
// 判断是否为空
|
||||
isEmpty := queue.IsEmpty()
|
||||
isEmpty := queue.isEmpty()
|
||||
fmt.Println("队是否为空 =", isEmpty)
|
||||
}
|
||||
|
||||
func TestLinkedListQueue(t *testing.T) {
|
||||
// 初始化队
|
||||
queue := NewLinkedListQueue()
|
||||
queue := newLinkedListQueue()
|
||||
|
||||
// 元素入队
|
||||
queue.Offer(1)
|
||||
queue.Offer(3)
|
||||
queue.Offer(2)
|
||||
queue.Offer(5)
|
||||
queue.Offer(4)
|
||||
queue.offer(1)
|
||||
queue.offer(3)
|
||||
queue.offer(2)
|
||||
queue.offer(5)
|
||||
queue.offer(4)
|
||||
fmt.Print("队列 queue = ")
|
||||
PrintList(queue.toList())
|
||||
|
||||
// 访问队首元素
|
||||
peek := queue.Peek()
|
||||
peek := queue.peek()
|
||||
fmt.Println("队首元素 peek =", peek)
|
||||
|
||||
// 元素出队
|
||||
poll := queue.Poll()
|
||||
poll := queue.poll()
|
||||
fmt.Print("出队元素 poll = ", poll, ", 出队后 queue = ")
|
||||
PrintList(queue.toList())
|
||||
|
||||
// 获取队的长度
|
||||
size := queue.Size()
|
||||
size := queue.size()
|
||||
fmt.Println("队的长度 size =", size)
|
||||
|
||||
// 判断是否为空
|
||||
isEmpty := queue.IsEmpty()
|
||||
isEmpty := queue.isEmpty()
|
||||
fmt.Println("队是否为空 =", isEmpty)
|
||||
}
|
||||
|
||||
// BenchmarkArrayQueue 8 ns/op in Mac M1 Pro
|
||||
func BenchmarkArrayQueue(b *testing.B) {
|
||||
capacity := 1000
|
||||
stack := NewArrayQueue(capacity)
|
||||
stack := newArrayQueue(capacity)
|
||||
// use b.N for looping
|
||||
for i := 0; i < b.N; i++ {
|
||||
stack.Offer(777)
|
||||
stack.offer(777)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
stack.Poll()
|
||||
stack.poll()
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkLinkedQueue 62.66 ns/op in Mac M1 Pro
|
||||
func BenchmarkLinkedQueue(b *testing.B) {
|
||||
stack := NewLinkedListQueue()
|
||||
stack := newLinkedListQueue()
|
||||
// use b.N for looping
|
||||
for i := 0; i < b.N; i++ {
|
||||
stack.Offer(777)
|
||||
stack.offer(777)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
stack.Poll()
|
||||
stack.poll()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,85 +46,85 @@ func TestStack(t *testing.T) {
|
|||
|
||||
func TestArrayStack(t *testing.T) {
|
||||
// 初始化栈, 使用接口承接
|
||||
stack := NewArrayStack()
|
||||
stack := newArrayStack()
|
||||
|
||||
// 元素入栈
|
||||
stack.Push(1)
|
||||
stack.Push(3)
|
||||
stack.Push(2)
|
||||
stack.Push(5)
|
||||
stack.Push(4)
|
||||
stack.push(1)
|
||||
stack.push(3)
|
||||
stack.push(2)
|
||||
stack.push(5)
|
||||
stack.push(4)
|
||||
fmt.Print("栈 stack = ")
|
||||
PrintSlice(stack.toSlice())
|
||||
|
||||
// 访问栈顶元素
|
||||
peek := stack.Peek()
|
||||
peek := stack.peek()
|
||||
fmt.Println("栈顶元素 peek =", peek)
|
||||
|
||||
// 元素出栈
|
||||
pop := stack.Pop()
|
||||
pop := stack.pop()
|
||||
fmt.Print("出栈元素 pop = ", pop, ", 出栈后 stack = ")
|
||||
PrintSlice(stack.toSlice())
|
||||
|
||||
// 获取栈的长度
|
||||
size := stack.Size()
|
||||
size := stack.size()
|
||||
fmt.Println("栈的长度 size =", size)
|
||||
|
||||
// 判断是否为空
|
||||
isEmpty := stack.IsEmpty()
|
||||
isEmpty := stack.isEmpty()
|
||||
fmt.Println("栈是否为空 =", isEmpty)
|
||||
}
|
||||
|
||||
func TestLinkedListStack(t *testing.T) {
|
||||
// 初始化栈
|
||||
stack := NewLinkedListStack()
|
||||
stack := newLinkedListStack()
|
||||
// 元素入栈
|
||||
stack.Push(1)
|
||||
stack.Push(3)
|
||||
stack.Push(2)
|
||||
stack.Push(5)
|
||||
stack.Push(4)
|
||||
stack.push(1)
|
||||
stack.push(3)
|
||||
stack.push(2)
|
||||
stack.push(5)
|
||||
stack.push(4)
|
||||
fmt.Print("栈 stack = ")
|
||||
PrintList(stack.toList())
|
||||
|
||||
// 访问栈顶元素
|
||||
peek := stack.Peek()
|
||||
peek := stack.peek()
|
||||
fmt.Println("栈顶元素 peek =", peek)
|
||||
|
||||
// 元素出栈
|
||||
pop := stack.Pop()
|
||||
pop := stack.pop()
|
||||
fmt.Print("出栈元素 pop = ", pop, ", 出栈后 stack = ")
|
||||
PrintList(stack.toList())
|
||||
|
||||
// 获取栈的长度
|
||||
size := stack.Size()
|
||||
size := stack.size()
|
||||
fmt.Println("栈的长度 size =", size)
|
||||
|
||||
// 判断是否为空
|
||||
isEmpty := stack.IsEmpty()
|
||||
isEmpty := stack.isEmpty()
|
||||
fmt.Println("栈是否为空 =", isEmpty)
|
||||
}
|
||||
|
||||
// BenchmarkArrayStack 8 ns/op in Mac M1 Pro
|
||||
func BenchmarkArrayStack(b *testing.B) {
|
||||
stack := NewArrayStack()
|
||||
stack := newArrayStack()
|
||||
// use b.N for looping
|
||||
for i := 0; i < b.N; i++ {
|
||||
stack.Push(777)
|
||||
stack.push(777)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
stack.Pop()
|
||||
stack.pop()
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkLinkedListStack 65.02 ns/op in Mac M1 Pro
|
||||
func BenchmarkLinkedListStack(b *testing.B) {
|
||||
stack := NewLinkedListStack()
|
||||
stack := newLinkedListStack()
|
||||
// use b.N for looping
|
||||
for i := 0; i < b.N; i++ {
|
||||
stack.Push(777)
|
||||
stack.push(777)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
stack.Pop()
|
||||
stack.pop()
|
||||
}
|
||||
}
|
||||
|
|
211
codes/go/chapter_tree/avl_tree.go
Normal file
211
codes/go/chapter_tree/avl_tree.go
Normal file
|
@ -0,0 +1,211 @@
|
|||
// File: avl_tree.go
|
||||
// Created Time: 2023-01-08
|
||||
// Author: Reanon (793584285@qq.com)
|
||||
|
||||
package chapter_tree
|
||||
|
||||
import . "github.com/krahets/hello-algo/pkg"
|
||||
|
||||
/* AVL Tree*/
|
||||
type avlTree struct {
|
||||
// 根节点
|
||||
root *TreeNode
|
||||
}
|
||||
|
||||
func newAVLTree() *avlTree {
|
||||
return &avlTree{root: nil}
|
||||
}
|
||||
|
||||
/* 获取结点高度 */
|
||||
func height(node *TreeNode) int {
|
||||
// 空结点高度为 -1 ,叶结点高度为 0
|
||||
if node != nil {
|
||||
return node.Height
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
/* 更新结点高度 */
|
||||
func updateHeight(node *TreeNode) {
|
||||
lh := height(node.Left)
|
||||
rh := height(node.Right)
|
||||
// 结点高度等于最高子树高度 + 1
|
||||
if lh > rh {
|
||||
node.Height = lh + 1
|
||||
} else {
|
||||
node.Height = rh + 1
|
||||
}
|
||||
}
|
||||
|
||||
/* 获取平衡因子 */
|
||||
func balanceFactor(node *TreeNode) int {
|
||||
// 空结点平衡因子为 0
|
||||
if node == nil {
|
||||
return 0
|
||||
}
|
||||
// 结点平衡因子 = 左子树高度 - 右子树高度
|
||||
return height(node.Left) - height(node.Right)
|
||||
}
|
||||
|
||||
/* 右旋操作 */
|
||||
func rightRotate(node *TreeNode) *TreeNode {
|
||||
child := node.Left
|
||||
grandChild := child.Right
|
||||
// 以 child 为原点,将 node 向右旋转
|
||||
child.Right = node
|
||||
node.Left = grandChild
|
||||
// 更新结点高度
|
||||
updateHeight(node)
|
||||
updateHeight(child)
|
||||
// 返回旋转后子树的根节点
|
||||
return child
|
||||
}
|
||||
|
||||
/* 左旋操作 */
|
||||
func leftRotate(node *TreeNode) *TreeNode {
|
||||
child := node.Right
|
||||
grandChild := child.Left
|
||||
// 以 child 为原点,将 node 向左旋转
|
||||
child.Left = node
|
||||
node.Right = grandChild
|
||||
// 更新结点高度
|
||||
updateHeight(node)
|
||||
updateHeight(child)
|
||||
// 返回旋转后子树的根节点
|
||||
return child
|
||||
}
|
||||
|
||||
/* 执行旋转操作,使该子树重新恢复平衡 */
|
||||
func rotate(node *TreeNode) *TreeNode {
|
||||
// 获取结点 node 的平衡因子
|
||||
// Go 推荐短变量,这里 bf 指代 balanceFactor
|
||||
bf := balanceFactor(node)
|
||||
// 左偏树
|
||||
if bf > 1 {
|
||||
if balanceFactor(node.Left) >= 0 {
|
||||
// 右旋
|
||||
return rightRotate(node)
|
||||
} else {
|
||||
// 先左旋后右旋
|
||||
node.Left = leftRotate(node.Left)
|
||||
return rightRotate(node)
|
||||
}
|
||||
}
|
||||
// 右偏树
|
||||
if bf < -1 {
|
||||
if balanceFactor(node.Right) <= 0 {
|
||||
// 左旋
|
||||
return leftRotate(node)
|
||||
} else {
|
||||
// 先右旋后左旋
|
||||
node.Right = rightRotate(node.Right)
|
||||
return leftRotate(node)
|
||||
}
|
||||
}
|
||||
// 平衡树,无需旋转,直接返回
|
||||
return node
|
||||
}
|
||||
|
||||
/* 插入结点 */
|
||||
func (t *avlTree) insert(val int) *TreeNode {
|
||||
t.root = insertHelper(t.root, val)
|
||||
return t.root
|
||||
}
|
||||
|
||||
/* 递归插入结点(辅助函数) */
|
||||
func insertHelper(node *TreeNode, val int) *TreeNode {
|
||||
if node == nil {
|
||||
return NewTreeNode(val)
|
||||
}
|
||||
/* 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
|
||||
}
|
||||
|
||||
/* 删除结点 */
|
||||
func (t *avlTree) remove(val int) *TreeNode {
|
||||
root := removeHelper(t.root, val)
|
||||
return root
|
||||
}
|
||||
|
||||
/* 递归删除结点(辅助函数) */
|
||||
func removeHelper(node *TreeNode, val int) *TreeNode {
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
/* 1. 查找结点,并删除之 */
|
||||
if val < node.Val {
|
||||
node.Left = removeHelper(node.Left, val)
|
||||
} else if val > node.Val {
|
||||
node.Right = removeHelper(node.Right, val)
|
||||
} else {
|
||||
if node.Left == nil || node.Right == nil {
|
||||
child := node.Left
|
||||
if node.Right != nil {
|
||||
child = node.Right
|
||||
}
|
||||
// 子结点数量 = 0 ,直接删除 node 并返回
|
||||
if child == nil {
|
||||
return nil
|
||||
} else {
|
||||
// 子结点数量 = 1 ,直接删除 node
|
||||
node = child
|
||||
}
|
||||
} else {
|
||||
// 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点
|
||||
temp := getInOrderNext(node.Right)
|
||||
node.Right = removeHelper(node.Right, temp.Val)
|
||||
node.Val = temp.Val
|
||||
}
|
||||
}
|
||||
// 更新结点高度
|
||||
updateHeight(node)
|
||||
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
|
||||
node = rotate(node)
|
||||
// 返回子树的根节点
|
||||
return node
|
||||
}
|
||||
|
||||
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
|
||||
func 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 {
|
||||
// 目标结点在 root 的右子树中
|
||||
if cur.Val < val {
|
||||
cur = cur.Right
|
||||
} else if cur.Val > val {
|
||||
// 目标结点在 root 的左子树中
|
||||
cur = cur.Left
|
||||
} else {
|
||||
// 找到目标结点,跳出循环
|
||||
break
|
||||
}
|
||||
}
|
||||
// 返回目标结点
|
||||
return cur
|
||||
}
|
54
codes/go/chapter_tree/avl_tree_test.go
Normal file
54
codes/go/chapter_tree/avl_tree_test.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
// File: avl_tree_test.go
|
||||
// Created Time: 2023-01-08
|
||||
// Author: Reanon (793584285@qq.com)
|
||||
|
||||
package chapter_tree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
. "github.com/krahets/hello-algo/pkg"
|
||||
)
|
||||
|
||||
func TestAVLTree(t *testing.T) {
|
||||
/* 初始化空 AVL 树 */
|
||||
tree := newAVLTree()
|
||||
/* 插入结点 */
|
||||
// 请关注插入结点后,AVL 树是如何保持平衡的
|
||||
testInsert(tree, 1)
|
||||
testInsert(tree, 2)
|
||||
testInsert(tree, 3)
|
||||
testInsert(tree, 4)
|
||||
testInsert(tree, 5)
|
||||
testInsert(tree, 8)
|
||||
testInsert(tree, 7)
|
||||
testInsert(tree, 9)
|
||||
testInsert(tree, 10)
|
||||
testInsert(tree, 6)
|
||||
|
||||
/* 插入重复结点 */
|
||||
testInsert(tree, 7)
|
||||
|
||||
/* 删除结点 */
|
||||
// 请关注删除结点后,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)
|
||||
}
|
||||
|
||||
func testInsert(tree *avlTree, val int) {
|
||||
tree.insert(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)
|
||||
PrintTree(tree.root)
|
||||
}
|
|
@ -10,26 +10,26 @@ import (
|
|||
. "github.com/krahets/hello-algo/pkg"
|
||||
)
|
||||
|
||||
type BinarySearchTree struct {
|
||||
type binarySearchTree struct {
|
||||
root *TreeNode
|
||||
}
|
||||
|
||||
func NewBinarySearchTree(nums []int) *BinarySearchTree {
|
||||
func newBinarySearchTree(nums []int) *binarySearchTree {
|
||||
// sorting array
|
||||
sort.Ints(nums)
|
||||
root := buildBinarySearchTree(nums, 0, len(nums)-1)
|
||||
return &BinarySearchTree{
|
||||
return &binarySearchTree{
|
||||
root: root,
|
||||
}
|
||||
}
|
||||
|
||||
// GetRoot Get the root node of binary search tree
|
||||
func (bst *BinarySearchTree) GetRoot() *TreeNode {
|
||||
/* 获取根结点 */
|
||||
func (bst *binarySearchTree) getRoot() *TreeNode {
|
||||
return bst.root
|
||||
}
|
||||
|
||||
// GetMin Get node with the min value
|
||||
func (bst *BinarySearchTree) GetMin(node *TreeNode) *TreeNode {
|
||||
/* 获取中序遍历的下一个结点 */
|
||||
func (bst *binarySearchTree) getInOrderNext(node *TreeNode) *TreeNode {
|
||||
if node == nil {
|
||||
return node
|
||||
}
|
||||
|
@ -40,21 +40,8 @@ func (bst *BinarySearchTree) GetMin(node *TreeNode) *TreeNode {
|
|||
return node
|
||||
}
|
||||
|
||||
// GetInorderNext Get node inorder next
|
||||
func (bst *BinarySearchTree) GetInorderNext(node *TreeNode) *TreeNode {
|
||||
if node == nil || node.Right == nil {
|
||||
return node
|
||||
}
|
||||
node = node.Right
|
||||
// 循环访问左子结点,直到叶结点时为最小结点,跳出
|
||||
for node.Left != nil {
|
||||
node = node.Left
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
/* 查找结点 */
|
||||
func (bst *BinarySearchTree) Search(num int) *TreeNode {
|
||||
func (bst *binarySearchTree) search(num int) *TreeNode {
|
||||
node := bst.root
|
||||
// 循环查找,越过叶结点后跳出
|
||||
for node != nil {
|
||||
|
@ -74,7 +61,7 @@ func (bst *BinarySearchTree) Search(num int) *TreeNode {
|
|||
}
|
||||
|
||||
/* 插入结点 */
|
||||
func (bst *BinarySearchTree) Insert(num int) *TreeNode {
|
||||
func (bst *binarySearchTree) insert(num int) *TreeNode {
|
||||
cur := bst.root
|
||||
// 若树为空,直接提前返回
|
||||
if cur == nil {
|
||||
|
@ -105,7 +92,7 @@ func (bst *BinarySearchTree) Insert(num int) *TreeNode {
|
|||
}
|
||||
|
||||
/* 删除结点 */
|
||||
func (bst *BinarySearchTree) Remove(num int) *TreeNode {
|
||||
func (bst *binarySearchTree) remove(num int) *TreeNode {
|
||||
cur := bst.root
|
||||
// 若树为空,直接提前返回
|
||||
if cur == nil {
|
||||
|
@ -149,10 +136,10 @@ func (bst *BinarySearchTree) Remove(num int) *TreeNode {
|
|||
// 子结点数为 2
|
||||
} else {
|
||||
// 获取中序遍历中待删除结点 cur 的下一个结点
|
||||
next := bst.GetInorderNext(cur)
|
||||
next := bst.getInOrderNext(cur)
|
||||
temp := next.Val
|
||||
// 递归删除结点 next
|
||||
bst.Remove(next.Val)
|
||||
bst.remove(next.Val)
|
||||
// 将 next 的值复制给 cur
|
||||
cur.Val = temp
|
||||
}
|
||||
|
@ -173,7 +160,7 @@ func buildBinarySearchTree(nums []int, left, right int) *TreeNode {
|
|||
return root
|
||||
}
|
||||
|
||||
// Print binary search tree
|
||||
func (bst *BinarySearchTree) Print() {
|
||||
// print binary search tree
|
||||
func (bst *binarySearchTree) print() {
|
||||
PrintTree(bst.root)
|
||||
}
|
||||
|
|
|
@ -11,34 +11,31 @@ import (
|
|||
|
||||
func TestBinarySearchTree(t *testing.T) {
|
||||
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
|
||||
bst := NewBinarySearchTree(nums)
|
||||
fmt.Println("初始化的二叉树为:")
|
||||
bst.Print()
|
||||
bst := newBinarySearchTree(nums)
|
||||
fmt.Println("\n初始化的二叉树为:")
|
||||
bst.print()
|
||||
|
||||
// 获取根结点
|
||||
node := bst.GetRoot()
|
||||
fmt.Println("二叉树的根结点为:", node.Val)
|
||||
// 获取最小的结点
|
||||
node = bst.GetMin(bst.GetRoot())
|
||||
fmt.Println("二叉树的最小结点为:", node.Val)
|
||||
node := bst.getRoot()
|
||||
fmt.Println("\n二叉树的根结点为:", node.Val)
|
||||
|
||||
// 查找结点
|
||||
node = bst.Search(7)
|
||||
fmt.Println("查找到的结点对象为", node, ",结点值 =", node.Val)
|
||||
|
||||
// 插入结点
|
||||
node = bst.Insert(16)
|
||||
fmt.Println("插入结点后 16 的二叉树为:")
|
||||
bst.Print()
|
||||
node = bst.insert(16)
|
||||
fmt.Println("\n插入结点后 16 的二叉树为:")
|
||||
bst.print()
|
||||
|
||||
// 删除结点
|
||||
bst.Remove(1)
|
||||
fmt.Println("删除结点 1 后的二叉树为:")
|
||||
bst.Print()
|
||||
bst.Remove(2)
|
||||
fmt.Println("删除结点 2 后的二叉树为:")
|
||||
bst.Print()
|
||||
bst.Remove(4)
|
||||
fmt.Println("删除结点 4 后的二叉树为:")
|
||||
bst.Print()
|
||||
bst.remove(1)
|
||||
fmt.Println("\n删除结点 1 后的二叉树为:")
|
||||
bst.print()
|
||||
bst.remove(2)
|
||||
fmt.Println("\n删除结点 2 后的二叉树为:")
|
||||
bst.print()
|
||||
bst.remove(4)
|
||||
fmt.Println("\n删除结点 4 后的二叉树为:")
|
||||
bst.print()
|
||||
}
|
||||
|
|
|
@ -14,11 +14,11 @@ import (
|
|||
func TestLevelOrder(t *testing.T) {
|
||||
/* 初始化二叉树 */
|
||||
// 这里借助了一个从数组直接生成二叉树的函数
|
||||
root := ArrayToTree([]int{1, 2, 3, 4, 5, 6, 7})
|
||||
fmt.Println("初始化二叉树: ")
|
||||
root := ArrToTree([]any{1, 2, 3, 4, 5, 6, 7})
|
||||
fmt.Println("\n初始化二叉树: ")
|
||||
PrintTree(root)
|
||||
|
||||
// 层序遍历
|
||||
nums := levelOrder(root)
|
||||
fmt.Println("层序遍历的结点打印序列 =", nums)
|
||||
fmt.Println("\n层序遍历的结点打印序列 =", nums)
|
||||
}
|
||||
|
|
|
@ -14,22 +14,22 @@ import (
|
|||
func TestPreInPostOrderTraversal(t *testing.T) {
|
||||
/* 初始化二叉树 */
|
||||
// 这里借助了一个从数组直接生成二叉树的函数
|
||||
root := ArrayToTree([]int{1, 2, 3, 4, 5, 6, 7})
|
||||
fmt.Println("初始化二叉树: ")
|
||||
root := ArrToTree([]any{1, 2, 3, 4, 5, 6, 7})
|
||||
fmt.Println("\n初始化二叉树: ")
|
||||
PrintTree(root)
|
||||
|
||||
// 前序遍历
|
||||
nums = nil
|
||||
preOrder(root)
|
||||
fmt.Println("前序遍历的结点打印序列 =", nums)
|
||||
fmt.Println("\n前序遍历的结点打印序列 =", nums)
|
||||
|
||||
// 中序遍历
|
||||
nums = nil
|
||||
inOrder(root)
|
||||
fmt.Println("中序遍历的结点打印序列 =", nums)
|
||||
fmt.Println("\n中序遍历的结点打印序列 =", nums)
|
||||
|
||||
// 后序遍历
|
||||
nums = nil
|
||||
postOrder(root)
|
||||
fmt.Println("后序遍历的结点打印序列 =", nums)
|
||||
fmt.Println("\n后序遍历的结点打印序列 =", nums)
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ func printTreeHelper(root *TreeNode, prev *trunk, isLeft bool) {
|
|||
printTreeHelper(root.Left, trunk, false)
|
||||
}
|
||||
|
||||
// trunk Help to Print tree structure
|
||||
// trunk Help to print tree structure
|
||||
type trunk struct {
|
||||
prev *trunk
|
||||
str string
|
||||
|
@ -103,4 +103,4 @@ func PrintMap[K comparable, V any](m map[K]V) {
|
|||
for key, value := range m {
|
||||
fmt.Println(key, "->", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,41 +9,48 @@ import (
|
|||
)
|
||||
|
||||
type TreeNode struct {
|
||||
Val int
|
||||
Left *TreeNode
|
||||
Right *TreeNode
|
||||
Val int // 结点值
|
||||
Height int // 结点高度
|
||||
Left *TreeNode // 左子结点引用
|
||||
Right *TreeNode // 右子结点引用
|
||||
}
|
||||
|
||||
func NewTreeNode(v int) *TreeNode {
|
||||
return &TreeNode{
|
||||
Left: nil,
|
||||
Right: nil,
|
||||
Val: v,
|
||||
Val: v,
|
||||
Height: 0,
|
||||
Left: nil,
|
||||
Right: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// ArrayToTree Generate a binary tree with an array
|
||||
func ArrayToTree(arr []int) *TreeNode {
|
||||
// ArrToTree Generate a binary tree given an array
|
||||
func ArrToTree(arr []any) *TreeNode {
|
||||
if len(arr) <= 0 {
|
||||
return nil
|
||||
}
|
||||
root := NewTreeNode(arr[0])
|
||||
// TreeNode only accept integer value for now.
|
||||
root := NewTreeNode(arr[0].(int))
|
||||
// Let container.list as queue
|
||||
queue := list.New()
|
||||
queue.PushBack(root)
|
||||
i := 1
|
||||
i := 0
|
||||
for queue.Len() > 0 {
|
||||
// poll
|
||||
node := queue.Remove(queue.Front()).(*TreeNode)
|
||||
i++
|
||||
if i < len(arr) {
|
||||
node.Left = NewTreeNode(arr[i])
|
||||
queue.PushBack(node.Left)
|
||||
i++
|
||||
if arr[i] != nil {
|
||||
node.Left = NewTreeNode(arr[i].(int))
|
||||
queue.PushBack(node.Left)
|
||||
}
|
||||
}
|
||||
i++
|
||||
if i < len(arr) {
|
||||
node.Right = NewTreeNode(arr[i])
|
||||
queue.PushBack(node.Right)
|
||||
i++
|
||||
if arr[i] != nil {
|
||||
node.Right = NewTreeNode(arr[i].(int))
|
||||
queue.PushBack(node.Right)
|
||||
}
|
||||
}
|
||||
}
|
||||
return root
|
||||
|
|
|
@ -10,8 +10,8 @@ import (
|
|||
)
|
||||
|
||||
func TestTreeNode(t *testing.T) {
|
||||
arr := []int{2, 3, 5, 6, 7}
|
||||
node := ArrayToTree(arr)
|
||||
arr := []any{1, 2, 3, nil, 5, 6, nil}
|
||||
node := ArrToTree(arr)
|
||||
|
||||
// print tree
|
||||
PrintTree(node)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: array.java
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: linked_list.java
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
@ -29,9 +29,9 @@ public class linked_list {
|
|||
/* 访问链表中索引为 index 的结点 */
|
||||
static ListNode access(ListNode head, int index) {
|
||||
for (int i = 0; i < index; i++) {
|
||||
head = head.next;
|
||||
if (head == null)
|
||||
return null;
|
||||
head = head.next;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: list.java
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: my_list.java
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: leetcode_two_sum.java
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: space_complexity.java
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: time_complexity.java
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: worst_best_time_complexity.java
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: hash_map.java
|
||||
* Created Time: 2022-12-04
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: hash_map.java
|
||||
* Created Time: 2022-12-04
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: binary_search.java
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: hashing_search.java
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: linear_search.java
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: bubble_sort.java
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* File: insertion_sort.java
|
||||
* Created Time: 2022-11-25
|
||||
* Author: Krahets (krahets@163.com)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue