diff --git a/codes/csharp/chapter_searching/binary_search_edge.cs b/codes/csharp/chapter_searching/binary_search_edge.cs new file mode 100644 index 000000000..081cc6a11 --- /dev/null +++ b/codes/csharp/chapter_searching/binary_search_edge.cs @@ -0,0 +1,57 @@ +/** +* File: binary_search_edge.cs +* Created Time: 2023-06-01 +* Author: hpstory (hpstory1024@163.com) +*/ + +namespace hello_algo.chapter_searching; + +public class binary_search_edge { + /* 二分查找最左一个元素 */ + public static int binarySearchLeftEdge(int[] nums, int target) { + int i = 0, j = nums.Length - 1; // 初始化双闭区间 [0, n-1] + while (i <= j) { + int m = i + (j - i) / 2; // 计算中点索引 m + if (nums[m] < target) + i = m + 1; // target 在区间 [m+1, j] 中 + else if (nums[m] > target) + j = m - 1; // target 在区间 [i, m-1] 中 + else + j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中 + } + if (i == nums.Length || nums[i] != target) + return -1; // 未找到目标元素,返回 -1 + return i; + } + + /* 二分查找最右一个元素 */ + public static int binarySearchRightEdge(int[] nums, int target) { + int i = 0, j = nums.Length - 1; // 初始化双闭区间 [0, n-1] + while (i <= j) { + int m = i + (j - i) / 2; // 计算中点索引 m + if (nums[m] < target) + i = m + 1; // target 在区间 [m+1, j] 中 + else if (nums[m] > target) + j = m - 1; // target 在区间 [i, m-1] 中 + else + i = m + 1; // 首个大于 target 的元素在区间 [m+1, j] 中 + } + if (j < 0 || nums[j] != target) + return -1; // 未找到目标元素,返回 -1 + return j; + } + + [Test] + public void Test() { + int target = 6; + int[] nums = { 1, 3, 6, 6, 6, 6, 6, 10, 12, 15 }; + + // 二分查找最左一个元素 + int indexLeft = binarySearchLeftEdge(nums, target); + Console.WriteLine("数组中最左一个元素 6 的索引 = " + indexLeft); + + // 二分查找最右一个元素 + int indexRight = binarySearchRightEdge(nums, target); + Console.WriteLine("数组中最右一个元素 6 的索引 = " + indexRight); + } +} diff --git a/codes/csharp/chapter_sorting/heap_sort.cs b/codes/csharp/chapter_sorting/heap_sort.cs new file mode 100644 index 000000000..d6074faeb --- /dev/null +++ b/codes/csharp/chapter_sorting/heap_sort.cs @@ -0,0 +1,52 @@ +/** +* File: heap_sort.cs +* Created Time: 2023-06-01 +* Author: hpstory (hpstory1024@163.com) +*/ + +namespace hello_algo.chapter_sorting; + +public class heap_sort { + /* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */ + public static void siftDown(int[] nums, int n, int i) { + while (true) { + // 判断节点 i, l, r 中值最大的节点,记为 ma + int l = 2 * i + 1; + int r = 2 * i + 2; + int ma = i; + if (l < n && nums[l] > nums[ma]) + ma = l; + if (r < n && nums[r] > nums[ma]) + ma = r; + // 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出 + if (ma == i) + break; + // 交换两节点 + (nums[ma], nums[i]) = (nums[i], nums[ma]); + // 循环向下堆化 + i = ma; + } + } + + /* 堆排序 */ + public static void heapSort(int[] nums) { + // 建堆操作:堆化除叶节点以外的其他所有节点 + for (int i = nums.Length / 2 - 1; i >= 0; i--) { + siftDown(nums, nums.Length, i); + } + // 从堆中提取最大元素,循环 n-1 轮 + for (int i = nums.Length - 1; i > 0; i--) { + // 交换根节点与最右叶节点(即交换首元素与尾元素) + (nums[i], nums[0]) = (nums[0], nums[i]); + // 以根节点为起点,从顶至底进行堆化 + siftDown(nums, i, 0); + } + } + + [Test] + public void Test() { + int[] nums = { 4, 1, 3, 1, 5, 2 }; + heapSort(nums); + Console.WriteLine("堆排序完成后 nums = " + string.Join(" ", nums)); + } +} diff --git a/codes/csharp/chapter_sorting/selection_sort.cs b/codes/csharp/chapter_sorting/selection_sort.cs new file mode 100644 index 000000000..42550494b --- /dev/null +++ b/codes/csharp/chapter_sorting/selection_sort.cs @@ -0,0 +1,32 @@ +/** +* File: selection_sort.cs +* Created Time: 2023-06-01 +* Author: hpstory (hpstory1024@163.com) +*/ + +namespace hello_algo.chapter_sorting; + +public class selection_sort { + /* 选择排序 */ + public static void selectionSort(int[] nums) { + int n = nums.Length; + // 外循环:未排序区间为 [i, n-1] + for (int i = 0; i < n - 1; i++) { + // 内循环:找到未排序区间内的最小元素 + int k = i; + for (int j = i + 1; j < n; j++) { + if (nums[j] < nums[k]) + k = j; // 记录最小元素的索引 + } + // 将该最小元素与未排序区间的首个元素交换 + (nums[k], nums[i]) = (nums[i], nums[k]); + } + } + + [Test] + public void Test() { + int[] nums = { 4, 1, 3, 1, 5, 2 }; + selectionSort(nums); + Console.WriteLine("选择排序完成后 nums = " + string.Join(" ", nums)); + } +}