mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-17 22:10:59 +00:00
feat: Traditional Chinese version (#1163)
* First commit * Update mkdocs.yml * Translate all the docs to traditional Chinese * Translate the code files. * Translate the docker file * Fix mkdocs.yml * Translate all the figures from SC to TC * 二叉搜尋樹 -> 二元搜尋樹 * Update terminology. * Update terminology * 构造函数/构造方法 -> 建構子 异或 -> 互斥或 * 擴充套件 -> 擴展 * constant - 常量 - 常數 * 類 -> 類別 * AVL -> AVL 樹 * 數組 -> 陣列 * 係統 -> 系統 斐波那契數列 -> 費波那契數列 運算元量 -> 運算量 引數 -> 參數 * 聯絡 -> 關聯 * 麵試 -> 面試 * 面向物件 -> 物件導向 歸併排序 -> 合併排序 范式 -> 範式 * Fix 算法 -> 演算法 * 錶示 -> 表示 反碼 -> 一補數 補碼 -> 二補數 列列尾部 -> 佇列尾部 區域性性 -> 區域性 一摞 -> 一疊 * Synchronize with main branch * 賬號 -> 帳號 推匯 -> 推導 * Sync with main branch * First commit * Update mkdocs.yml * Translate all the docs to traditional Chinese * Translate the code files. * Translate the docker file * Fix mkdocs.yml * Translate all the figures from SC to TC * 二叉搜尋樹 -> 二元搜尋樹 * Update terminology * 构造函数/构造方法 -> 建構子 异或 -> 互斥或 * 擴充套件 -> 擴展 * constant - 常量 - 常數 * 類 -> 類別 * AVL -> AVL 樹 * 數組 -> 陣列 * 係統 -> 系統 斐波那契數列 -> 費波那契數列 運算元量 -> 運算量 引數 -> 參數 * 聯絡 -> 關聯 * 麵試 -> 面試 * 面向物件 -> 物件導向 歸併排序 -> 合併排序 范式 -> 範式 * Fix 算法 -> 演算法 * 錶示 -> 表示 反碼 -> 一補數 補碼 -> 二補數 列列尾部 -> 佇列尾部 區域性性 -> 區域性 一摞 -> 一疊 * Synchronize with main branch * 賬號 -> 帳號 推匯 -> 推導 * Sync with main branch * Update terminology.md * 操作数量(num. of operations)-> 操作數量 * 字首和->前綴和 * Update figures * 歸 -> 迴 記憶體洩漏 -> 記憶體流失 * Fix the bug of the file filter * 支援 -> 支持 Add zh-Hant/README.md * Add the zh-Hant chapter covers. Bug fixes. * 外掛 -> 擴充功能 * Add the landing page for zh-Hant version * Unify the font of the chapter covers for the zh, en, and zh-Hant version * Move zh-Hant/ to zh-hant/ * Translate terminology.md to traditional Chinese
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
// File: bubble_sort.zig
|
||||
// Created Time: 2023-01-08
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// 泡沫排序
|
||||
fn bubbleSort(nums: []i32) void {
|
||||
// 外迴圈:未排序區間為 [0, i]
|
||||
var i: usize = nums.len - 1;
|
||||
while (i > 0) : (i -= 1) {
|
||||
var j: usize = 0;
|
||||
// 內迴圈:將未排序區間 [0, i] 中的最大元素交換至該區間的最右端
|
||||
while (j < i) : (j += 1) {
|
||||
if (nums[j] > nums[j + 1]) {
|
||||
// 交換 nums[j] 與 nums[j + 1]
|
||||
var tmp = nums[j];
|
||||
nums[j] = nums[j + 1];
|
||||
nums[j + 1] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 泡沫排序(標誌最佳化)
|
||||
fn bubbleSortWithFlag(nums: []i32) void {
|
||||
// 外迴圈:未排序區間為 [0, i]
|
||||
var i: usize = nums.len - 1;
|
||||
while (i > 0) : (i -= 1) {
|
||||
var flag = false; // 初始化標誌位
|
||||
var j: usize = 0;
|
||||
// 內迴圈:將未排序區間 [0, i] 中的最大元素交換至該區間的最右端
|
||||
while (j < i) : (j += 1) {
|
||||
if (nums[j] > nums[j + 1]) {
|
||||
// 交換 nums[j] 與 nums[j + 1]
|
||||
var tmp = nums[j];
|
||||
nums[j] = nums[j + 1];
|
||||
nums[j + 1] = tmp;
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
if (!flag) break; // 此輪“冒泡”未交換任何元素,直接跳出
|
||||
}
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
var nums = [_]i32{ 4, 1, 3, 1, 5, 2 };
|
||||
bubbleSort(&nums);
|
||||
std.debug.print("泡沫排序完成後 nums = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums);
|
||||
|
||||
var nums1 = [_]i32{ 4, 1, 3, 1, 5, 2 };
|
||||
bubbleSortWithFlag(&nums1);
|
||||
std.debug.print("\n泡沫排序完成後 nums1 = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums1);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// File: insertion_sort.zig
|
||||
// Created Time: 2023-01-08
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// 插入排序
|
||||
fn insertionSort(nums: []i32) void {
|
||||
// 外迴圈:已排序區間為 [0, i-1]
|
||||
var i: usize = 1;
|
||||
while (i < nums.len) : (i += 1) {
|
||||
var base = nums[i];
|
||||
var j: usize = i;
|
||||
// 內迴圈:將 base 插入到已排序區間 [0, i-1] 中的正確位置
|
||||
while (j >= 1 and nums[j - 1] > base) : (j -= 1) {
|
||||
nums[j] = nums[j - 1]; // 將 nums[j] 向右移動一位
|
||||
}
|
||||
nums[j] = base; // 將 base 賦值到正確位置
|
||||
}
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
var nums = [_]i32{ 4, 1, 3, 1, 5, 2 };
|
||||
insertionSort(&nums);
|
||||
std.debug.print("插入排序完成後 nums = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// File: merge_sort.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// 合併左子陣列和右子陣列
|
||||
// 左子陣列區間 [left, mid]
|
||||
// 右子陣列區間 [mid + 1, right]
|
||||
fn merge(nums: []i32, left: usize, mid: usize, right: usize) !void {
|
||||
// 初始化輔助陣列
|
||||
var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer mem_arena.deinit();
|
||||
const mem_allocator = mem_arena.allocator();
|
||||
var tmp = try mem_allocator.alloc(i32, right + 1 - left);
|
||||
std.mem.copy(i32, tmp, nums[left..right+1]);
|
||||
// 左子陣列的起始索引和結束索引
|
||||
var leftStart = left - left;
|
||||
var leftEnd = mid - left;
|
||||
// 右子陣列的起始索引和結束索引
|
||||
var rightStart = mid + 1 - left;
|
||||
var rightEnd = right - left;
|
||||
// i, j 分別指向左子陣列、右子陣列的首元素
|
||||
var i = leftStart;
|
||||
var j = rightStart;
|
||||
// 透過覆蓋原陣列 nums 來合併左子陣列和右子陣列
|
||||
var k = left;
|
||||
while (k <= right) : (k += 1) {
|
||||
// 若“左子陣列已全部合併完”,則選取右子陣列元素,並且 j++
|
||||
if (i > leftEnd) {
|
||||
nums[k] = tmp[j];
|
||||
j += 1;
|
||||
// 否則,若“右子陣列已全部合併完”或“左子陣列元素 <= 右子陣列元素”,則選取左子陣列元素,並且 i++
|
||||
} else if (j > rightEnd or tmp[i] <= tmp[j]) {
|
||||
nums[k] = tmp[i];
|
||||
i += 1;
|
||||
// 否則,若“左右子陣列都未全部合併完”且“左子陣列元素 > 右子陣列元素”,則選取右子陣列元素,並且 j++
|
||||
} else {
|
||||
nums[k] = tmp[j];
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 合併排序
|
||||
fn mergeSort(nums: []i32, left: usize, right: usize) !void {
|
||||
// 終止條件
|
||||
if (left >= right) return; // 當子陣列長度為 1 時終止遞迴
|
||||
// 劃分階段
|
||||
var mid = (left + right) / 2; // 計算中點
|
||||
try mergeSort(nums, left, mid); // 遞迴左子陣列
|
||||
try mergeSort(nums, mid + 1, right); // 遞迴右子陣列
|
||||
// 合併階段
|
||||
try merge(nums, left, mid, right);
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// 合併排序
|
||||
var nums = [_]i32{ 7, 3, 2, 6, 0, 1, 5, 4 };
|
||||
try mergeSort(&nums, 0, nums.len - 1);
|
||||
std.debug.print("合併排序完成後 nums = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
// File: quick_sort.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// 快速排序類別
|
||||
const QuickSort = struct {
|
||||
|
||||
// 元素交換
|
||||
pub fn swap(nums: []i32, i: usize, j: usize) void {
|
||||
var tmp = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = tmp;
|
||||
}
|
||||
|
||||
// 哨兵劃分
|
||||
pub fn partition(nums: []i32, left: usize, right: usize) usize {
|
||||
// 以 nums[left] 為基準數
|
||||
var i = left;
|
||||
var j = right;
|
||||
while (i < j) {
|
||||
while (i < j and nums[j] >= nums[left]) j -= 1; // 從右向左找首個小於基準數的元素
|
||||
while (i < j and nums[i] <= nums[left]) i += 1; // 從左向右找首個大於基準數的元素
|
||||
swap(nums, i, j); // 交換這兩個元素
|
||||
}
|
||||
swap(nums, i, left); // 將基準數交換至兩子陣列的分界線
|
||||
return i; // 返回基準數的索引
|
||||
}
|
||||
|
||||
// 快速排序
|
||||
pub fn quickSort(nums: []i32, left: usize, right: usize) void {
|
||||
// 子陣列長度為 1 時終止遞迴
|
||||
if (left >= right) return;
|
||||
// 哨兵劃分
|
||||
var pivot = partition(nums, left, right);
|
||||
// 遞迴左子陣列、右子陣列
|
||||
quickSort(nums, left, pivot - 1);
|
||||
quickSort(nums, pivot + 1, right);
|
||||
}
|
||||
};
|
||||
|
||||
// 快速排序類別(中位基準數最佳化)
|
||||
const QuickSortMedian = struct {
|
||||
|
||||
// 元素交換
|
||||
pub fn swap(nums: []i32, i: usize, j: usize) void {
|
||||
var tmp = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = tmp;
|
||||
}
|
||||
|
||||
// 選取三個候選元素的中位數
|
||||
pub fn medianThree(nums: []i32, left: usize, mid: usize, right: usize) usize {
|
||||
var l = nums[left];
|
||||
var m = nums[mid];
|
||||
var r = nums[right];
|
||||
if ((l <= m && m <= r) || (r <= m && m <= l))
|
||||
return mid; // m 在 l 和 r 之間
|
||||
if ((m <= l && l <= r) || (r <= l && l <= m))
|
||||
return left; // l 在 m 和 r 之間
|
||||
return right;
|
||||
}
|
||||
|
||||
// 哨兵劃分(三數取中值)
|
||||
pub fn partition(nums: []i32, left: usize, right: usize) usize {
|
||||
// 選取三個候選元素的中位數
|
||||
var med = medianThree(nums, left, (left + right) / 2, right);
|
||||
// 將中位數交換至陣列最左端
|
||||
swap(nums, left, med);
|
||||
// 以 nums[left] 為基準數
|
||||
var i = left;
|
||||
var j = right;
|
||||
while (i < j) {
|
||||
while (i < j and nums[j] >= nums[left]) j -= 1; // 從右向左找首個小於基準數的元素
|
||||
while (i < j and nums[i] <= nums[left]) i += 1; // 從左向右找首個大於基準數的元素
|
||||
swap(nums, i, j); // 交換這兩個元素
|
||||
}
|
||||
swap(nums, i, left); // 將基準數交換至兩子陣列的分界線
|
||||
return i; // 返回基準數的索引
|
||||
}
|
||||
|
||||
// 快速排序
|
||||
pub fn quickSort(nums: []i32, left: usize, right: usize) void {
|
||||
// 子陣列長度為 1 時終止遞迴
|
||||
if (left >= right) return;
|
||||
// 哨兵劃分
|
||||
var pivot = partition(nums, left, right);
|
||||
if (pivot == 0) return;
|
||||
// 遞迴左子陣列、右子陣列
|
||||
quickSort(nums, left, pivot - 1);
|
||||
quickSort(nums, pivot + 1, right);
|
||||
}
|
||||
};
|
||||
|
||||
// 快速排序類別(尾遞迴最佳化)
|
||||
const QuickSortTailCall = struct {
|
||||
|
||||
// 元素交換
|
||||
pub fn swap(nums: []i32, i: usize, j: usize) void {
|
||||
var tmp = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = tmp;
|
||||
}
|
||||
|
||||
// 哨兵劃分
|
||||
pub fn partition(nums: []i32, left: usize, right: usize) usize {
|
||||
// 以 nums[left] 為基準數
|
||||
var i = left;
|
||||
var j = right;
|
||||
while (i < j) {
|
||||
while (i < j and nums[j] >= nums[left]) j -= 1; // 從右向左找首個小於基準數的元素
|
||||
while (i < j and nums[i] <= nums[left]) i += 1; // 從左向右找首個大於基準數的元素
|
||||
swap(nums, i, j); // 交換這兩個元素
|
||||
}
|
||||
swap(nums, i, left); // 將基準數交換至兩子陣列的分界線
|
||||
return i; // 返回基準數的索引
|
||||
}
|
||||
|
||||
// 快速排序(尾遞迴最佳化)
|
||||
pub fn quickSort(nums: []i32, left_: usize, right_: usize) void {
|
||||
var left = left_;
|
||||
var right = right_;
|
||||
// 子陣列長度為 1 時終止遞迴
|
||||
while (left < right) {
|
||||
// 哨兵劃分操作
|
||||
var pivot = partition(nums, left, right);
|
||||
// 對兩個子陣列中較短的那個執行快速排序
|
||||
if (pivot - left < right - pivot) {
|
||||
quickSort(nums, left, pivot - 1); // 遞迴排序左子陣列
|
||||
left = pivot + 1; // 剩餘未排序區間為 [pivot + 1, right]
|
||||
} else {
|
||||
quickSort(nums, pivot + 1, right); // 遞迴排序右子陣列
|
||||
right = pivot - 1; // 剩餘未排序區間為 [left, pivot - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// 快速排序
|
||||
var nums = [_]i32{ 2, 4, 1, 0, 3, 5 };
|
||||
QuickSort.quickSort(&nums, 0, nums.len - 1);
|
||||
std.debug.print("快速排序完成後 nums = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums);
|
||||
|
||||
// 快速排序(中位基準數最佳化)
|
||||
var nums1 = [_]i32{ 2, 4, 1, 0, 3, 5 };
|
||||
QuickSortMedian.quickSort(&nums1, 0, nums1.len - 1);
|
||||
std.debug.print("\n快速排序(中位基準數最佳化)完成後 nums = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums1);
|
||||
|
||||
// 快速排序(尾遞迴最佳化)
|
||||
var nums2 = [_]i32{ 2, 4, 1, 0, 3, 5 };
|
||||
QuickSortTailCall.quickSort(&nums2, 0, nums2.len - 1);
|
||||
std.debug.print("\n快速排序(尾遞迴最佳化)完成後 nums = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums2);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// File: radix_sort.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// 獲取元素 num 的第 k 位,其中 exp = 10^(k-1)
|
||||
fn digit(num: i32, exp: i32) i32 {
|
||||
// 傳入 exp 而非 k 可以避免在此重複執行昂貴的次方計算
|
||||
return @mod(@divFloor(num, exp), 10);
|
||||
}
|
||||
|
||||
// 計數排序(根據 nums 第 k 位排序)
|
||||
fn countingSortDigit(nums: []i32, exp: i32) !void {
|
||||
// 十進位制的位範圍為 0~9 ,因此需要長度為 10 的桶陣列
|
||||
var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
// defer mem_arena.deinit();
|
||||
const mem_allocator = mem_arena.allocator();
|
||||
var counter = try mem_allocator.alloc(usize, 10);
|
||||
@memset(counter, 0);
|
||||
var n = nums.len;
|
||||
// 統計 0~9 各數字的出現次數
|
||||
for (nums) |num| {
|
||||
var d: u32 = @bitCast(digit(num, exp)); // 獲取 nums[i] 第 k 位,記為 d
|
||||
counter[d] += 1; // 統計數字 d 的出現次數
|
||||
}
|
||||
// 求前綴和,將“出現個數”轉換為“陣列索引”
|
||||
var i: usize = 1;
|
||||
while (i < 10) : (i += 1) {
|
||||
counter[i] += counter[i - 1];
|
||||
}
|
||||
// 倒序走訪,根據桶內統計結果,將各元素填入 res
|
||||
var res = try mem_allocator.alloc(i32, n);
|
||||
i = n - 1;
|
||||
while (i >= 0) : (i -= 1) {
|
||||
var d: u32 = @bitCast(digit(nums[i], exp));
|
||||
var j = counter[d] - 1; // 獲取 d 在陣列中的索引 j
|
||||
res[j] = nums[i]; // 將當前元素填入索引 j
|
||||
counter[d] -= 1; // 將 d 的數量減 1
|
||||
if (i == 0) break;
|
||||
}
|
||||
// 使用結果覆蓋原陣列 nums
|
||||
i = 0;
|
||||
while (i < n) : (i += 1) {
|
||||
nums[i] = res[i];
|
||||
}
|
||||
}
|
||||
|
||||
// 基數排序
|
||||
fn radixSort(nums: []i32) !void {
|
||||
// 獲取陣列的最大元素,用於判斷最大位數
|
||||
var m: i32 = std.math.minInt(i32);
|
||||
for (nums) |num| {
|
||||
if (num > m) m = num;
|
||||
}
|
||||
// 按照從低位到高位的順序走訪
|
||||
var exp: i32 = 1;
|
||||
while (exp <= m) : (exp *= 10) {
|
||||
// 對陣列元素的第 k 位執行計數排序
|
||||
// k = 1 -> exp = 1
|
||||
// k = 2 -> exp = 10
|
||||
// 即 exp = 10^(k-1)
|
||||
try countingSortDigit(nums, exp);
|
||||
}
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// 基數排序
|
||||
var nums = [_]i32{ 23, 12, 3, 4, 788, 192 };
|
||||
try radixSort(&nums);
|
||||
std.debug.print("基數排序完成後 nums = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
Reference in New Issue
Block a user