diff --git a/codes/cpp/chapter_stack_and_queue/array_queue.cpp b/codes/cpp/chapter_stack_and_queue/array_queue.cpp index 8e92c620f..696967f15 100644 --- a/codes/cpp/chapter_stack_and_queue/array_queue.cpp +++ b/codes/cpp/chapter_stack_and_queue/array_queue.cpp @@ -72,11 +72,10 @@ public: /* 将数组转化为 Vector 并返回 */ vector toVector() { - int cap = queCapacity; // 仅转换有效长度范围内的列表元素 vector arr(queSize); for (int i = 0, j = front; i < queSize; i++, j++) { - arr[i] = nums[j % cap]; + arr[i] = nums[j % queCapacity]; } return arr; } diff --git a/codes/csharp/chapter_array_and_linkedlist/array.cs b/codes/csharp/chapter_array_and_linkedlist/array.cs index 922219655..25b2afc7f 100644 --- a/codes/csharp/chapter_array_and_linkedlist/array.cs +++ b/codes/csharp/chapter_array_and_linkedlist/array.cs @@ -4,122 +4,121 @@ using NUnit.Framework; -namespace hello_algo.chapter_array_and_linkedlist +namespace hello_algo.chapter_array_and_linkedlist; + +public class array { - public class Array + /* 随机返回一个数组元素 */ + public static int randomAccess(int[] nums) { - /* 随机返回一个数组元素 */ - public static int RandomAccess(int[] nums) + Random random = new(); + // 在区间 [0, nums.Length) 中随机抽取一个数字 + int randomIndex = random.Next(nums.Length); + // 获取并返回随机元素 + int randomNum = nums[randomIndex]; + return randomNum; + } + + /* 扩展数组长度 */ + public static int[] extend(int[] nums, int enlarge) + { + // 初始化一个扩展长度后的数组 + int[] res = new int[nums.Length + enlarge]; + // 将原数组中的所有元素复制到新数组 + for (int i = 0; i < nums.Length; i++) { - Random random=new(); - // 在区间 [0, nums.Length) 中随机抽取一个数字 - int randomIndex = random.Next(nums.Length); - // 获取并返回随机元素 - int randomNum = nums[randomIndex]; - return randomNum; + res[i] = nums[i]; } + // 返回扩展后的新数组 + return res; + } - /* 扩展数组长度 */ - public static int[] Extend(int[] nums, int enlarge) + /* 在数组的索引 index 处插入元素 num */ + public static void insert(int[] nums, int num, int index) + { + // 把索引 index 以及之后的所有元素向后移动一位 + for (int i = nums.Length - 1; i > index; i--) { - // 初始化一个扩展长度后的数组 - int[] res = new int[nums.Length + enlarge]; - // 将原数组中的所有元素复制到新数组 - for (int i = 0; i < nums.Length; i++) - { - res[i] = nums[i]; - } - // 返回扩展后的新数组 - return res; + nums[i] = nums[i - 1]; } + // 将 num 赋给 index 处元素 + nums[index] = num; + } - /* 在数组的索引 index 处插入元素 num */ - public static void Insert(int[] nums, int num, int index) + /* 删除索引 index 处元素 */ + public static void remove(int[] nums, int index) + { + // 把索引 index 之后的所有元素向前移动一位 + for (int i = index; i < nums.Length - 1; i++) { - // 把索引 index 以及之后的所有元素向后移动一位 - for (int i = nums.Length - 1; i > index; i--) - { - nums[i] = nums[i - 1]; - } - // 将 num 赋给 index 处元素 - nums[index] = num; - } - - /* 删除索引 index 处元素 */ - public static void Remove(int[] nums, int index) - { - // 把索引 index 之后的所有元素向前移动一位 - for (int i = index; i < nums.Length - 1; i++) - { - nums[i] = nums[i + 1]; - } - } - - /* 遍历数组 */ - public static void Traverse(int[] nums) - { - int count = 0; - // 通过索引遍历数组 - for (int i = 0; i < nums.Length; i++) - { - count++; - } - // 直接遍历数组 - foreach (int num in nums) - { - count++; - } - } - - /* 在数组中查找指定元素 */ - public static int Find(int[] nums, int target) - { - for (int i = 0; i < nums.Length; i++) - { - if (nums[i] == target) - return i; - } - return -1; - } - - /* 辅助函数,数组转字符串 */ - public static string ToString(int[] nums) - { - return string.Join(",", nums); - } - - - [Test] - public static void Test() - { - // 初始化数组 - int[] arr = new int[5]; - Console.WriteLine("数组 arr = " + ToString(arr)); - int[] nums = { 1, 3, 2, 5, 4 }; - Console.WriteLine("数组 nums = " + ToString(nums)); - - // 随机访问 - int randomNum = RandomAccess(nums); - Console.WriteLine("在 nums 中获取随机元素 " + randomNum); - - // 长度扩展 - nums = Extend(nums, 3); - Console.WriteLine("将数组长度扩展至 8 ,得到 nums = " + ToString(nums)); - - // 插入元素 - Insert(nums, 6, 3); - Console.WriteLine("在索引 3 处插入数字 6 ,得到 nums = " + ToString(nums)); - - // 删除元素 - Remove(nums, 2); - Console.WriteLine("删除索引 2 处的元素,得到 nums = " + ToString(nums)); - - // 遍历数组 - Traverse(nums); - - // 查找元素 - int index = Find(nums, 3); - Console.WriteLine("在 nums 中查找元素 3 ,得到索引 = " + index); + nums[i] = nums[i + 1]; } } + + /* 遍历数组 */ + public static void traverse(int[] nums) + { + int count = 0; + // 通过索引遍历数组 + for (int i = 0; i < nums.Length; i++) + { + count++; + } + // 直接遍历数组 + foreach (int num in nums) + { + count++; + } + } + + /* 在数组中查找指定元素 */ + public static int find(int[] nums, int target) + { + for (int i = 0; i < nums.Length; i++) + { + if (nums[i] == target) + return i; + } + return -1; + } + + /* 辅助函数,数组转字符串 */ + public static string toString(int[] nums) + { + return string.Join(",", nums); + } + + + [Test] + public static void Test() + { + // 初始化数组 + int[] arr = new int[5]; + Console.WriteLine("数组 arr = " + toString(arr)); + int[] nums = { 1, 3, 2, 5, 4 }; + Console.WriteLine("数组 nums = " + toString(nums)); + + // 随机访问 + int randomNum = randomAccess(nums); + Console.WriteLine("在 nums 中获取随机元素 " + randomNum); + + // 长度扩展 + nums = extend(nums, 3); + Console.WriteLine("将数组长度扩展至 8 ,得到 nums = " + toString(nums)); + + // 插入元素 + insert(nums, 6, 3); + Console.WriteLine("在索引 3 处插入数字 6 ,得到 nums = " + toString(nums)); + + // 删除元素 + remove(nums, 2); + Console.WriteLine("删除索引 2 处的元素,得到 nums = " + toString(nums)); + + // 遍历数组 + traverse(nums); + + // 查找元素 + int index = find(nums, 3); + Console.WriteLine("在 nums 中查找元素 3 ,得到索引 = " + index); + } } diff --git a/codes/csharp/chapter_array_and_linkedlist/linked_list.cs b/codes/csharp/chapter_array_and_linkedlist/linked_list.cs index 81e1499cb..68e0d4671 100644 --- a/codes/csharp/chapter_array_and_linkedlist/linked_list.cs +++ b/codes/csharp/chapter_array_and_linkedlist/linked_list.cs @@ -5,88 +5,87 @@ using hello_algo.include; using NUnit.Framework; -namespace hello_algo.chapter_array_and_linkedlist +namespace hello_algo.chapter_array_and_linkedlist; + +public class linked_list { - public class linked_list + /* 在链表的结点 n0 之后插入结点 P */ + public static void insert(ListNode n0, ListNode P) { - /* 在链表的结点 n0 之后插入结点 P */ - public static void Insert(ListNode n0, ListNode P) + ListNode? n1 = n0.next; + n0.next = P; + P.next = n1; + } + + /* 删除链表的结点 n0 之后的首个结点 */ + public static void remove(ListNode n0) + { + if (n0.next == null) + return; + // n0 -> P -> n1 + ListNode P = n0.next; + ListNode? n1 = P.next; + n0.next = n1; + } + + /* 访问链表中索引为 index 的结点 */ + public static ListNode? access(ListNode head, int index) + { + for (int i = 0; i < index; i++) { - ListNode? n1 = n0.next; - n0.next = P; - P.next = n1; + if (head == null) + return null; + head = head.next; } + return head; + } - /* 删除链表的结点 n0 之后的首个结点 */ - public static void Remove(ListNode n0) + /* 在链表中查找值为 target 的首个结点 */ + public static int find(ListNode head, int target) + { + int index = 0; + while (head != null) { - if (n0.next == null) - return; - // n0 -> P -> n1 - ListNode P = n0.next; - ListNode? n1 = P.next; - n0.next = n1; - } - - /* 访问链表中索引为 index 的结点 */ - public static ListNode? Access(ListNode head, int index) - { - for (int i = 0; i < index; i++) - { - if (head == null) - return null; - head = head.next; - } - return head; - } - - /* 在链表中查找值为 target 的首个结点 */ - public static int Find(ListNode head, int target) - { - int index = 0; - while (head != null) - { - if (head.val == target) - return index; - head = head.next; - index++; - } - return -1; + if (head.val == target) + return index; + head = head.next; + index++; } + return -1; + } - [Test] - public void Test() - { - // 初始化链表 - // 初始化各个结点 - ListNode n0 = new ListNode(1); - ListNode n1 = new ListNode(3); - ListNode n2 = new ListNode(2); - ListNode n3 = new ListNode(5); - ListNode n4 = new ListNode(4); - // 构建引用指向 - n0.next = n1; - n1.next = n2; - n2.next = n3; - n3.next = n4; - Console.WriteLine($"初始化的链表为{n0}"); + [Test] + public void Test() + { + // 初始化链表 + // 初始化各个结点 + ListNode n0 = new ListNode(1); + ListNode n1 = new ListNode(3); + ListNode n2 = new ListNode(2); + ListNode n3 = new ListNode(5); + ListNode n4 = new ListNode(4); + // 构建引用指向 + n0.next = n1; + n1.next = n2; + n2.next = n3; + n3.next = n4; + Console.WriteLine($"初始化的链表为{n0}"); - // 插入结点 - Insert(n0, new ListNode(0)); - Console.WriteLine($"插入结点后的链表为{n0}"); + // 插入结点 + insert(n0, new ListNode(0)); + Console.WriteLine($"插入结点后的链表为{n0}"); - // 删除结点 - Remove(n0); - Console.WriteLine($"删除结点后的链表为{n0}"); + // 删除结点 + remove(n0); + Console.WriteLine($"删除结点后的链表为{n0}"); - // 访问结点 - ListNode? node = Access(n0, 3); - Console.WriteLine($"链表中索引 3 处的结点的值 = {node?.val}"); + // 访问结点 + ListNode? node = access(n0, 3); + Console.WriteLine($"链表中索引 3 处的结点的值 = {node?.val}"); - // 查找结点 - int index = Find(n0, 2); - Console.WriteLine($"链表中值为 2 的结点的索引 = {index}"); - } + // 查找结点 + int index = find(n0, 2); + Console.WriteLine($"链表中值为 2 的结点的索引 = {index}"); } } diff --git a/codes/csharp/chapter_array_and_linkedlist/list.cs b/codes/csharp/chapter_array_and_linkedlist/list.cs index 4f702163f..51915618d 100644 --- a/codes/csharp/chapter_array_and_linkedlist/list.cs +++ b/codes/csharp/chapter_array_and_linkedlist/list.cs @@ -6,70 +6,69 @@ using NUnit.Framework; -namespace hello_algo.chapter_array_and_linkedlist +namespace hello_algo.chapter_array_and_linkedlist; + +public class list { - public class list + [Test] + public void Test() { - [Test] - public void Test() + + /* 初始化列表 */ + // 注意数组的元素类型是 int[] 的包装类 int[] + int[] numbers = new int[] { 1, 3, 2, 5, 4 }; + List list = numbers.ToList(); + Console.WriteLine("列表 list = " + string.Join(",", list)); + + /* 访问元素 */ + int num = list[1]; + Console.WriteLine("访问索引 1 处的元素,得到 num = " + num); + + /* 更新元素 */ + list[1] = 0; + Console.WriteLine("将索引 1 处的元素更新为 0 ,得到 list = " + string.Join(",", list)); + + /* 清空列表 */ + list.Clear(); + Console.WriteLine("清空列表后 list = " + string.Join(",", list)); + + /* 尾部添加元素 */ + list.Add(1); + list.Add(3); + list.Add(2); + list.Add(5); + list.Add(4); + Console.WriteLine("添加元素后 list = " + string.Join(",", list)); + + /* 中间插入元素 */ + list.Insert(3, 6); + Console.WriteLine("在索引 3 处插入数字 6 ,得到 list = " + string.Join(",", list)); + + /* 删除元素 */ + list.RemoveAt(3); + Console.WriteLine("删除索引 3 处的元素,得到 list = " + string.Join(",", list)); + + /* 通过索引遍历列表 */ + int count = 0; + for (int i = 0; i < list.Count(); i++) { - - /* 初始化列表 */ - // 注意数组的元素类型是 int[] 的包装类 int[] - int[] numbers = new int[] { 1, 3, 2, 5, 4 }; - List list = numbers.ToList(); - Console.WriteLine("列表 list = " + string.Join(",",list)); - - /* 访问元素 */ - int num = list[1]; - Console.WriteLine("访问索引 1 处的元素,得到 num = " + num); - - /* 更新元素 */ - list[1] = 0; - Console.WriteLine("将索引 1 处的元素更新为 0 ,得到 list = " + string.Join(",", list)); - - /* 清空列表 */ - list.Clear(); - Console.WriteLine("清空列表后 list = " + string.Join(",", list)); - - /* 尾部添加元素 */ - list.Add(1); - list.Add(3); - list.Add(2); - list.Add(5); - list.Add(4); - Console.WriteLine("添加元素后 list = " + string.Join(",", list)); - - /* 中间插入元素 */ - list.Insert(3, 6); - Console.WriteLine("在索引 3 处插入数字 6 ,得到 list = " + string.Join(",", list)); - - /* 删除元素 */ - list.RemoveAt(3); - Console.WriteLine("删除索引 3 处的元素,得到 list = " + string.Join(",", list)); - - /* 通过索引遍历列表 */ - int count = 0; - for (int i = 0; i < list.Count(); i++) - { - count++; - } - - /* 直接遍历列表元素 */ - count = 0; - foreach (int n in list) - { - count++; - } - - /* 拼接两个列表 */ - List list1 = new() { 6, 8, 7, 10, 9 }; - list.AddRange(list1); - Console.WriteLine("将列表 list1 拼接到 list 之后,得到 list = " + string.Join(",", list)); - - /* 排序列表 */ - list.Sort(); // 排序后,列表元素从小到大排列 - Console.WriteLine("排序列表后 list = " + string.Join(",", list)); + count++; } + + /* 直接遍历列表元素 */ + count = 0; + foreach (int n in list) + { + count++; + } + + /* 拼接两个列表 */ + List list1 = new() { 6, 8, 7, 10, 9 }; + list.AddRange(list1); + Console.WriteLine("将列表 list1 拼接到 list 之后,得到 list = " + string.Join(",", list)); + + /* 排序列表 */ + list.Sort(); // 排序后,列表元素从小到大排列 + Console.WriteLine("排序列表后 list = " + string.Join(",", list)); } } diff --git a/codes/csharp/chapter_array_and_linkedlist/my_list.cs b/codes/csharp/chapter_array_and_linkedlist/my_list.cs index 22dd583f6..999e98ee2 100644 --- a/codes/csharp/chapter_array_and_linkedlist/my_list.cs +++ b/codes/csharp/chapter_array_and_linkedlist/my_list.cs @@ -6,159 +6,158 @@ using NUnit.Framework; -namespace hello_algo.chapter_array_and_linkedlist +namespace hello_algo.chapter_array_and_linkedlist; + +/* 列表类简易实现 */ +class MyList { - class MyList + private int[] nums; // 数组(存储列表元素) + private int numsCapacity = 10; // 列表容量 + private int numsSize = 0; // 列表长度(即当前元素数量) + private int extendRatio = 2; // 每次列表扩容的倍数 + + /* 构造函数 */ + public MyList() { - private int[] nums; // 数组(存储列表元素) - private int capacity = 10; // 列表容量 - private int size = 0; // 列表长度(即当前元素数量) - private int extendRatio = 2; // 每次列表扩容的倍数 - - /* 构造函数 */ - public MyList() - { - nums = new int[capacity]; - } - - /* 获取列表长度(即当前元素数量)*/ - public int Size() - { - return size; - } - - /* 获取列表容量 */ - public int Capacity() - { - return capacity; - } - - /* 访问元素 */ - public int Get(int index) - { - // 索引如果越界则抛出异常,下同 - if (index < 0 || index >= size) - throw new IndexOutOfRangeException("索引越界"); - return nums[index]; - } - - /* 更新元素 */ - public void Set(int index, int num) - { - if (index < 0 || index >= size) - throw new IndexOutOfRangeException("索引越界"); - nums[index] = num; - } - - /* 尾部添加元素 */ - public void Add(int num) - { - // 元素数量超出容量时,触发扩容机制 - if (size == Capacity()) - ExtendCapacity(); - nums[size] = num; - // 更新元素数量 - size++; - } - - /* 中间插入元素 */ - public void Insert(int index, int num) - { - if (index < 0 || index >= size) - throw new IndexOutOfRangeException("索引越界"); - // 元素数量超出容量时,触发扩容机制 - if (size == Capacity()) - ExtendCapacity(); - // 将索引 index 以及之后的元素都向后移动一位 - for (int j = size - 1; j >= index; j--) - { - nums[j + 1] = nums[j]; - } - nums[index] = num; - // 更新元素数量 - size++; - } - - /* 删除元素 */ - public int Remove(int index) - { - if (index < 0 || index >= size) - throw new IndexOutOfRangeException("索引越界"); - int num = nums[index]; - // 将索引 index 之后的元素都向前移动一位 - for (int j = index; j < size - 1; j++) - { - nums[j] = nums[j + 1]; - } - // 更新元素数量 - size--; - // 返回被删除元素 - return num; - } - - /* 列表扩容 */ - public void ExtendCapacity() - { - // 新建一个长度为 size 的数组,并将原数组拷贝到新数组 - System.Array.Resize(ref nums, Capacity() * extendRatio); - // 更新列表容量 - capacity = nums.Length; - } - - /* 将列表转换为数组 */ - public int[] ToArray() - { - int size = Size(); - // 仅转换有效长度范围内的列表元素 - int[] nums = new int[size]; - for (int i = 0; i < size; i++) - { - nums[i] = Get(i); - } - return nums; - } + nums = new int[numsCapacity]; } - public class my_list + /* 获取列表长度(即当前元素数量)*/ + public int size() { - [Test] - public void Test() + return numsSize; + } + + /* 获取列表容量 */ + public int capacity() + { + return numsCapacity; + } + + /* 访问元素 */ + public int get(int index) + { + // 索引如果越界则抛出异常,下同 + if (index < 0 || index >= numsSize) + throw new IndexOutOfRangeException("索引越界"); + return nums[index]; + } + + /* 更新元素 */ + public void set(int index, int num) + { + if (index < 0 || index >= numsSize) + throw new IndexOutOfRangeException("索引越界"); + nums[index] = num; + } + + /* 尾部添加元素 */ + public void add(int num) + { + // 元素数量超出容量时,触发扩容机制 + if (numsSize == numsCapacity) + extendCapacity(); + nums[numsSize] = num; + // 更新元素数量 + numsSize++; + } + + /* 中间插入元素 */ + public void insert(int index, int num) + { + if (index < 0 || index >= numsSize) + throw new IndexOutOfRangeException("索引越界"); + // 元素数量超出容量时,触发扩容机制 + if (numsSize == numsCapacity) + extendCapacity(); + // 将索引 index 以及之后的元素都向后移动一位 + for (int j = numsSize - 1; j >= index; j--) { - /* 初始化列表 */ - MyList list = new MyList(); - /* 尾部添加元素 */ - list.Add(1); - list.Add(3); - list.Add(2); - list.Add(5); - list.Add(4); - Console.WriteLine("列表 list = " + string.Join(",", list.ToArray()) + - " ,容量 = " + list.Capacity() + " ,长度 = " + list.Size()); - - /* 中间插入元素 */ - list.Insert(3, 6); - Console.WriteLine("在索引 3 处插入数字 6 ,得到 list = " + string.Join(",", list.ToArray())); - - /* 删除元素 */ - list.Remove(3); - Console.WriteLine("删除索引 3 处的元素,得到 list = " + string.Join(",", list.ToArray())); - - /* 访问元素 */ - int num = list.Get(1); - Console.WriteLine("访问索引 1 处的元素,得到 num = " + num); - - /* 更新元素 */ - list.Set(1, 0); - Console.WriteLine("将索引 1 处的元素更新为 0 ,得到 list = " + string.Join(",", list.ToArray())); - - /* 测试扩容机制 */ - for (int i = 0; i < 10; i++) - { - // 在 i = 5 时,列表长度将超出列表容量,此时触发扩容机制 - list.Add(i); - } - Console.WriteLine("扩容后的列表 list = " + string.Join(",", list.ToArray()) + - " ,容量 = " + list.Capacity() + " ,长度 = " + list.Size()); + nums[j + 1] = nums[j]; } + nums[index] = num; + // 更新元素数量 + numsSize++; + } + + /* 删除元素 */ + public int remove(int index) + { + if (index < 0 || index >= numsSize) + throw new IndexOutOfRangeException("索引越界"); + int num = nums[index]; + // 将索引 index 之后的元素都向前移动一位 + for (int j = index; j < numsSize - 1; j++) + { + nums[j] = nums[j + 1]; + } + // 更新元素数量 + numsSize--; + // 返回被删除元素 + return num; + } + + /* 列表扩容 */ + public void extendCapacity() + { + // 新建一个长度为 numsCapacity * extendRatio 的数组,并将原数组拷贝到新数组 + System.Array.Resize(ref nums, numsCapacity * extendRatio); + // 更新列表容量 + numsCapacity = nums.Length; + } + + /* 将列表转换为数组 */ + public int[] toArray() + { + // 仅转换有效长度范围内的列表元素 + int[] nums = new int[numsSize]; + for (int i = 0; i < numsSize; i++) + { + nums[i] = get(i); + } + return nums; + } +} + +public class my_list +{ + [Test] + public void Test() + { + /* 初始化列表 */ + MyList list = new MyList(); + /* 尾部添加元素 */ + list.add(1); + list.add(3); + list.add(2); + list.add(5); + list.add(4); + Console.WriteLine("列表 list = " + string.Join(",", list.toArray()) + + " ,容量 = " + list.capacity() + " ,长度 = " + list.size()); + + /* 中间插入元素 */ + list.insert(3, 6); + Console.WriteLine("在索引 3 处插入数字 6 ,得到 list = " + string.Join(",", list.toArray())); + + /* 删除元素 */ + list.remove(3); + Console.WriteLine("删除索引 3 处的元素,得到 list = " + string.Join(",", list.toArray())); + + /* 访问元素 */ + int num = list.get(1); + Console.WriteLine("访问索引 1 处的元素,得到 num = " + num); + + /* 更新元素 */ + list.set(1, 0); + Console.WriteLine("将索引 1 处的元素更新为 0 ,得到 list = " + string.Join(",", list.toArray())); + + /* 测试扩容机制 */ + for (int i = 0; i < 10; i++) + { + // 在 i = 5 时,列表长度将超出列表容量,此时触发扩容机制 + list.add(i); + } + Console.WriteLine("扩容后的列表 list = " + string.Join(",", list.toArray()) + + " ,容量 = " + list.capacity() + " ,长度 = " + list.size()); } } diff --git a/codes/csharp/chapter_computational_complexity/leetcode_two_sum.cs b/codes/csharp/chapter_computational_complexity/leetcode_two_sum.cs index 37fe60c04..4d716f971 100644 --- a/codes/csharp/chapter_computational_complexity/leetcode_two_sum.cs +++ b/codes/csharp/chapter_computational_complexity/leetcode_two_sum.cs @@ -6,58 +6,57 @@ using NUnit.Framework; -namespace hello_algo.chapter_computational_complexity +namespace hello_algo.chapter_computational_complexity; + +public class leetcode_two_sum { - public class leetcode_two_sum + /* 方法一:暴力枚举 */ + public static int[] twoSumBruteForce(int[] nums, int target) { - /* 方法一:暴力枚举 */ - public static int[] twoSumBruteForce(int[] nums, int target) + int size = nums.Length; + // 两层循环,时间复杂度 O(n^2) + for (int i = 0; i < size - 1; i++) { - int size = nums.Length; - // 两层循环,时间复杂度 O(n^2) - for (int i = 0; i < size - 1; i++) + for (int j = i + 1; j < size; j++) { - for (int j = i + 1; j < size; j++) - { - if (nums[i] + nums[j] == target) - return new int[] { i, j }; - } + if (nums[i] + nums[j] == target) + return new int[] { i, j }; } - return new int[0]; - } - - /* 方法二:辅助哈希表 */ - public static int[] twoSumHashTable(int[] nums, int target) - { - int size = nums.Length; - // 辅助哈希表,空间复杂度 O(n) - Dictionary dic = new(); - // 单层循环,时间复杂度 O(n) - for (int i = 0; i < size; i++) - { - if (dic.ContainsKey(target - nums[i])) - { - return new int[] { dic[target - nums[i]], i }; - } - dic.Add(nums[i], i); - } - return new int[0]; - } - - [Test] - public void Test() - { - // ======= Test Case ======= - int[] nums = { 2, 7, 11, 15 }; - int target = 9; - - // ====== Driver Code ====== - // 方法一 - int[] res = twoSumBruteForce(nums, target); - Console.WriteLine("方法一 res = " + string.Join(",", res)); - // 方法二 - res = twoSumHashTable(nums, target); - Console.WriteLine("方法二 res = " + string.Join(",", res)); } + return new int[0]; } -} \ No newline at end of file + + /* 方法二:辅助哈希表 */ + public static int[] twoSumHashTable(int[] nums, int target) + { + int size = nums.Length; + // 辅助哈希表,空间复杂度 O(n) + Dictionary dic = new(); + // 单层循环,时间复杂度 O(n) + for (int i = 0; i < size; i++) + { + if (dic.ContainsKey(target - nums[i])) + { + return new int[] { dic[target - nums[i]], i }; + } + dic.Add(nums[i], i); + } + return new int[0]; + } + + [Test] + public void Test() + { + // ======= Test Case ======= + int[] nums = { 2, 7, 11, 15 }; + int target = 9; + + // ====== Driver Code ====== + // 方法一 + int[] res = twoSumBruteForce(nums, target); + Console.WriteLine("方法一 res = " + string.Join(",", res)); + // 方法二 + res = twoSumHashTable(nums, target); + Console.WriteLine("方法二 res = " + string.Join(",", res)); + } +} diff --git a/codes/csharp/chapter_computational_complexity/space_complexity.cs b/codes/csharp/chapter_computational_complexity/space_complexity.cs index c534c81b2..9fbd2aeff 100644 --- a/codes/csharp/chapter_computational_complexity/space_complexity.cs +++ b/codes/csharp/chapter_computational_complexity/space_complexity.cs @@ -7,116 +7,115 @@ using hello_algo.include; using NUnit.Framework; -namespace hello_algo.chapter_computational_complexity +namespace hello_algo.chapter_computational_complexity; + +public class space_complexity { - public class space_complexity + /* 函数 */ + static int function() { - /* 函数 */ - static int function() - { - // do something - return 0; - } + // do something + return 0; + } - /* 常数阶 */ - static void constant(int n) + /* 常数阶 */ + static void constant(int n) + { + // 常量、变量、对象占用 O(1) 空间 + int a = 0; + int b = 0; + int[] nums = new int[10000]; + ListNode node = new ListNode(0); + // 循环中的变量占用 O(1) 空间 + for (int i = 0; i < n; i++) { - // 常量、变量、对象占用 O(1) 空间 - int a = 0; - int b = 0; - int[] nums = new int[10000]; - ListNode node = new ListNode(0); - // 循环中的变量占用 O(1) 空间 - for (int i = 0; i < n; i++) - { - int c = 0; - } - // 循环中的函数占用 O(1) 空间 - for (int i = 0; i < n; i++) - { - function(); - } + int c = 0; } - - /* 线性阶 */ - static void linear(int n) + // 循环中的函数占用 O(1) 空间 + for (int i = 0; i < n; i++) { - // 长度为 n 的数组占用 O(n) 空间 - int[] nums = new int[n]; - // 长度为 n 的列表占用 O(n) 空间 - List nodes = new(); - for (int i = 0; i < n; i++) - { - nodes.Add(new ListNode(i)); - } - // 长度为 n 的哈希表占用 O(n) 空间 - Dictionary map = new(); - for (int i = 0; i < n; i++) - { - map.Add(i, i.ToString()); - } - } - - /* 线性阶(递归实现) */ - static void linearRecur(int n) - { - Console.WriteLine("递归 n = " + n); - if (n == 1) return; - linearRecur(n - 1); - } - - /* 平方阶 */ - static void quadratic(int n) - { - // 矩阵占用 O(n^2) 空间 - int[,] numMatrix = new int[n, n]; - // 二维列表占用 O(n^2) 空间 - List> numList = new(); - for (int i = 0; i < n; i++) - { - List tmp = new(); - for (int j = 0; j < n; j++) - { - tmp.Add(0); - } - numList.Add(tmp); - } - } - - /* 平方阶(递归实现) */ - static int quadraticRecur(int n) - { - if (n <= 0) return 0; - int[] nums = new int[n]; - Console.WriteLine("递归 n = " + n + " 中的 nums 长度 = " + nums.Length); - return quadraticRecur(n - 1); - } - - /* 指数阶(建立满二叉树) */ - static TreeNode? buildTree(int n) - { - if (n == 0) return null; - TreeNode root = new TreeNode(0); - root.left = buildTree(n - 1); - root.right = buildTree(n - 1); - return root; - } - - [Test] - public void Test() - { - int n = 5; - // 常数阶 - constant(n); - // 线性阶 - linear(n); - linearRecur(n); - // 平方阶 - quadratic(n); - quadraticRecur(n); - // 指数阶 - TreeNode? root = buildTree(n); - PrintUtil.PrintTree(root); + function(); } } + + /* 线性阶 */ + static void linear(int n) + { + // 长度为 n 的数组占用 O(n) 空间 + int[] nums = new int[n]; + // 长度为 n 的列表占用 O(n) 空间 + List nodes = new(); + for (int i = 0; i < n; i++) + { + nodes.Add(new ListNode(i)); + } + // 长度为 n 的哈希表占用 O(n) 空间 + Dictionary map = new(); + for (int i = 0; i < n; i++) + { + map.Add(i, i.ToString()); + } + } + + /* 线性阶(递归实现) */ + static void linearRecur(int n) + { + Console.WriteLine("递归 n = " + n); + if (n == 1) return; + linearRecur(n - 1); + } + + /* 平方阶 */ + static void quadratic(int n) + { + // 矩阵占用 O(n^2) 空间 + int[,] numMatrix = new int[n, n]; + // 二维列表占用 O(n^2) 空间 + List> numList = new(); + for (int i = 0; i < n; i++) + { + List tmp = new(); + for (int j = 0; j < n; j++) + { + tmp.Add(0); + } + numList.Add(tmp); + } + } + + /* 平方阶(递归实现) */ + static int quadraticRecur(int n) + { + if (n <= 0) return 0; + int[] nums = new int[n]; + Console.WriteLine("递归 n = " + n + " 中的 nums 长度 = " + nums.Length); + return quadraticRecur(n - 1); + } + + /* 指数阶(建立满二叉树) */ + static TreeNode? buildTree(int n) + { + if (n == 0) return null; + TreeNode root = new TreeNode(0); + root.left = buildTree(n - 1); + root.right = buildTree(n - 1); + return root; + } + + [Test] + public void Test() + { + int n = 5; + // 常数阶 + constant(n); + // 线性阶 + linear(n); + linearRecur(n); + // 平方阶 + quadratic(n); + quadraticRecur(n); + // 指数阶 + TreeNode? root = buildTree(n); + PrintUtil.PrintTree(root); + } } diff --git a/codes/csharp/chapter_computational_complexity/time_complexity.cs b/codes/csharp/chapter_computational_complexity/time_complexity.cs index ac7b405a9..4b33bd921 100644 --- a/codes/csharp/chapter_computational_complexity/time_complexity.cs +++ b/codes/csharp/chapter_computational_complexity/time_complexity.cs @@ -6,227 +6,226 @@ using NUnit.Framework; -namespace hello_algo.chapter_computational_complexity -{ - public class time_complexity - { - void algorithm(int n) - { - int a = 1; // +0(技巧 1) - a = a + n; // +0(技巧 1) - // +n(技巧 2) - for (int i = 0; i < 5 * n + 1; i++) - { - Console.WriteLine(0); - } - // +n*n(技巧 3) - for (int i = 0; i < 2 * n; i++) - { - for (int j = 0; j < n + 1; j++) - { - Console.WriteLine(0); - } - } - } +namespace hello_algo.chapter_computational_complexity; - // 算法 A 时间复杂度:常数阶 - void algorithm_A(int n) +public class time_complexity +{ + void algorithm(int n) + { + int a = 1; // +0(技巧 1) + a = a + n; // +0(技巧 1) + // +n(技巧 2) + for (int i = 0; i < 5 * n + 1; i++) { Console.WriteLine(0); } - // 算法 B 时间复杂度:线性阶 - void algorithm_B(int n) + // +n*n(技巧 3) + for (int i = 0; i < 2 * n; i++) { - for (int i = 0; i < n; i++) + for (int j = 0; j < n + 1; j++) { Console.WriteLine(0); } } - // 算法 C 时间复杂度:常数阶 - void algorithm_C(int n) - { - for (int i = 0; i < 1000000; i++) - { - Console.WriteLine(0); - } - } - - /* 常数阶 */ - static int constant(int n) - { - int count = 0; - int size = 100000; - for (int i = 0; i < size; i++) - count++; - return count; - } - - /* 线性阶 */ - static int linear(int n) - { - int count = 0; - for (int i = 0; i < n; i++) - count++; - return count; - } - - /* 线性阶(遍历数组) */ - static int arrayTraversal(int[] nums) - { - int count = 0; - // 循环次数与数组长度成正比 - foreach (int num in nums) - { - count++; - } - return count; - } - - /* 平方阶 */ - static int quadratic(int n) - { - int count = 0; - // 循环次数与数组长度成平方关系 - for (int i = 0; i < n; i++) - { - for (int j = 0; j < n; j++) - { - count++; - } - } - return count; - } - - /* 平方阶(冒泡排序) */ - static int bubbleSort(int[] nums) - { - int count = 0; // 计数器 - // 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for (int i = nums.Length - 1; i > 0; i--) - { - // 内循环:冒泡操作 - for (int j = 0; j < i; j++) - { - if (nums[j] > nums[j + 1]) - { - // 交换 nums[j] 与 nums[j + 1] - int tmp = nums[j]; - nums[j] = nums[j + 1]; - nums[j + 1] = tmp; - count += 3; // 元素交换包含 3 个单元操作 - } - } - } - return count; - } - - /* 指数阶(循环实现) */ - static int exponential(int n) - { - int count = 0, 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; - } - - /* 指数阶(递归实现) */ - static int expRecur(int n) - { - if (n == 1) return 1; - return expRecur(n - 1) + expRecur(n - 1) + 1; - } - - /* 对数阶(循环实现) */ - static int logarithmic(float n) - { - int count = 0; - while (n > 1) - { - n = n / 2; - count++; - } - return count; - } - - /* 对数阶(递归实现) */ - static int logRecur(float n) - { - if (n <= 1) return 0; - return logRecur(n / 2) + 1; - } - - /* 线性对数阶 */ - static 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; - } - - /* 阶乘阶(递归实现) */ - static int factorialRecur(int n) - { - if (n == 0) return 1; - int count = 0; - // 从 1 个分裂出 n 个 - for (int i = 0; i < n; i++) - { - count += factorialRecur(n - 1); - } - return count; - } - - [Test] - public void Test() - { - // 可以修改 n 运行,体会一下各种复杂度的操作数量变化趋势 - int n = 8; - Console.WriteLine("输入数据大小 n = " + n); - - int count = constant(n); - Console.WriteLine("常数阶的计算操作数量 = " + count); - - count = linear(n); - Console.WriteLine("线性阶的计算操作数量 = " + count); - count = arrayTraversal(new int[n]); - Console.WriteLine("线性阶(遍历数组)的计算操作数量 = " + count); - - count = quadratic(n); - Console.WriteLine("平方阶的计算操作数量 = " + count); - int[] nums = new int[n]; - for (int i = 0; i < n; i++) - nums[i] = n - i; // [n,n-1,...,2,1] - count = bubbleSort(nums); - Console.WriteLine("平方阶(冒泡排序)的计算操作数量 = " + count); - - count = exponential(n); - Console.WriteLine("指数阶(循环实现)的计算操作数量 = " + count); - count = expRecur(n); - Console.WriteLine("指数阶(递归实现)的计算操作数量 = " + count); - - count = logarithmic((float)n); - Console.WriteLine("对数阶(循环实现)的计算操作数量 = " + count); - count = logRecur((float)n); - Console.WriteLine("对数阶(递归实现)的计算操作数量 = " + count); - - count = linearLogRecur((float)n); - Console.WriteLine("线性对数阶(递归实现)的计算操作数量 = " + count); - - count = factorialRecur(n); - Console.WriteLine("阶乘阶(递归实现)的计算操作数量 = " + count); - } + } + + // 算法 A 时间复杂度:常数阶 + void algorithm_A(int n) + { + Console.WriteLine(0); + } + // 算法 B 时间复杂度:线性阶 + void algorithm_B(int n) + { + for (int i = 0; i < n; i++) + { + Console.WriteLine(0); + } + } + // 算法 C 时间复杂度:常数阶 + void algorithm_C(int n) + { + for (int i = 0; i < 1000000; i++) + { + Console.WriteLine(0); + } + } + + /* 常数阶 */ + static int constant(int n) + { + int count = 0; + int size = 100000; + for (int i = 0; i < size; i++) + count++; + return count; + } + + /* 线性阶 */ + static int linear(int n) + { + int count = 0; + for (int i = 0; i < n; i++) + count++; + return count; + } + + /* 线性阶(遍历数组) */ + static int arrayTraversal(int[] nums) + { + int count = 0; + // 循环次数与数组长度成正比 + foreach (int num in nums) + { + count++; + } + return count; + } + + /* 平方阶 */ + static int quadratic(int n) + { + int count = 0; + // 循环次数与数组长度成平方关系 + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + count++; + } + } + return count; + } + + /* 平方阶(冒泡排序) */ + static int bubbleSort(int[] nums) + { + int count = 0; // 计数器 + // 外循环:待排序元素数量为 n-1, n-2, ..., 1 + for (int i = nums.Length - 1; i > 0; i--) + { + // 内循环:冒泡操作 + for (int j = 0; j < i; j++) + { + if (nums[j] > nums[j + 1]) + { + // 交换 nums[j] 与 nums[j + 1] + int tmp = nums[j]; + nums[j] = nums[j + 1]; + nums[j + 1] = tmp; + count += 3; // 元素交换包含 3 个单元操作 + } + } + } + return count; + } + + /* 指数阶(循环实现) */ + static int exponential(int n) + { + int count = 0, 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; + } + + /* 指数阶(递归实现) */ + static int expRecur(int n) + { + if (n == 1) return 1; + return expRecur(n - 1) + expRecur(n - 1) + 1; + } + + /* 对数阶(循环实现) */ + static int logarithmic(float n) + { + int count = 0; + while (n > 1) + { + n = n / 2; + count++; + } + return count; + } + + /* 对数阶(递归实现) */ + static int logRecur(float n) + { + if (n <= 1) return 0; + return logRecur(n / 2) + 1; + } + + /* 线性对数阶 */ + static 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; + } + + /* 阶乘阶(递归实现) */ + static int factorialRecur(int n) + { + if (n == 0) return 1; + int count = 0; + // 从 1 个分裂出 n 个 + for (int i = 0; i < n; i++) + { + count += factorialRecur(n - 1); + } + return count; + } + + [Test] + public void Test() + { + // 可以修改 n 运行,体会一下各种复杂度的操作数量变化趋势 + int n = 8; + Console.WriteLine("输入数据大小 n = " + n); + + int count = constant(n); + Console.WriteLine("常数阶的计算操作数量 = " + count); + + count = linear(n); + Console.WriteLine("线性阶的计算操作数量 = " + count); + count = arrayTraversal(new int[n]); + Console.WriteLine("线性阶(遍历数组)的计算操作数量 = " + count); + + count = quadratic(n); + Console.WriteLine("平方阶的计算操作数量 = " + count); + int[] nums = new int[n]; + for (int i = 0; i < n; i++) + nums[i] = n - i; // [n,n-1,...,2,1] + count = bubbleSort(nums); + Console.WriteLine("平方阶(冒泡排序)的计算操作数量 = " + count); + + count = exponential(n); + Console.WriteLine("指数阶(循环实现)的计算操作数量 = " + count); + count = expRecur(n); + Console.WriteLine("指数阶(递归实现)的计算操作数量 = " + count); + + count = logarithmic((float)n); + Console.WriteLine("对数阶(循环实现)的计算操作数量 = " + count); + count = logRecur((float)n); + Console.WriteLine("对数阶(递归实现)的计算操作数量 = " + count); + + count = linearLogRecur((float)n); + Console.WriteLine("线性对数阶(递归实现)的计算操作数量 = " + count); + + count = factorialRecur(n); + Console.WriteLine("阶乘阶(递归实现)的计算操作数量 = " + count); } } diff --git a/codes/csharp/chapter_computational_complexity/worst_best_time_complexity.cs b/codes/csharp/chapter_computational_complexity/worst_best_time_complexity.cs index 4469fd976..86d9c4894 100644 --- a/codes/csharp/chapter_computational_complexity/worst_best_time_complexity.cs +++ b/codes/csharp/chapter_computational_complexity/worst_best_time_complexity.cs @@ -6,58 +6,57 @@ using NUnit.Framework; -namespace hello_algo.chapter_computational_complexity +namespace hello_algo.chapter_computational_complexity; + +public class worst_best_time_complexity { - public class worst_best_time_complexity + /* 生成一个数组,元素为 { 1, 2, ..., n },顺序被打乱 */ + static int[] randomNumbers(int n) { - /* 生成一个数组,元素为 { 1, 2, ..., n },顺序被打乱 */ - static int[] randomNumbers(int n) + int[] nums = new int[n]; + // 生成数组 nums = { 1, 2, 3, ..., n } + for (int i = 0; i < n; i++) { - int[] nums = new int[n]; - // 生成数组 nums = { 1, 2, 3, ..., n } - for (int i = 0; i < n; i++) - { - nums[i] = i + 1; - } - - // 随机打乱数组元素 - for (int i = 0; i < nums.Length; i++) - { - var index = new Random().Next(i, nums.Length); - var tmp = nums[i]; - var ran = nums[index]; - nums[i] = ran; - nums[index] = tmp; - } - return nums; + nums[i] = i + 1; } - /* 查找数组 nums 中数字 1 所在索引 */ - static int findOne(int[] nums) + // 随机打乱数组元素 + for (int i = 0; i < nums.Length; i++) { - for (int i = 0; i < nums.Length; i++) - { - // 当元素 1 在数组头部时,达到最佳时间复杂度 O(1) - // 当元素 1 在数组尾部时,达到最差时间复杂度 O(n) - if (nums[i] == 1) - return i; - } - return -1; + var index = new Random().Next(i, nums.Length); + var tmp = nums[i]; + var ran = nums[index]; + nums[i] = ran; + nums[index] = tmp; } + return nums; + } - - /* Driver Code */ - [Test] - public void Test() + /* 查找数组 nums 中数字 1 所在索引 */ + static int findOne(int[] nums) + { + for (int i = 0; i < nums.Length; i++) { - for (int i = 0; i < 10; i++) - { - int n = 100; - int[] nums = randomNumbers(n); - int index = findOne(nums); - Console.WriteLine("\n数组 [ 1, 2, ..., n ] 被打乱后 = " + string.Join(",", nums)); - Console.WriteLine("数字 1 的索引为 " + index); - } + // 当元素 1 在数组头部时,达到最佳时间复杂度 O(1) + // 当元素 1 在数组尾部时,达到最差时间复杂度 O(n) + if (nums[i] == 1) + return i; + } + return -1; + } + + + /* Driver Code */ + [Test] + public void Test() + { + for (int i = 0; i < 10; i++) + { + int n = 100; + int[] nums = randomNumbers(n); + int index = findOne(nums); + Console.WriteLine("\n数组 [ 1, 2, ..., n ] 被打乱后 = " + string.Join(",", nums)); + Console.WriteLine("数字 1 的索引为 " + index); } } } diff --git a/codes/csharp/chapter_hashing/array_hash_map.cs b/codes/csharp/chapter_hashing/array_hash_map.cs index 3320fa856..3a3d692a7 100644 --- a/codes/csharp/chapter_hashing/array_hash_map.cs +++ b/codes/csharp/chapter_hashing/array_hash_map.cs @@ -6,159 +6,157 @@ using NUnit.Framework; -namespace hello_algo.chapter_hashing -{ +namespace hello_algo.chapter_hashing; - /* 键值对 int->String */ - class Entry +/* 键值对 int->String */ +class Entry +{ + public int key; + public String val; + public Entry(int key, String val) { - public int key; - public String val; - public Entry(int key, String val) + this.key = key; + this.val = val; + } +} + +/* 基于数组简易实现的哈希表 */ +class ArrayHashMap +{ + private List bucket; + public ArrayHashMap() + { + // 初始化一个长度为 100 的桶(数组) + bucket = new(); + for (int i = 0; i < 100; i++) { - this.key = key; - this.val = val; + bucket.Add(null); } } - /* 基于数组简易实现的哈希表 */ - class ArrayHashMap + /* 哈希函数 */ + private int hashFunc(int key) { - private List bucket; - public ArrayHashMap() - { - // 初始化一个长度为 100 的桶(数组) - bucket = new (); - for (int i = 0; i < 100; i++) - { - bucket.Add(null); - } - } + int index = key % 100; + return index; + } - /* 哈希函数 */ - private int hashFunc(int key) - { - int index = key % 100; - return index; - } + /* 查询操作 */ + public String? get(int key) + { + int index = hashFunc(key); + Entry? pair = bucket[index]; + if (pair == null) return null; + return pair.val; + } - /* 查询操作 */ - public String? get(int key) + /* 添加操作 */ + public void put(int key, String val) + { + Entry pair = new Entry(key, val); + int index = hashFunc(key); + bucket[index] = pair; + } + + /* 删除操作 */ + public void remove(int key) + { + int index = hashFunc(key); + // 置为 null ,代表删除 + bucket[index] = null; + } + + /* 获取所有键值对 */ + public List entrySet() + { + List entrySet = new(); + foreach (Entry? pair in bucket) { - int index = hashFunc(key); - Entry? pair = bucket[index]; - if (pair == null) return null; - return pair.val; + if (pair != null) + entrySet.Add(pair); } + return entrySet; + } + + /* 获取所有键 */ + public List keySet() + { + List keySet = new(); + foreach (Entry? pair in bucket) + { + if (pair != null) + keySet.Add(pair.key); + } + return keySet; + } + + /* 获取所有值 */ + public List valueSet() + { + List valueSet = new(); + foreach (Entry? pair in bucket) + { + if (pair != null) + valueSet.Add(pair.val); + } + return valueSet; + } + + /* 打印哈希表 */ + public void print() + { + foreach (Entry kv in entrySet()) + { + Console.WriteLine(kv.key + " -> " + kv.val); + } + } +} + + +public class array_hash_map +{ + [Test] + public void Test() + { + /* 初始化哈希表 */ + ArrayHashMap map = new ArrayHashMap(); /* 添加操作 */ - public void put(int key, String val) - { - Entry pair = new Entry(key, val); - int index = hashFunc(key); - bucket[index]=pair; - } + // 在哈希表中添加键值对 (key, value) + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); + Console.WriteLine("\n添加完成后,哈希表为\nKey -> Value"); + map.print(); + + /* 查询操作 */ + // 向哈希表输入键 key ,得到值 value + String? name = map.get(15937); + Console.WriteLine("\n输入学号 15937 ,查询到姓名 " + name); /* 删除操作 */ - public void remove(int key) - { - int index = hashFunc(key); - // 置为 null ,代表删除 - bucket[index]=null; - } + // 在哈希表中删除键值对 (key, value) + map.remove(10583); + Console.WriteLine("\n删除 10583 后,哈希表为\nKey -> Value"); + map.print(); - /* 获取所有键值对 */ - public List entrySet() + /* 遍历哈希表 */ + Console.WriteLine("\n遍历键值对 Key->Value"); + foreach (Entry kv in map.entrySet()) { - List entrySet = new (); - foreach (Entry? pair in bucket) - { - if (pair != null) - entrySet.Add(pair); - } - return entrySet; + Console.WriteLine(kv.key + " -> " + kv.val); } - - /* 获取所有键 */ - public List keySet() + Console.WriteLine("\n单独遍历键 Key"); + foreach (int key in map.keySet()) { - List keySet = new (); - foreach (Entry? pair in bucket) - { - if (pair != null) - keySet.Add(pair.key); - } - return keySet; + Console.WriteLine(key); } - - /* 获取所有值 */ - public List valueSet() + Console.WriteLine("\n单独遍历值 Value"); + foreach (String val in map.valueSet()) { - List valueSet = new (); - foreach (Entry? pair in bucket) - { - if (pair != null) - valueSet.Add(pair.val); - } - return valueSet; - } - - /* 打印哈希表 */ - public void print() - { - foreach (Entry kv in entrySet()) - { - Console.WriteLine(kv.key + " -> " + kv.val); - } + Console.WriteLine(val); } } - - - public class array_hash_map - { - [Test] - public void Test() - { - /* 初始化哈希表 */ - ArrayHashMap map = new ArrayHashMap(); - - /* 添加操作 */ - // 在哈希表中添加键值对 (key, value) - map.put(12836, "小哈"); - map.put(15937, "小啰"); - map.put(16750, "小算"); - map.put(13276, "小法"); - map.put(10583, "小鸭"); - Console.WriteLine("\n添加完成后,哈希表为\nKey -> Value"); - map.print(); - - /* 查询操作 */ - // 向哈希表输入键 key ,得到值 value - String? name = map.get(15937); - Console.WriteLine("\n输入学号 15937 ,查询到姓名 " + name); - - /* 删除操作 */ - // 在哈希表中删除键值对 (key, value) - map.remove(10583); - Console.WriteLine("\n删除 10583 后,哈希表为\nKey -> Value"); - map.print(); - - /* 遍历哈希表 */ - Console.WriteLine("\n遍历键值对 Key->Value"); - foreach (Entry kv in map.entrySet()) - { - Console.WriteLine(kv.key + " -> " + kv.val); - } - Console.WriteLine("\n单独遍历键 Key"); - foreach (int key in map.keySet()) - { - Console.WriteLine(key); - } - Console.WriteLine("\n单独遍历值 Value"); - foreach (String val in map.valueSet()) - { - Console.WriteLine(val); - } - } - } -} \ No newline at end of file +} diff --git a/codes/csharp/chapter_hashing/hash_map.cs b/codes/csharp/chapter_hashing/hash_map.cs index 6afcc82c8..f733795d1 100644 --- a/codes/csharp/chapter_hashing/hash_map.cs +++ b/codes/csharp/chapter_hashing/hash_map.cs @@ -8,50 +8,52 @@ using hello_algo.include; using NUnit.Framework; -namespace hello_algo.chapter_hashing +namespace hello_algo.chapter_hashing; + +public class hash_map { + [Test] + public void Test() + { + /* 初始化哈希表 */ + Dictionary map = new(); - public class hash_map { - [Test] - public void Test() + /* 添加操作 */ + // 在哈希表中添加键值对 (key, value) + map.Add(12836, "小哈"); + map.Add(15937, "小啰"); + map.Add(16750, "小算"); + map.Add(13276, "小法"); + map.Add(10583, "小鸭"); + Console.WriteLine("\n添加完成后,哈希表为\nKey -> Value"); + PrintUtil.printHashMap(map); + + /* 查询操作 */ + // 向哈希表输入键 key ,得到值 value + String name = map[15937]; + Console.WriteLine("\n输入学号 15937 ,查询到姓名 " + name); + + /* 删除操作 */ + // 在哈希表中删除键值对 (key, value) + map.Remove(10583); + Console.WriteLine("\n删除 10583 后,哈希表为\nKey -> Value"); + PrintUtil.printHashMap(map); + + /* 遍历哈希表 */ + Console.WriteLine("\n遍历键值对 Key->Value"); + foreach (var kv in map) { - /* 初始化哈希表 */ - Dictionary map = new (); - - /* 添加操作 */ - // 在哈希表中添加键值对 (key, value) - map.Add(12836, "小哈"); - map.Add(15937, "小啰"); - map.Add(16750, "小算"); - map.Add(13276, "小法"); - map.Add(10583, "小鸭"); - Console.WriteLine("\n添加完成后,哈希表为\nKey -> Value"); - PrintUtil.printHashMap(map); - - /* 查询操作 */ - // 向哈希表输入键 key ,得到值 value - String name = map[15937]; - Console.WriteLine("\n输入学号 15937 ,查询到姓名 " + name); - - /* 删除操作 */ - // 在哈希表中删除键值对 (key, value) - map.Remove(10583); - Console.WriteLine("\n删除 10583 后,哈希表为\nKey -> Value"); - PrintUtil.printHashMap(map); - - /* 遍历哈希表 */ - Console.WriteLine("\n遍历键值对 Key->Value"); - foreach (var kv in map) { - Console.WriteLine(kv.Key + " -> " + kv.Value); - } - Console.WriteLine("\n单独遍历键 Key"); - foreach (int key in map.Keys) { - Console.WriteLine(key); - } - Console.WriteLine("\n单独遍历值 Value"); - foreach (String val in map.Values) { - Console.WriteLine(val); - } + Console.WriteLine(kv.Key + " -> " + kv.Value); + } + Console.WriteLine("\n单独遍历键 Key"); + foreach (int key in map.Keys) + { + Console.WriteLine(key); + } + Console.WriteLine("\n单独遍历值 Value"); + foreach (String val in map.Values) + { + Console.WriteLine(val); } } } diff --git a/codes/csharp/chapter_searching/binary_search.cs b/codes/csharp/chapter_searching/binary_search.cs index 1bf8a5b2f..361f40723 100644 --- a/codes/csharp/chapter_searching/binary_search.cs +++ b/codes/csharp/chapter_searching/binary_search.cs @@ -6,63 +6,62 @@ using NUnit.Framework; -namespace hello_algo.chapter_searching +namespace hello_algo.chapter_searching; + +public class binary_search { - public class binary_search + /* 二分查找(双闭区间) */ + static int binarySearch(int[] nums, int target) { - /* 二分查找(双闭区间) */ - static int binarySearch(int[] nums, int target) + // 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 + int i = 0, j = nums.Length - 1; + // 循环,当搜索区间为空时跳出(当 i > j 时为空) + while (i <= j) { - // 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 - int i = 0, j = nums.Length - 1; - // 循环,当搜索区间为空时跳出(当 i > j 时为空) - while (i <= j) - { - int m = (i + j) / 2; // 计算中点索引 m - if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中 - i = m + 1; - else if (nums[m] > target) // 此情况说明 target 在区间 [i, m-1] 中 - j = m - 1; - else // 找到目标元素,返回其索引 - return m; - } - // 未找到目标元素,返回 -1 - return -1; + int m = (i + j) / 2; // 计算中点索引 m + if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中 + i = m + 1; + else if (nums[m] > target) // 此情况说明 target 在区间 [i, m-1] 中 + j = m - 1; + else // 找到目标元素,返回其索引 + return m; } + // 未找到目标元素,返回 -1 + return -1; + } + + /* 二分查找(左闭右开) */ + static int binarySearch1(int[] nums, int target) + { + // 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 + int i = 0, j = nums.Length; + // 循环,当搜索区间为空时跳出(当 i = j 时为空) + while (i < j) + { + int m = (i + j) / 2; // 计算中点索引 m + if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中 + i = m + 1; + else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中 + j = m; + else // 找到目标元素,返回其索引 + return m; + } + // 未找到目标元素,返回 -1 + return -1; + } + + [Test] + public void Test() + { + int target = 6; + int[] nums = { 1, 3, 6, 8, 12, 15, 23, 67, 70, 92 }; + + /* 二分查找(双闭区间) */ + int index = binarySearch(nums, target); + Console.WriteLine("目标元素 6 的索引 = " + index); /* 二分查找(左闭右开) */ - static int binarySearch1(int[] nums, int target) - { - // 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 - int i = 0, j = nums.Length; - // 循环,当搜索区间为空时跳出(当 i = j 时为空) - while (i < j) - { - int m = (i + j) / 2; // 计算中点索引 m - if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中 - i = m + 1; - else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中 - j = m; - else // 找到目标元素,返回其索引 - return m; - } - // 未找到目标元素,返回 -1 - return -1; - } - - [Test] - public void Test() - { - int target = 6; - int[] nums = { 1, 3, 6, 8, 12, 15, 23, 67, 70, 92 }; - - /* 二分查找(双闭区间) */ - int index = binarySearch(nums, target); - Console.WriteLine("目标元素 6 的索引 = " + index); - - /* 二分查找(左闭右开) */ - index = binarySearch1(nums, target); - Console.WriteLine("目标元素 6 的索引 = " + index); - } + index = binarySearch1(nums, target); + Console.WriteLine("目标元素 6 的索引 = " + index); } } diff --git a/codes/csharp/chapter_searching/hashing_search.cs b/codes/csharp/chapter_searching/hashing_search.cs index 1c324bdfa..1986ef86d 100644 --- a/codes/csharp/chapter_searching/hashing_search.cs +++ b/codes/csharp/chapter_searching/hashing_search.cs @@ -7,54 +7,53 @@ using hello_algo.include; using NUnit.Framework; -namespace hello_algo.chapter_searching +namespace hello_algo.chapter_searching; + +public class hashing_search { - public class hashing_search + /* 哈希查找(数组) */ + static int hashingSearchArray(Dictionary map, int target) { + // 哈希表的 key: 目标元素,value: 索引 + // 若哈希表中无此 key ,返回 -1 + return map.GetValueOrDefault(target, -1); + } + + /* 哈希查找(链表) */ + static ListNode? hashingSearchLinkedList(Dictionary map, int target) + { + + // 哈希表的 key: 目标结点值,value: 结点对象 + // 若哈希表中无此 key ,返回 null + return map.GetValueOrDefault(target); + } + + [Test] + public void Test() + { + int target = 3; + /* 哈希查找(数组) */ - static int hashingSearchArray(Dictionary map, int target) + int[] nums = { 1, 5, 3, 2, 4, 7, 5, 9, 10, 8 }; + // 初始化哈希表 + Dictionary map = new(); + for (int i = 0; i < nums.Length; i++) { - // 哈希表的 key: 目标元素,value: 索引 - // 若哈希表中无此 key ,返回 -1 - return map.GetValueOrDefault(target, -1); + map[nums[i]] = i; // key: 元素,value: 索引 } + int index = hashingSearchArray(map, target); + Console.WriteLine("目标元素 3 的索引 = " + index); /* 哈希查找(链表) */ - static ListNode? hashingSearchLinkedList(Dictionary map, int target) + ListNode? head = ListNode.ArrToLinkedList(nums); + // 初始化哈希表 + Dictionary map1 = new(); + while (head != null) { - - // 哈希表的 key: 目标结点值,value: 结点对象 - // 若哈希表中无此 key ,返回 null - return map.GetValueOrDefault(target); - } - - [Test] - public void Test() - { - int target = 3; - - /* 哈希查找(数组) */ - int[] nums = { 1, 5, 3, 2, 4, 7, 5, 9, 10, 8 }; - // 初始化哈希表 - Dictionary map = new(); - for (int i = 0; i < nums.Length; i++) - { - map[nums[i]] = i; // key: 元素,value: 索引 - } - int index = hashingSearchArray(map, target); - Console.WriteLine("目标元素 3 的索引 = " + index); - - /* 哈希查找(链表) */ - ListNode? head = ListNode.ArrToLinkedList(nums); - // 初始化哈希表 - Dictionary map1 = new(); - while (head != null) - { - map1[head.val] = head; // key: 结点值,value: 结点 - head = head.next; - } - ListNode? node = hashingSearchLinkedList(map1, target); - Console.WriteLine("目标结点值 3 的对应结点对象为 " + node); + map1[head.val] = head; // key: 结点值,value: 结点 + head = head.next; } + ListNode? node = hashingSearchLinkedList(map1, target); + Console.WriteLine("目标结点值 3 的对应结点对象为 " + node); } } diff --git a/codes/csharp/chapter_searching/linear_search.cs b/codes/csharp/chapter_searching/linear_search.cs index 7faa47325..3123de859 100644 --- a/codes/csharp/chapter_searching/linear_search.cs +++ b/codes/csharp/chapter_searching/linear_search.cs @@ -7,53 +7,52 @@ using hello_algo.include; using NUnit.Framework; -namespace hello_algo.chapter_searching +namespace hello_algo.chapter_searching; + +public class linear_search { - public class linear_search + /* 线性查找(数组) */ + static int linearSearchArray(int[] nums, int target) { - /* 线性查找(数组) */ - static int linearSearchArray(int[] nums, int target) + // 遍历数组 + for (int i = 0; i < nums.Length; i++) { - // 遍历数组 - for (int i = 0; i < nums.Length; i++) - { - // 找到目标元素,返回其索引 - if (nums[i] == target) - return i; - } - // 未找到目标元素,返回 -1 - return -1; + // 找到目标元素,返回其索引 + if (nums[i] == target) + return i; } + // 未找到目标元素,返回 -1 + return -1; + } - /* 线性查找(链表) */ - static ListNode? linearSearchLinkedList(ListNode head, int target) + /* 线性查找(链表) */ + static ListNode? linearSearchLinkedList(ListNode head, int target) + { + // 遍历链表 + while (head != null) { - // 遍历链表 - while (head != null) - { - // 找到目标结点,返回之 - if (head.val == target) - return head; - head = head.next; - } - // 未找到目标结点,返回 null - return null; + // 找到目标结点,返回之 + if (head.val == target) + return head; + head = head.next; } + // 未找到目标结点,返回 null + return null; + } - [Test] - public void Test() - { - int target = 3; + [Test] + public void Test() + { + int target = 3; - /* 在数组中执行线性查找 */ - int[] nums = { 1, 5, 3, 2, 4, 7, 5, 9, 10, 8 }; - int index = linearSearchArray(nums, target); - Console.WriteLine("目标元素 3 的索引 = " + index); + /* 在数组中执行线性查找 */ + int[] nums = { 1, 5, 3, 2, 4, 7, 5, 9, 10, 8 }; + int index = linearSearchArray(nums, target); + Console.WriteLine("目标元素 3 的索引 = " + index); - /* 在链表中执行线性查找 */ - ListNode head = ListNode.ArrToLinkedList(nums); - ListNode? node = linearSearchLinkedList(head, target); - Console.WriteLine("目标结点值 3 的对应结点对象为 " + node); - } + /* 在链表中执行线性查找 */ + ListNode head = ListNode.ArrToLinkedList(nums); + ListNode? node = linearSearchLinkedList(head, target); + Console.WriteLine("目标结点值 3 的对应结点对象为 " + node); } } diff --git a/codes/csharp/chapter_sorting/bubble_sort.cs b/codes/csharp/chapter_sorting/bubble_sort.cs index b3304df04..64fcc6702 100644 --- a/codes/csharp/chapter_sorting/bubble_sort.cs +++ b/codes/csharp/chapter_sorting/bubble_sort.cs @@ -6,63 +6,62 @@ using NUnit.Framework; -namespace hello_algo.chapter_sorting +namespace hello_algo.chapter_sorting; + +public class bubble_sort { - public class bubble_sort + /* 冒泡排序 */ + static void bubbleSort(int[] nums) { - /* 冒泡排序 */ - static void bubbleSort(int[] nums) + // 外循环:待排序元素数量为 n-1, n-2, ..., 1 + for (int i = nums.Length - 1; i > 0; i--) { - // 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for (int i = nums.Length - 1; i > 0; i--) + // 内循环:冒泡操作 + for (int j = 0; j < i; j++) { - // 内循环:冒泡操作 - for (int j = 0; j < i; j++) + if (nums[j] > nums[j + 1]) { - if (nums[j] > nums[j + 1]) - { - // 交换 nums[j] 与 nums[j + 1] - int tmp = nums[j]; - nums[j] = nums[j + 1]; - nums[j + 1] = tmp; - } + // 交换 nums[j] 与 nums[j + 1] + int tmp = nums[j]; + nums[j] = nums[j + 1]; + nums[j + 1] = tmp; } } } - - /* 冒泡排序(标志优化)*/ - static void bubbleSortWithFlag(int[] nums) - { - // 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for (int i = nums.Length - 1; i > 0; i--) - { - bool flag = false; // 初始化标志位 - // 内循环:冒泡操作 - for (int j = 0; j < i; j++) - { - if (nums[j] > nums[j + 1]) - { - // 交换 nums[j] 与 nums[j + 1] - int tmp = nums[j]; - nums[j] = nums[j + 1]; - nums[j + 1] = tmp; - flag = true; // 记录交换元素 - } - } - if (!flag) break; // 此轮冒泡未交换任何元素,直接跳出 - } - } - - [Test] - public void Test() - { - int[] nums = { 4, 1, 3, 1, 5, 2 }; - bubbleSort(nums); - Console.WriteLine("冒泡排序完成后 nums = " + string.Join(",",nums)); - - int[] nums1 = { 4, 1, 3, 1, 5, 2 }; - bubbleSortWithFlag(nums1); - Console.WriteLine("冒泡排序完成后 nums1 = " + string.Join(",", nums)); - } + } + + /* 冒泡排序(标志优化)*/ + static void bubbleSortWithFlag(int[] nums) + { + // 外循环:待排序元素数量为 n-1, n-2, ..., 1 + for (int i = nums.Length - 1; i > 0; i--) + { + bool flag = false; // 初始化标志位 + // 内循环:冒泡操作 + for (int j = 0; j < i; j++) + { + if (nums[j] > nums[j + 1]) + { + // 交换 nums[j] 与 nums[j + 1] + int tmp = nums[j]; + nums[j] = nums[j + 1]; + nums[j + 1] = tmp; + flag = true; // 记录交换元素 + } + } + if (!flag) break; // 此轮冒泡未交换任何元素,直接跳出 + } + } + + [Test] + public void Test() + { + int[] nums = { 4, 1, 3, 1, 5, 2 }; + bubbleSort(nums); + Console.WriteLine("冒泡排序完成后 nums = " + string.Join(",", nums)); + + int[] nums1 = { 4, 1, 3, 1, 5, 2 }; + bubbleSortWithFlag(nums1); + Console.WriteLine("冒泡排序完成后 nums1 = " + string.Join(",", nums)); } } diff --git a/codes/csharp/chapter_sorting/insertion_sort.cs b/codes/csharp/chapter_sorting/insertion_sort.cs index 0f674c9fc..171bc3c33 100644 --- a/codes/csharp/chapter_sorting/insertion_sort.cs +++ b/codes/csharp/chapter_sorting/insertion_sort.cs @@ -6,33 +6,32 @@ using NUnit.Framework; -namespace hello_algo.chapter_sorting -{ - public class insertion_sort - { - /* 插入排序 */ - static void insertionSort(int[] nums) - { - // 外循环:base = nums[1], nums[2], ..., nums[n-1] - for (int i = 1; i < nums.Length; i++) - { - int bas = nums[i], j = i - 1; - // 内循环:将 base 插入到左边的正确位置 - while (j >= 0 && nums[j] > bas) - { - nums[j + 1] = nums[j]; // 1. 将 nums[j] 向右移动一位 - j--; - } - nums[j + 1] = bas; // 2. 将 base 赋值到正确位置 - } - } +namespace hello_algo.chapter_sorting; - [Test] - public void Test() +public class insertion_sort +{ + /* 插入排序 */ + static void insertionSort(int[] nums) + { + // 外循环:base = nums[1], nums[2], ..., nums[n-1] + for (int i = 1; i < nums.Length; i++) { - int[] nums = { 4, 1, 3, 1, 5, 2 }; - insertionSort(nums); - Console.WriteLine("插入排序完成后 nums = " + string.Join(",", nums)); + int bas = nums[i], j = i - 1; + // 内循环:将 base 插入到左边的正确位置 + while (j >= 0 && nums[j] > bas) + { + nums[j + 1] = nums[j]; // 1. 将 nums[j] 向右移动一位 + j--; + } + nums[j + 1] = bas; // 2. 将 base 赋值到正确位置 } } + + [Test] + public void Test() + { + int[] nums = { 4, 1, 3, 1, 5, 2 }; + insertionSort(nums); + Console.WriteLine("插入排序完成后 nums = " + string.Join(",", nums)); + } } diff --git a/codes/csharp/chapter_sorting/merge_sort.cs b/codes/csharp/chapter_sorting/merge_sort.cs index e66ae5e23..899dad99e 100644 --- a/codes/csharp/chapter_sorting/merge_sort.cs +++ b/codes/csharp/chapter_sorting/merge_sort.cs @@ -6,60 +6,57 @@ using NUnit.Framework; -namespace hello_algo.chapter_sorting +namespace hello_algo.chapter_sorting; + +public class merge_sort { - public class merge_sort + /* 合并左子数组和右子数组 */ + // 左子数组区间 [left, mid] + // 右子数组区间 [mid + 1, right] + static void merge(int[] nums, int left, int mid, int right) { - /** - * 合并左子数组和右子数组 - * 左子数组区间 [left, mid] - * 右子数组区间 [mid + 1, right] - */ - static void merge(int[] nums, int left, int mid, int right) + // 初始化辅助数组 + int[] tmp = nums[left..(right + 1)]; + // 左子数组的起始索引和结束索引 + int leftStart = left - left, leftEnd = mid - left; + // 右子数组的起始索引和结束索引 + int rightStart = mid + 1 - left, rightEnd = right - left; + // i, j 分别指向左子数组、右子数组的首元素 + int i = leftStart, j = rightStart; + // 通过覆盖原数组 nums 来合并左子数组和右子数组 + for (int k = left; k <= right; k++) { - // 初始化辅助数组 - int[] tmp = nums[left..(right + 1)]; - // 左子数组的起始索引和结束索引 - int leftStart = left - left, leftEnd = mid - left; - // 右子数组的起始索引和结束索引 - int rightStart = mid + 1 - left, rightEnd = right - left; - // i, j 分别指向左子数组、右子数组的首元素 - int i = leftStart, j = rightStart; - // 通过覆盖原数组 nums 来合并左子数组和右子数组 - for (int k = left; k <= right; k++) - { - // 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++ - if (i > leftEnd) - nums[k] = tmp[j++]; - // 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++ - else if (j > rightEnd || tmp[i] <= tmp[j]) - nums[k] = tmp[i++]; - // 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++ - else - nums[k] = tmp[j++]; - } - } - - /* 归并排序 */ - static void mergeSort(int[] nums, int left, int right) - { - // 终止条件 - if (left >= right) return; // 当子数组长度为 1 时终止递归 - // 划分阶段 - int mid = (left + right) / 2; // 计算中点 - mergeSort(nums, left, mid); // 递归左子数组 - mergeSort(nums, mid + 1, right); // 递归右子数组 - // 合并阶段 - merge(nums, left, mid, right); - } - - [Test] - public void Test() - { - /* 归并排序 */ - int[] nums = { 7, 3, 2, 6, 0, 1, 5, 4 }; - mergeSort(nums, 0, nums.Length - 1); - Console.WriteLine("归并排序完成后 nums = " + string.Join(",", nums)); + // 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++ + if (i > leftEnd) + nums[k] = tmp[j++]; + // 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++ + else if (j > rightEnd || tmp[i] <= tmp[j]) + nums[k] = tmp[i++]; + // 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++ + else + nums[k] = tmp[j++]; } } + + /* 归并排序 */ + static void mergeSort(int[] nums, int left, int right) + { + // 终止条件 + if (left >= right) return; // 当子数组长度为 1 时终止递归 + // 划分阶段 + int mid = (left + right) / 2; // 计算中点 + mergeSort(nums, left, mid); // 递归左子数组 + mergeSort(nums, mid + 1, right); // 递归右子数组 + // 合并阶段 + merge(nums, left, mid, right); + } + + [Test] + public void Test() + { + /* 归并排序 */ + int[] nums = { 7, 3, 2, 6, 0, 1, 5, 4 }; + mergeSort(nums, 0, nums.Length - 1); + Console.WriteLine("归并排序完成后 nums = " + string.Join(",", nums)); + } } diff --git a/codes/csharp/chapter_sorting/quick_sort.cs b/codes/csharp/chapter_sorting/quick_sort.cs index 90de5c192..91b23b650 100644 --- a/codes/csharp/chapter_sorting/quick_sort.cs +++ b/codes/csharp/chapter_sorting/quick_sort.cs @@ -6,178 +6,177 @@ using NUnit.Framework; -namespace hello_algo.chapter_sorting +namespace hello_algo.chapter_sorting; + +class QuickSort { - class QuickSort + /* 元素交换 */ + static void swap(int[] nums, int i, int j) { - /* 元素交换 */ - static void swap(int[] nums, int i, int j) - { - int tmp = nums[i]; - nums[i] = nums[j]; - nums[j] = tmp; - } - - /* 哨兵划分 */ - static int partition(int[] nums, int left, int right) - { - // 以 nums[left] 作为基准数 - int i = left, j = right; - while (i < j) - { - while (i < j && nums[j] >= nums[left]) - j--; // 从右向左找首个小于基准数的元素 - while (i < j && nums[i] <= nums[left]) - i++; // 从左向右找首个大于基准数的元素 - swap(nums, i, j); // 交换这两个元素 - } - swap(nums, i, left); // 将基准数交换至两子数组的分界线 - return i; // 返回基准数的索引 - } - - /* 快速排序 */ - public static void quickSort(int[] nums, int left, int right) - { - // 子数组长度为 1 时终止递归 - if (left >= right) - return; - // 哨兵划分 - int pivot = partition(nums, left, right); - // 递归左子数组、右子数组 - quickSort(nums, left, pivot - 1); - quickSort(nums, pivot + 1, right); - } + int tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; } - /* 快速排序类(中位基准数优化) */ - class QuickSortMedian + /* 哨兵划分 */ + static int partition(int[] nums, int left, int right) { - /* 元素交换 */ - static void swap(int[] nums, int i, int j) + // 以 nums[left] 作为基准数 + int i = left, j = right; + while (i < j) { - int tmp = nums[i]; - nums[i] = nums[j]; - nums[j] = tmp; + while (i < j && nums[j] >= nums[left]) + j--; // 从右向左找首个小于基准数的元素 + while (i < j && nums[i] <= nums[left]) + i++; // 从左向右找首个大于基准数的元素 + swap(nums, i, j); // 交换这两个元素 } + swap(nums, i, left); // 将基准数交换至两子数组的分界线 + return i; // 返回基准数的索引 + } - /* 选取三个元素的中位数 */ - static int medianThree(int[] nums, int left, int mid, int right) + /* 快速排序 */ + public static void quickSort(int[] nums, int left, int right) + { + // 子数组长度为 1 时终止递归 + if (left >= right) + return; + // 哨兵划分 + int pivot = partition(nums, left, right); + // 递归左子数组、右子数组 + quickSort(nums, left, pivot - 1); + quickSort(nums, pivot + 1, right); + } +} + +/* 快速排序类(中位基准数优化) */ +class QuickSortMedian +{ + /* 元素交换 */ + static void swap(int[] nums, int i, int j) + { + int tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; + } + + /* 选取三个元素的中位数 */ + static int medianThree(int[] nums, int left, int mid, int right) + { + // 使用了异或操作来简化代码 + // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 + if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right])) + return left; + else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right])) + return mid; + else + return right; + } + + /* 哨兵划分(三数取中值) */ + static int partition(int[] nums, int left, int right) + { + // 选取三个候选元素的中位数 + int med = medianThree(nums, left, (left + right) / 2, right); + // 将中位数交换至数组最左端 + swap(nums, left, med); + // 以 nums[left] 作为基准数 + int i = left, j = right; + while (i < j) { - // 使用了异或操作来简化代码 - // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right])) - return left; - else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right])) - return mid; + while (i < j && nums[j] >= nums[left]) + j--; // 从右向左找首个小于基准数的元素 + while (i < j && nums[i] <= nums[left]) + i++; // 从左向右找首个大于基准数的元素 + swap(nums, i, j); // 交换这两个元素 + } + swap(nums, i, left); // 将基准数交换至两子数组的分界线 + return i; // 返回基准数的索引 + } + + /* 快速排序 */ + public static void quickSort(int[] nums, int left, int right) + { + // 子数组长度为 1 时终止递归 + if (left >= right) + return; + // 哨兵划分 + int pivot = partition(nums, left, right); + // 递归左子数组、右子数组 + quickSort(nums, left, pivot - 1); + quickSort(nums, pivot + 1, right); + } +} + +/* 快速排序类(尾递归优化) */ +class QuickSortTailCall +{ + /* 元素交换 */ + static void swap(int[] nums, int i, int j) + { + int tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; + } + + /* 哨兵划分 */ + static int partition(int[] nums, int left, int right) + { + // 以 nums[left] 作为基准数 + int i = left, j = right; + while (i < j) + { + while (i < j && nums[j] >= nums[left]) + j--; // 从右向左找首个小于基准数的元素 + while (i < j && nums[i] <= nums[left]) + i++; // 从左向右找首个大于基准数的元素 + swap(nums, i, j); // 交换这两个元素 + } + swap(nums, i, left); // 将基准数交换至两子数组的分界线 + return i; // 返回基准数的索引 + } + + /* 快速排序(尾递归优化) */ + public static void quickSort(int[] nums, int left, int right) + { + // 子数组长度为 1 时终止 + while (left < right) + { + // 哨兵划分操作 + int pivot = partition(nums, left, right); + // 对两个子数组中较短的那个执行快排 + if (pivot - left < right - pivot) + { + quickSort(nums, left, pivot - 1); // 递归排序左子数组 + left = pivot + 1; // 剩余待排序区间为 [pivot + 1, right] + } else - return right; - } - - /* 哨兵划分(三数取中值) */ - static int partition(int[] nums, int left, int right) - { - // 选取三个候选元素的中位数 - int med = medianThree(nums, left, (left + right) / 2, right); - // 将中位数交换至数组最左端 - swap(nums, left, med); - // 以 nums[left] 作为基准数 - int i = left, j = right; - while (i < j) { - while (i < j && nums[j] >= nums[left]) - j--; // 从右向左找首个小于基准数的元素 - while (i < j && nums[i] <= nums[left]) - i++; // 从左向右找首个大于基准数的元素 - swap(nums, i, j); // 交换这两个元素 + quickSort(nums, pivot + 1, right); // 递归排序右子数组 + right = pivot - 1; // 剩余待排序区间为 [left, pivot - 1] } - swap(nums, i, left); // 将基准数交换至两子数组的分界线 - return i; // 返回基准数的索引 - } - - /* 快速排序 */ - public static void quickSort(int[] nums, int left, int right) - { - // 子数组长度为 1 时终止递归 - if (left >= right) - return; - // 哨兵划分 - int pivot = partition(nums, left, right); - // 递归左子数组、右子数组 - quickSort(nums, left, pivot - 1); - quickSort(nums, pivot + 1, right); - } - } - - /* 快速排序类(尾递归优化) */ - class QuickSortTailCall - { - /* 元素交换 */ - static void swap(int[] nums, int i, int j) - { - int tmp = nums[i]; - nums[i] = nums[j]; - nums[j] = tmp; - } - - /* 哨兵划分 */ - static int partition(int[] nums, int left, int right) - { - // 以 nums[left] 作为基准数 - int i = left, j = right; - while (i < j) - { - while (i < j && nums[j] >= nums[left]) - j--; // 从右向左找首个小于基准数的元素 - while (i < j && nums[i] <= nums[left]) - i++; // 从左向右找首个大于基准数的元素 - swap(nums, i, j); // 交换这两个元素 - } - swap(nums, i, left); // 将基准数交换至两子数组的分界线 - return i; // 返回基准数的索引 - } - - /* 快速排序(尾递归优化) */ - public static void quickSort(int[] nums, int left, int right) - { - // 子数组长度为 1 时终止 - while (left < right) - { - // 哨兵划分操作 - int 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] - } - } - } - } - - public class quick_sort - { - [Test] - public void Test() - { - /* 快速排序 */ - int[] nums = { 2, 4, 1, 0, 3, 5 }; - QuickSort.quickSort(nums, 0, nums.Length - 1); - Console.WriteLine("快速排序完成后 nums = " + string.Join(",", nums)); - - /* 快速排序(中位基准数优化) */ - int[] nums1 = { 2, 4, 1, 0, 3, 5 }; - QuickSortMedian.quickSort(nums1, 0, nums1.Length - 1); - Console.WriteLine("快速排序(中位基准数优化)完成后 nums1 = " + string.Join(",", nums1)); - - /* 快速排序(尾递归优化) */ - int[] nums2 = { 2, 4, 1, 0, 3, 5 }; - QuickSortTailCall.quickSort(nums2, 0, nums2.Length - 1); - Console.WriteLine("快速排序(尾递归优化)完成后 nums2 = " + string.Join(",", nums2)); } } } + +public class quick_sort +{ + [Test] + public void Test() + { + /* 快速排序 */ + int[] nums = { 2, 4, 1, 0, 3, 5 }; + QuickSort.quickSort(nums, 0, nums.Length - 1); + Console.WriteLine("快速排序完成后 nums = " + string.Join(",", nums)); + + /* 快速排序(中位基准数优化) */ + int[] nums1 = { 2, 4, 1, 0, 3, 5 }; + QuickSortMedian.quickSort(nums1, 0, nums1.Length - 1); + Console.WriteLine("快速排序(中位基准数优化)完成后 nums1 = " + string.Join(",", nums1)); + + /* 快速排序(尾递归优化) */ + int[] nums2 = { 2, 4, 1, 0, 3, 5 }; + QuickSortTailCall.quickSort(nums2, 0, nums2.Length - 1); + Console.WriteLine("快速排序(尾递归优化)完成后 nums2 = " + string.Join(",", nums2)); + } +} diff --git a/codes/csharp/chapter_stack_and_queue/array_queue.cs b/codes/csharp/chapter_stack_and_queue/array_queue.cs index ca84dc93a..51160eb64 100644 --- a/codes/csharp/chapter_stack_and_queue/array_queue.cs +++ b/codes/csharp/chapter_stack_and_queue/array_queue.cs @@ -6,127 +6,125 @@ using NUnit.Framework; -namespace hello_algo.chapter_stack_and_queue +namespace hello_algo.chapter_stack_and_queue; + +/* 基于环形数组实现的队列 */ +class ArrayQueue { + private int[] nums; // 用于存储队列元素的数组 + private int front; // 队首指针,指向队首元素 + private int queSize; // 队列长度 - /* 基于环形数组实现的队列 */ - class ArrayQueue + public ArrayQueue(int capacity) { - private int[] nums; // 用于存储队列元素的数组 - private int front; // 队首指针,指向队首元素 - private int queSize; // 队列长度 + nums = new int[capacity]; + front = queSize = 0; + } - public ArrayQueue(int capacity) - { - nums = new int[capacity]; - front = queSize = 0; - } + /* 获取队列的容量 */ + public int capacity() + { + return nums.Length; + } - /* 获取队列的容量 */ - public int capacity() - { - return nums.Length; - } + /* 获取队列的长度 */ + public int size() + { + return queSize; + } - /* 获取队列的长度 */ - public int size() - { - return queSize; - } + /* 判断队列是否为空 */ + public bool isEmpty() + { + return queSize == 0; + } - /* 判断队列是否为空 */ - public bool isEmpty() + /* 入队 */ + public void push(int num) + { + if (queSize == capacity()) { - return queSize == 0; + Console.WriteLine("队列已满"); + return; } + // 计算尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + int rear = (front + queSize) % capacity(); + // 尾结点后添加 num + nums[rear] = num; + queSize++; + } - /* 入队 */ - public void push(int num) - { - if (queSize == capacity()) - { - Console.WriteLine("队列已满"); - return; - } - // 计算尾指针,指向队尾索引 + 1 - // 通过取余操作,实现 rear 越过数组尾部后回到头部 - int rear = (front + queSize) % capacity(); - // 尾结点后添加 num - nums[rear] = num; - queSize++; - } + /* 出队 */ + public int poll() + { + int num = peek(); + // 队首指针向后移动一位,若越过尾部则返回到数组头部 + front = (front + 1) % capacity(); + queSize--; + return num; + } - /* 出队 */ - public int poll() + /* 访问队首元素 */ + public int peek() + { + if (isEmpty()) + throw new Exception(); + return nums[front]; + } + + /* 返回数组 */ + public int[] toArray() + { + // 仅转换有效长度范围内的列表元素 + int[] res = new int[queSize]; + for (int i = 0, j = front; i < queSize; i++, j++) { - int num = peek(); - // 队首指针向后移动一位,若越过尾部则返回到数组头部 - front = (front + 1) % capacity(); - queSize--; - return num; + res[i] = nums[j % this.capacity()]; } + return res; + } +} + +public class array_queue +{ + [Test] + public void Test() + { + /* 初始化队列 */ + int capacity = 10; + ArrayQueue queue = new ArrayQueue(capacity); + + /* 元素入队 */ + queue.push(1); + queue.push(3); + queue.push(2); + queue.push(5); + queue.push(4); + Console.WriteLine("队列 queue = " + string.Join(",", queue.toArray())); /* 访问队首元素 */ - public int peek() - { - if (isEmpty()) - throw new Exception(); - return nums[front]; - } + int peek = queue.peek(); + Console.WriteLine("队首元素 peek = " + peek); - /* 返回数组 */ - public int[] toArray() + /* 元素出队 */ + int poll = queue.poll(); + Console.WriteLine("出队元素 poll = " + poll + ",出队后 queue = " + string.Join(",", queue.toArray())); + + /* 获取队列的长度 */ + int size = queue.size(); + Console.WriteLine("队列长度 size = " + size); + + /* 判断队列是否为空 */ + bool isEmpty = queue.isEmpty(); + Console.WriteLine("队列是否为空 = " + isEmpty); + + /* 测试环形数组 */ + for (int i = 0; i < 10; i++) { - // 仅转换有效长度范围内的列表元素 - int[] res = new int[queSize]; - for (int i = 0, j = front; i < queSize; i++, j++) - { - res[i] = nums[j % this.capacity()]; - } - return res; + queue.push(i); + queue.poll(); + Console.WriteLine("第 " + i + " 轮入队 + 出队后 queue = " + string.Join(",", queue.toArray())); } } - - public class array_queue - { - [Test] - public void Test() - { - /* 初始化队列 */ - int capacity = 10; - ArrayQueue queue = new ArrayQueue(capacity); - - /* 元素入队 */ - queue.push(1); - queue.push(3); - queue.push(2); - queue.push(5); - queue.push(4); - Console.WriteLine("队列 queue = " + string.Join(",", queue.toArray())); - - /* 访问队首元素 */ - int peek = queue.peek(); - Console.WriteLine("队首元素 peek = " + peek); - - /* 元素出队 */ - int poll = queue.poll(); - Console.WriteLine("出队元素 poll = " + poll + ",出队后 queue = " + string.Join(",", queue.toArray())); - - /* 获取队列的长度 */ - int size = queue.size(); - Console.WriteLine("队列长度 size = " + size); - - /* 判断队列是否为空 */ - bool isEmpty = queue.isEmpty(); - Console.WriteLine("队列是否为空 = " + isEmpty); - - /* 测试环形数组 */ - for (int i = 0; i < 10; i++) - { - queue.push(i); - queue.poll(); - Console.WriteLine("第 " + i + " 轮入队 + 出队后 queue = " + string.Join(",", queue.toArray())); - } - } - } -} \ No newline at end of file +} diff --git a/codes/csharp/chapter_stack_and_queue/array_stack.cs b/codes/csharp/chapter_stack_and_queue/array_stack.cs index b7ea6df76..07711be4f 100644 --- a/codes/csharp/chapter_stack_and_queue/array_stack.cs +++ b/codes/csharp/chapter_stack_and_queue/array_stack.cs @@ -6,93 +6,91 @@ using NUnit.Framework; -namespace hello_algo.chapter_stack_and_queue +namespace hello_algo.chapter_stack_and_queue; + +/* 基于数组实现的栈 */ +class ArrayStack { - - /* 基于数组实现的栈 */ - class ArrayStack + private List stack; + public ArrayStack() { - private List stack; - public ArrayStack() - { - // 初始化列表(动态数组) - stack = new(); - } - - /* 获取栈的长度 */ - public int size() - { - return stack.Count(); - } - - /* 判断栈是否为空 */ - public bool isEmpty() - { - return size() == 0; - } - - /* 入栈 */ - public void push(int num) - { - stack.Add(num); - } - - /* 出栈 */ - public int pop() - { - if (isEmpty()) - throw new Exception(); - var val = peek(); - stack.RemoveAt(size() - 1); - return val; - } - - /* 访问栈顶元素 */ - public int peek() - { - if (isEmpty()) - throw new Exception(); - return stack[size() - 1]; - } - - /* 将 List 转化为 Array 并返回 */ - public int[] toArray() - { - return stack.ToArray(); - } + // 初始化列表(动态数组) + stack = new(); } - public class array_stack + /* 获取栈的长度 */ + public int size() { - [Test] - public void Test() - { - /* 初始化栈 */ - ArrayStack stack = new ArrayStack(); + return stack.Count(); + } - /* 元素入栈 */ - stack.push(1); - stack.push(3); - stack.push(2); - stack.push(5); - stack.push(4); - Console.WriteLine("栈 stack = " + String.Join(",", stack.toArray())); + /* 判断栈是否为空 */ + public bool isEmpty() + { + return size() == 0; + } - /* 访问栈顶元素 */ - int peek = stack.peek(); - Console.WriteLine("栈顶元素 peek = " + peek); + /* 入栈 */ + public void push(int num) + { + stack.Add(num); + } - /* 元素出栈 */ - int pop = stack.pop(); - Console.WriteLine("出栈元素 pop = " + pop + ",出栈后 stack = " + String.Join(",", stack.toArray())); + /* 出栈 */ + public int pop() + { + if (isEmpty()) + throw new Exception(); + var val = peek(); + stack.RemoveAt(size() - 1); + return val; + } - /* 获取栈的长度 */ - int size = stack.size(); - Console.WriteLine("栈的长度 size = " + size); + /* 访问栈顶元素 */ + public int peek() + { + if (isEmpty()) + throw new Exception(); + return stack[size() - 1]; + } - /* 判断是否为空 */ - bool isEmpty = stack.isEmpty(); - Console.WriteLine("栈是否为空 = " + isEmpty); - } + /* 将 List 转化为 Array 并返回 */ + public int[] toArray() + { + return stack.ToArray(); + } +} + +public class array_stack +{ + [Test] + public void Test() + { + /* 初始化栈 */ + ArrayStack stack = new ArrayStack(); + + /* 元素入栈 */ + stack.push(1); + stack.push(3); + stack.push(2); + stack.push(5); + stack.push(4); + Console.WriteLine("栈 stack = " + String.Join(",", stack.toArray())); + + /* 访问栈顶元素 */ + int peek = stack.peek(); + Console.WriteLine("栈顶元素 peek = " + peek); + + /* 元素出栈 */ + int pop = stack.pop(); + Console.WriteLine("出栈元素 pop = " + pop + ",出栈后 stack = " + String.Join(",", stack.toArray())); + + /* 获取栈的长度 */ + int size = stack.size(); + Console.WriteLine("栈的长度 size = " + size); + + /* 判断是否为空 */ + bool isEmpty = stack.isEmpty(); + Console.WriteLine("栈是否为空 = " + isEmpty); } } diff --git a/codes/csharp/chapter_stack_and_queue/deque.cs b/codes/csharp/chapter_stack_and_queue/deque.cs index d9f7a5098..47700f7c8 100644 --- a/codes/csharp/chapter_stack_and_queue/deque.cs +++ b/codes/csharp/chapter_stack_and_queue/deque.cs @@ -6,44 +6,43 @@ using NUnit.Framework; -namespace hello_algo.chapter_stack_and_queue +namespace hello_algo.chapter_stack_and_queue; + +public class deque { - public class deque + [Test] + public void Test() { - [Test] - public void Test() - { - /* 初始化双向队列 */ - // 在 C# 中,将链表 LinkedList 看作双向队列来使用 - LinkedList deque = new LinkedList(); + /* 初始化双向队列 */ + // 在 C# 中,将链表 LinkedList 看作双向队列来使用 + LinkedList deque = new LinkedList(); - /* 元素入队 */ - deque.AddLast(2); // 添加至队尾 - deque.AddLast(5); - deque.AddLast(4); - deque.AddFirst(3); // 添加至队首 - deque.AddFirst(1); - Console.WriteLine("双向队列 deque = " + String.Join(",", deque.ToArray())); + /* 元素入队 */ + 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); + /* 访问元素 */ + 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())); + /* 元素出队 */ + 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); + /* 获取双向队列的长度 */ + int size = deque.Count; + Console.WriteLine("双向队列长度 size = " + size); - /* 判断双向队列是否为空 */ - bool isEmpty = deque.Count == 0; - Console.WriteLine("双向队列是否为空 = " + isEmpty); - } + /* 判断双向队列是否为空 */ + bool isEmpty = deque.Count == 0; + Console.WriteLine("双向队列是否为空 = " + isEmpty); } } diff --git a/codes/csharp/chapter_stack_and_queue/linkedlist_queue.cs b/codes/csharp/chapter_stack_and_queue/linkedlist_queue.cs index 4ee650fdc..93141cbc4 100644 --- a/codes/csharp/chapter_stack_and_queue/linkedlist_queue.cs +++ b/codes/csharp/chapter_stack_and_queue/linkedlist_queue.cs @@ -7,118 +7,117 @@ using hello_algo.include; using NUnit.Framework; -namespace hello_algo.chapter_stack_and_queue +namespace hello_algo.chapter_stack_and_queue; + +/* 基于链表实现的队列 */ +class LinkedListQueue { - /* 基于链表实现的队列 */ - class LinkedListQueue + private ListNode? front, rear; // 头结点 front ,尾结点 rear + private int queSize = 0; + + public LinkedListQueue() { - private ListNode? front, rear; // 头结点 front ,尾结点 rear - private int queSize = 0; + front = null; + rear = null; + } - public LinkedListQueue() - { - front = null; - rear = null; - } + /* 获取队列的长度 */ + public int size() + { + return queSize; + } - /* 获取队列的长度 */ - public int size() - { - return queSize; - } + /* 判断队列是否为空 */ + public bool isEmpty() + { + return size() == 0; + } - /* 判断队列是否为空 */ - public bool isEmpty() + /* 入队 */ + public void push(int num) + { + // 尾结点后添加 num + ListNode node = new ListNode(num); + // 如果队列为空,则令头、尾结点都指向该结点 + if (front == null) { - return size() == 0; + front = node; + rear = node; + // 如果队列不为空,则将该结点添加到尾结点后 } + else if (rear != null) + { + rear.next = node; + rear = node; + } + queSize++; + } - /* 入队 */ - public void push(int num) - { - // 尾结点后添加 num - ListNode node = new ListNode(num); - // 如果队列为空,则令头、尾结点都指向该结点 - if (front == null) - { - front = node; - rear = node; - // 如果队列不为空,则将该结点添加到尾结点后 - } - else if (rear != null) - { - rear.next = node; - rear = node; - } - queSize++; - } + /* 出队 */ + public int poll() + { + int num = peek(); + // 删除头结点 + front = front?.next; + queSize--; + return num; + } - /* 出队 */ - public int poll() + /* 访问队首元素 */ + public int peek() + { + if (size() == 0 || front == null) + throw new Exception(); + return front.val; + } + + /* 将链表转化为 Array 并返回 */ + public int[] toArray() + { + if (front == null) + return Array.Empty(); + + ListNode node = front; + int[] res = new int[size()]; + for (int i = 0; i < res.Length; i++) { - int num = peek(); - // 删除头结点 - front = front?.next; - queSize--; - return num; + res[i] = node.val; + node = node.next; } + return res; + } +} + +public class linkedlist_queue +{ + [Test] + public void Test() + { + /* 初始化队列 */ + LinkedListQueue queue = new LinkedListQueue(); + + /* 元素入队 */ + queue.push(1); + queue.push(3); + queue.push(2); + queue.push(5); + queue.push(4); + Console.WriteLine("队列 queue = " + String.Join(",", queue.toArray())); /* 访问队首元素 */ - public int peek() - { - if (size() == 0 || front == null) - throw new Exception(); - return front.val; - } + int peek = queue.peek(); + Console.WriteLine("队首元素 peek = " + peek); - /* 将链表转化为 Array 并返回 */ - public int[] toArray() - { - if (front == null) - return Array.Empty(); + /* 元素出队 */ + int poll = queue.poll(); + Console.WriteLine("出队元素 poll = " + poll + ",出队后 queue = " + String.Join(",", queue.toArray())); - ListNode node = front; - int[] res = new int[size()]; - for (int i = 0; i < res.Length; i++) - { - res[i] = node.val; - node = node.next; - } - return res; - } + /* 获取队列的长度 */ + int size = queue.size(); + Console.WriteLine("队列长度 size = " + size); + + /* 判断队列是否为空 */ + bool isEmpty = queue.isEmpty(); + Console.WriteLine("队列是否为空 = " + isEmpty); } - - public class linkedlist_queue - { - [Test] - public void Test() - { - /* 初始化队列 */ - LinkedListQueue queue = new LinkedListQueue(); - - /* 元素入队 */ - queue.push(1); - queue.push(3); - queue.push(2); - queue.push(5); - queue.push(4); - Console.WriteLine("队列 queue = " + String.Join(",", queue.toArray())); - - /* 访问队首元素 */ - int peek = queue.peek(); - Console.WriteLine("队首元素 peek = " + peek); - - /* 元素出队 */ - int poll = queue.poll(); - Console.WriteLine("出队元素 poll = " + poll + ",出队后 queue = " + String.Join(",", queue.toArray())); - - /* 获取队列的长度 */ - int size = queue.size(); - Console.WriteLine("队列长度 size = " + size); - - /* 判断队列是否为空 */ - bool isEmpty = queue.isEmpty(); - Console.WriteLine("队列是否为空 = " + isEmpty); - } - } -} \ No newline at end of file +} diff --git a/codes/csharp/chapter_stack_and_queue/linkedlist_stack.cs b/codes/csharp/chapter_stack_and_queue/linkedlist_stack.cs index 78a409449..905491a92 100644 --- a/codes/csharp/chapter_stack_and_queue/linkedlist_stack.cs +++ b/codes/csharp/chapter_stack_and_queue/linkedlist_stack.cs @@ -7,107 +7,107 @@ using hello_algo.include; using NUnit.Framework; -namespace hello_algo.chapter_stack_and_queue +namespace hello_algo.chapter_stack_and_queue; + +/* 基于链表实现的栈 */ +class LinkedListStack { - class LinkedListStack + private ListNode? stackPeek; // 将头结点作为栈顶 + private int stkSize = 0; // 栈的长度 + + public LinkedListStack() { - private ListNode? stackPeek; // 将头结点作为栈顶 - private int stkSize = 0; // 栈的长度 + stackPeek = null; + } - public LinkedListStack() + /* 获取栈的长度 */ + public int size() + { + return stkSize; + } + + /* 判断栈是否为空 */ + public bool isEmpty() + { + return size() == 0; + } + + /* 入栈 */ + public void push(int num) + { + ListNode node = new ListNode(num); + node.next = stackPeek; + stackPeek = node; + stkSize++; + } + + /* 出栈 */ + public int pop() + { + if (stackPeek == null) + throw new Exception(); + + int num = peek(); + stackPeek = stackPeek.next; + stkSize--; + return num; + } + + /* 访问栈顶元素 */ + public int peek() + { + if (size() == 0 || stackPeek == null) + throw new Exception(); + return stackPeek.val; + } + + /* 将 List 转化为 Array 并返回 */ + public int[] toArray() + { + if (stackPeek == null) + return Array.Empty(); + + ListNode node = stackPeek; + int[] res = new int[size()]; + for (int i = res.Length - 1; i >= 0; i--) { - stackPeek = null; + res[i] = node.val; + node = node.next; } + return res; + } +} - /* 获取栈的长度 */ - public int size() - { - return stkSize; - } +public class linkedlist_stack +{ + [Test] + public void Test() + { + /* 初始化栈 */ + LinkedListStack stack = new LinkedListStack(); - /* 判断栈是否为空 */ - public bool isEmpty() - { - return size() == 0; - } - - /* 入栈 */ - public void push(int num) - { - ListNode node = new ListNode(num); - node.next = stackPeek; - stackPeek = node; - stkSize++; - } - - /* 出栈 */ - public int pop() - { - if (stackPeek == null) - throw new Exception(); - - int num = peek(); - stackPeek = stackPeek.next; - stkSize--; - return num; - } + /* 元素入栈 */ + stack.push(1); + stack.push(3); + stack.push(2); + stack.push(5); + stack.push(4); + Console.WriteLine("栈 stack = " + String.Join(",", stack.toArray())); /* 访问栈顶元素 */ - public int peek() - { - if (size() == 0 || stackPeek==null) - throw new Exception(); - return stackPeek.val; - } + int peek = stack.peek(); + Console.WriteLine("栈顶元素 peek = " + peek); - /* 将 List 转化为 Array 并返回 */ - public int[] toArray() - { - if (stackPeek == null) - return Array.Empty(); + /* 元素出栈 */ + int pop = stack.pop(); + Console.WriteLine("出栈元素 pop = " + pop + ",出栈后 stack = " + String.Join(",", stack.toArray())); - ListNode node = stackPeek; - int[] res = new int[size()]; - for (int i = res.Length - 1; i >= 0; i--) - { - res[i] = node.val; - node = node.next; - } - return res; - } + /* 获取栈的长度 */ + int size = stack.size(); + Console.WriteLine("栈的长度 size = " + size); + + /* 判断是否为空 */ + bool isEmpty = stack.isEmpty(); + Console.WriteLine("栈是否为空 = " + isEmpty); } - - public class linkedlist_stack - { - [Test] - public void Test() - { - /* 初始化栈 */ - LinkedListStack stack = new LinkedListStack(); - - /* 元素入栈 */ - stack.push(1); - stack.push(3); - stack.push(2); - stack.push(5); - stack.push(4); - Console.WriteLine("栈 stack = " + String.Join(",",stack.toArray())); - - /* 访问栈顶元素 */ - int peek = stack.peek(); - Console.WriteLine("栈顶元素 peek = " + peek); - - /* 元素出栈 */ - int pop = stack.pop(); - Console.WriteLine("出栈元素 pop = " + pop + ",出栈后 stack = " + String.Join(",",stack.toArray())); - - /* 获取栈的长度 */ - int size = stack.size(); - Console.WriteLine("栈的长度 size = " + size); - - /* 判断是否为空 */ - bool isEmpty = stack.isEmpty(); - Console.WriteLine("栈是否为空 = " + isEmpty); - } - } -} \ No newline at end of file +} diff --git a/codes/csharp/chapter_stack_and_queue/queue.cs b/codes/csharp/chapter_stack_and_queue/queue.cs index a5ce96953..4224daedc 100644 --- a/codes/csharp/chapter_stack_and_queue/queue.cs +++ b/codes/csharp/chapter_stack_and_queue/queue.cs @@ -6,40 +6,38 @@ using NUnit.Framework; -namespace hello_algo.chapter_stack_and_queue +namespace hello_algo.chapter_stack_and_queue; + +public class queue { - public class queue + [Test] + public void Test() { - [Test] - public void Test() - { - /* 初始化队列 */ - Queue queue = new(); + /* 初始化队列 */ + Queue queue = new(); - /* 元素入队 */ - queue.Enqueue(1); - queue.Enqueue(3); - queue.Enqueue(2); - queue.Enqueue(5); - queue.Enqueue(4); - Console.WriteLine("队列 queue = " + String.Join(",", queue.ToArray())); + /* 元素入队 */ + queue.Enqueue(1); + queue.Enqueue(3); + queue.Enqueue(2); + queue.Enqueue(5); + queue.Enqueue(4); + Console.WriteLine("队列 queue = " + String.Join(",", queue.ToArray())); - /* 访问队首元素 */ - int peek = queue.Peek(); - Console.WriteLine("队首元素 peek = " + peek); + /* 访问队首元素 */ + int peek = queue.Peek(); + Console.WriteLine("队首元素 peek = " + peek); - /* 元素出队 */ - int poll = queue.Dequeue(); - Console.WriteLine("出队元素 poll = " + poll + ",出队后 queue = " + String.Join(",", queue.ToArray())); + /* 元素出队 */ + int poll = queue.Dequeue(); + Console.WriteLine("出队元素 poll = " + poll + ",出队后 queue = " + String.Join(",", queue.ToArray())); - /* 获取队列的长度 */ - int size = queue.Count(); - Console.WriteLine("队列长度 size = " + size); + /* 获取队列的长度 */ + int size = queue.Count(); + Console.WriteLine("队列长度 size = " + size); - /* 判断队列是否为空 */ - bool isEmpty = queue.Count() == 0; - Console.WriteLine("队列是否为空 = " + isEmpty); - } + /* 判断队列是否为空 */ + bool isEmpty = queue.Count() == 0; + Console.WriteLine("队列是否为空 = " + isEmpty); } - } diff --git a/codes/csharp/chapter_stack_and_queue/stack.cs b/codes/csharp/chapter_stack_and_queue/stack.cs index c19666b72..56fc47f42 100644 --- a/codes/csharp/chapter_stack_and_queue/stack.cs +++ b/codes/csharp/chapter_stack_and_queue/stack.cs @@ -6,40 +6,39 @@ using NUnit.Framework; -namespace hello_algo.chapter_stack_and_queue +namespace hello_algo.chapter_stack_and_queue; + +public class stack { - public class stack + [Test] + public void Test() { - [Test] - public void Test() - { - /* 初始化栈 */ - Stack stack = new(); + /* 初始化栈 */ + Stack stack = new(); - /* 元素入栈 */ - stack.Push(1); - stack.Push(3); - stack.Push(2); - stack.Push(5); - stack.Push(4); - // 请注意,stack.ToArray() 得到的是倒序序列,即索引 0 为栈顶 - Console.WriteLine("栈 stack = " + string.Join(",", stack.ToArray())); + /* 元素入栈 */ + stack.Push(1); + stack.Push(3); + stack.Push(2); + stack.Push(5); + stack.Push(4); + // 请注意,stack.ToArray() 得到的是倒序序列,即索引 0 为栈顶 + Console.WriteLine("栈 stack = " + string.Join(",", stack.ToArray())); - /* 访问栈顶元素 */ - int peek = stack.Peek(); - Console.WriteLine("栈顶元素 peek = " + peek); + /* 访问栈顶元素 */ + int peek = stack.Peek(); + Console.WriteLine("栈顶元素 peek = " + peek); - /* 元素出栈 */ - int pop = stack.Pop(); - Console.WriteLine("出栈元素 pop = " + pop + ",出栈后 stack = " + string.Join(",", stack.ToArray())); + /* 元素出栈 */ + int pop = stack.Pop(); + Console.WriteLine("出栈元素 pop = " + pop + ",出栈后 stack = " + string.Join(",", stack.ToArray())); - /* 获取栈的长度 */ - int size = stack.Count(); - Console.WriteLine("栈的长度 size = " + size); + /* 获取栈的长度 */ + int size = stack.Count(); + Console.WriteLine("栈的长度 size = " + size); - /* 判断是否为空 */ - bool isEmpty = stack.Count() == 0; - Console.WriteLine("栈是否为空 = " + isEmpty); - } + /* 判断是否为空 */ + bool isEmpty = stack.Count() == 0; + Console.WriteLine("栈是否为空 = " + isEmpty); } -} \ No newline at end of file +} diff --git a/codes/csharp/chapter_tree/avl_tree.cs b/codes/csharp/chapter_tree/avl_tree.cs index 19ac8b85a..ffe1f690b 100644 --- a/codes/csharp/chapter_tree/avl_tree.cs +++ b/codes/csharp/chapter_tree/avl_tree.cs @@ -7,254 +7,253 @@ using hello_algo.include; using NUnit.Framework; -namespace hello_algo.chapter_tree +namespace hello_algo.chapter_tree; + +/* AVL 树 */ +class AVLTree { - /* AVL 树 */ - class AVLTree + public TreeNode? root; // 根结点 + + /* 获取结点高度 */ + public int height(TreeNode? node) { - public TreeNode? root; // 根结点 - - /* 获取结点高度 */ - public int height(TreeNode? node) - { - // 空结点高度为 -1 ,叶结点高度为 0 - return node == null ? -1 : node.height; - } - - /* 更新结点高度 */ - private void updateHeight(TreeNode node) - { - // 结点高度等于最高子树高度 + 1 - node.height = Math.Max(height(node.left), height(node.right)) + 1; - } - - /* 获取平衡因子 */ - public int balanceFactor(TreeNode? node) - { - // 空结点平衡因子为 0 - if (node == null) return 0; - // 结点平衡因子 = 左子树高度 - 右子树高度 - return height(node.left) - height(node.right); - } - - /* 右旋操作 */ - TreeNode? rightRotate(TreeNode? node) - { - TreeNode? child = node.left; - TreeNode? grandChild = child?.right; - // 以 child 为原点,将 node 向右旋转 - child.right = node; - node.left = grandChild; - // 更新结点高度 - updateHeight(node); - updateHeight(child); - // 返回旋转后子树的根结点 - return child; - } - - /* 左旋操作 */ - TreeNode? leftRotate(TreeNode? node) - { - TreeNode? child = node.right; - TreeNode? grandChild = child?.left; - // 以 child 为原点,将 node 向左旋转 - child.left = node; - node.right = grandChild; - // 更新结点高度 - updateHeight(node); - updateHeight(child); - // 返回旋转后子树的根结点 - return child; - } - - /* 执行旋转操作,使该子树重新恢复平衡 */ - TreeNode? rotate(TreeNode? node) - { - // 获取结点 node 的平衡因子 - int balanceFactorInt = balanceFactor(node); - // 左偏树 - if (balanceFactorInt > 1) - { - if (balanceFactor(node.left) >= 0) - { - // 右旋 - return rightRotate(node); - } - else - { - // 先左旋后右旋 - node.left = leftRotate(node?.left); - return rightRotate(node); - } - } - // 右偏树 - if (balanceFactorInt < -1) - { - if (balanceFactor(node.right) <= 0) - { - // 左旋 - return leftRotate(node); - } - else - { - // 先右旋后左旋 - node.right = rightRotate(node?.right); - return leftRotate(node); - } - } - // 平衡树,无需旋转,直接返回 - return node; - } - - /* 插入结点 */ - public TreeNode? insert(int val) - { - root = insertHelper(root, val); - return root; - } - - /* 递归插入结点(辅助函数) */ - private TreeNode? insertHelper(TreeNode? node, int val) - { - if (node == null) return new TreeNode(val); - /* 1. 查找插入位置,并插入结点 */ - 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; - } - - /* 删除结点 */ - public TreeNode? remove(int val) - { - root = removeHelper(root, val); - return root; - } - - /* 递归删除结点(辅助函数) */ - private TreeNode? removeHelper(TreeNode? node, int val) - { - if (node == null) return null; - /* 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 == null || node.right == null) - { - TreeNode? child = node.left != null ? node.left : node.right; - // 子结点数量 = 0 ,直接删除 node 并返回 - if (child == null) - return null; - // 子结点数量 = 1 ,直接删除 node - else - node = child; - } - else - { - // 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 - TreeNode? temp = getInOrderNext(node.right); - node.right = removeHelper(node.right, temp.val); - node.val = temp.val; - } - } - updateHeight(node); // 更新结点高度 - /* 2. 执行旋转操作,使该子树重新恢复平衡 */ - node = rotate(node); - // 返回子树的根结点 - return node; - } - - /* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */ - private TreeNode? getInOrderNext(TreeNode? node) - { - if (node == null) return node; - // 循环访问左子结点,直到叶结点时为最小结点,跳出 - while (node.left != null) - { - node = node.left; - } - return node; - } - - /* 查找结点 */ - public TreeNode? search(int val) - { - TreeNode? cur = root; - // 循环查找,越过叶结点后跳出 - while (cur != null) - { - // 目标结点在 cur 的右子树中 - if (cur.val < val) - cur = cur.right; - // 目标结点在 cur 的左子树中 - else if (cur.val > val) - cur = cur.left; - // 找到目标结点,跳出循环 - else - break; - } - // 返回目标结点 - return cur; - } + // 空结点高度为 -1 ,叶结点高度为 0 + return node == null ? -1 : node.height; } - public class avl_tree + /* 更新结点高度 */ + private void updateHeight(TreeNode node) { - static void testInsert(AVLTree tree, int val) + // 结点高度等于最高子树高度 + 1 + node.height = Math.Max(height(node.left), height(node.right)) + 1; + } + + /* 获取平衡因子 */ + public int balanceFactor(TreeNode? node) + { + // 空结点平衡因子为 0 + if (node == null) return 0; + // 结点平衡因子 = 左子树高度 - 右子树高度 + return height(node.left) - height(node.right); + } + + /* 右旋操作 */ + TreeNode? rightRotate(TreeNode? node) + { + TreeNode? child = node.left; + TreeNode? grandChild = child?.right; + // 以 child 为原点,将 node 向右旋转 + child.right = node; + node.left = grandChild; + // 更新结点高度 + updateHeight(node); + updateHeight(child); + // 返回旋转后子树的根结点 + return child; + } + + /* 左旋操作 */ + TreeNode? leftRotate(TreeNode? node) + { + TreeNode? child = node.right; + TreeNode? grandChild = child?.left; + // 以 child 为原点,将 node 向左旋转 + child.left = node; + node.right = grandChild; + // 更新结点高度 + updateHeight(node); + updateHeight(child); + // 返回旋转后子树的根结点 + return child; + } + + /* 执行旋转操作,使该子树重新恢复平衡 */ + TreeNode? rotate(TreeNode? node) + { + // 获取结点 node 的平衡因子 + int balanceFactorInt = balanceFactor(node); + // 左偏树 + if (balanceFactorInt > 1) { - tree.insert(val); - Console.WriteLine("\n插入结点 " + val + " 后,AVL 树为"); - PrintUtil.PrintTree(tree.root); + if (balanceFactor(node.left) >= 0) + { + // 右旋 + return rightRotate(node); + } + else + { + // 先左旋后右旋 + node.left = leftRotate(node?.left); + return rightRotate(node); + } } - - static void testRemove(AVLTree tree, int val) + // 右偏树 + if (balanceFactorInt < -1) { - tree.remove(val); - Console.WriteLine("\n删除结点 " + val + " 后,AVL 树为"); - PrintUtil.PrintTree(tree.root); + if (balanceFactor(node.right) <= 0) + { + // 左旋 + return leftRotate(node); + } + else + { + // 先右旋后左旋 + node.right = rightRotate(node?.right); + return leftRotate(node); + } } + // 平衡树,无需旋转,直接返回 + return node; + } - [Test] - public void Test() + /* 插入结点 */ + public TreeNode? insert(int val) + { + root = insertHelper(root, val); + return root; + } + + /* 递归插入结点(辅助函数) */ + private TreeNode? insertHelper(TreeNode? node, int val) + { + if (node == null) return new TreeNode(val); + /* 1. 查找插入位置,并插入结点 */ + 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; + } + + /* 删除结点 */ + public TreeNode? remove(int val) + { + root = removeHelper(root, val); + return root; + } + + /* 递归删除结点(辅助函数) */ + private TreeNode? removeHelper(TreeNode? node, int val) + { + if (node == null) return null; + /* 1. 查找结点,并删除之 */ + if (val < node.val) + node.left = removeHelper(node.left, val); + else if (val > node.val) + node.right = removeHelper(node.right, val); + else { - /* 初始化空 AVL 树 */ - AVLTree avlTree = new AVLTree(); - - /* 插入结点 */ - // 请关注插入结点后,AVL 树是如何保持平衡的 - testInsert(avlTree, 1); - testInsert(avlTree, 2); - testInsert(avlTree, 3); - testInsert(avlTree, 4); - testInsert(avlTree, 5); - testInsert(avlTree, 8); - testInsert(avlTree, 7); - testInsert(avlTree, 9); - testInsert(avlTree, 10); - testInsert(avlTree, 6); - - /* 插入重复结点 */ - testInsert(avlTree, 7); - - /* 删除结点 */ - // 请关注删除结点后,AVL 树是如何保持平衡的 - testRemove(avlTree, 8); // 删除度为 0 的结点 - testRemove(avlTree, 5); // 删除度为 1 的结点 - testRemove(avlTree, 4); // 删除度为 2 的结点 - - /* 查询结点 */ - TreeNode? node = avlTree.search(7); - Console.WriteLine("\n查找到的结点对象为 " + node + ",结点值 = " + node?.val); + if (node.left == null || node.right == null) + { + TreeNode? child = node.left != null ? node.left : node.right; + // 子结点数量 = 0 ,直接删除 node 并返回 + if (child == null) + return null; + // 子结点数量 = 1 ,直接删除 node + else + node = child; + } + else + { + // 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 + TreeNode? temp = getInOrderNext(node.right); + node.right = removeHelper(node.right, temp.val); + node.val = temp.val; + } } + updateHeight(node); // 更新结点高度 + /* 2. 执行旋转操作,使该子树重新恢复平衡 */ + node = rotate(node); + // 返回子树的根结点 + return node; + } + + /* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */ + private TreeNode? getInOrderNext(TreeNode? node) + { + if (node == null) return node; + // 循环访问左子结点,直到叶结点时为最小结点,跳出 + while (node.left != null) + { + node = node.left; + } + return node; + } + + /* 查找结点 */ + public TreeNode? search(int val) + { + TreeNode? cur = root; + // 循环查找,越过叶结点后跳出 + while (cur != null) + { + // 目标结点在 cur 的右子树中 + if (cur.val < val) + cur = cur.right; + // 目标结点在 cur 的左子树中 + else if (cur.val > val) + cur = cur.left; + // 找到目标结点,跳出循环 + else + break; + } + // 返回目标结点 + return cur; + } +} + +public class avl_tree +{ + static void testInsert(AVLTree tree, int val) + { + tree.insert(val); + Console.WriteLine("\n插入结点 " + val + " 后,AVL 树为"); + PrintUtil.PrintTree(tree.root); + } + + static void testRemove(AVLTree tree, int val) + { + tree.remove(val); + Console.WriteLine("\n删除结点 " + val + " 后,AVL 树为"); + PrintUtil.PrintTree(tree.root); + } + + [Test] + public void Test() + { + /* 初始化空 AVL 树 */ + AVLTree avlTree = new AVLTree(); + + /* 插入结点 */ + // 请关注插入结点后,AVL 树是如何保持平衡的 + testInsert(avlTree, 1); + testInsert(avlTree, 2); + testInsert(avlTree, 3); + testInsert(avlTree, 4); + testInsert(avlTree, 5); + testInsert(avlTree, 8); + testInsert(avlTree, 7); + testInsert(avlTree, 9); + testInsert(avlTree, 10); + testInsert(avlTree, 6); + + /* 插入重复结点 */ + testInsert(avlTree, 7); + + /* 删除结点 */ + // 请关注删除结点后,AVL 树是如何保持平衡的 + testRemove(avlTree, 8); // 删除度为 0 的结点 + testRemove(avlTree, 5); // 删除度为 1 的结点 + testRemove(avlTree, 4); // 删除度为 2 的结点 + + /* 查询结点 */ + TreeNode? node = avlTree.search(7); + Console.WriteLine("\n查找到的结点对象为 " + node + ",结点值 = " + node?.val); } } diff --git a/codes/csharp/chapter_tree/binary_search_tree.cs b/codes/csharp/chapter_tree/binary_search_tree.cs index 2821b29bb..e37a0ea06 100644 --- a/codes/csharp/chapter_tree/binary_search_tree.cs +++ b/codes/csharp/chapter_tree/binary_search_tree.cs @@ -7,176 +7,177 @@ using hello_algo.include; using NUnit.Framework; -namespace hello_algo.chapter_tree +namespace hello_algo.chapter_tree; + +class BinarySearchTree { - class BinarySearchTree + TreeNode? root; + + public BinarySearchTree(int[] nums) { - TreeNode? root; + Array.Sort(nums); // 排序数组 + root = buildTree(nums, 0, nums.Length - 1); // 构建二叉搜索树 + } - public BinarySearchTree(int[] nums) { - Array.Sort(nums); // 排序数组 - root = buildTree(nums, 0, nums.Length - 1); // 构建二叉搜索树 - } + /* 获取二叉树根结点 */ + public TreeNode? getRoot() + { + return root; + } - /* 获取二叉树根结点 */ - public TreeNode? getRoot() { - return root; - } + /* 构建二叉搜索树 */ + public TreeNode? buildTree(int[] nums, int i, int j) + { + if (i > j) return null; + // 将数组中间结点作为根结点 + int mid = (i + j) / 2; + TreeNode root = new TreeNode(nums[mid]); + // 递归建立左子树和右子树 + root.left = buildTree(nums, i, mid - 1); + root.right = buildTree(nums, mid + 1, j); + return root; + } - /* 构建二叉搜索树 */ - public TreeNode? buildTree(int[] nums, int i, int j) { - if (i > j) return null; - // 将数组中间结点作为根结点 - int mid = (i + j) / 2; - TreeNode root = new TreeNode(nums[mid]); - // 递归建立左子树和右子树 - root.left = buildTree(nums, i, mid - 1); - root.right = buildTree(nums, mid + 1, j); - return root; - } - - /* 查找结点 */ - public TreeNode? search(int num) + /* 查找结点 */ + public TreeNode? search(int num) + { + TreeNode? cur = root; + // 循环查找,越过叶结点后跳出 + while (cur != null) { - TreeNode? cur = root; - // 循环查找,越过叶结点后跳出 - while (cur != null) - { - // 目标结点在 cur 的右子树中 - if (cur.val < num) cur = cur.right; - // 目标结点在 cur 的左子树中 - else if (cur.val > num) cur = cur.left; - // 找到目标结点,跳出循环 - else break; - } - // 返回目标结点 - return cur; + // 目标结点在 cur 的右子树中 + if (cur.val < num) cur = cur.right; + // 目标结点在 cur 的左子树中 + else if (cur.val > num) cur = cur.left; + // 找到目标结点,跳出循环 + else break; + } + // 返回目标结点 + return cur; + } + + /* 插入结点 */ + public TreeNode? insert(int num) + { + // 若树为空,直接提前返回 + if (root == null) return null; + TreeNode? cur = root, pre = null; + // 循环查找,越过叶结点后跳出 + while (cur != null) + { + // 找到重复结点,直接返回 + if (cur.val == num) return null; + pre = cur; + // 插入位置在 cur 的右子树中 + if (cur.val < num) cur = cur.right; + // 插入位置在 cur 的左子树中 + else cur = cur.left; } - /* 插入结点 */ - public TreeNode? insert(int num) + // 插入结点 val + TreeNode node = new TreeNode(num); + if (pre != null) { - // 若树为空,直接提前返回 - if (root == null) return null; - TreeNode? cur = root, pre = null; - // 循环查找,越过叶结点后跳出 - while (cur != null) - { - // 找到重复结点,直接返回 - if (cur.val == num) return null; - pre = cur; - // 插入位置在 cur 的右子树中 - if (cur.val < num) cur = cur.right; - // 插入位置在 cur 的左子树中 - else cur = cur.left; - } - - // 插入结点 val - TreeNode node = new TreeNode(num); - if (pre != null) - { - if (pre.val < num) pre.right = node; - else pre.left = node; - } - return node; + if (pre.val < num) pre.right = node; + else pre.left = node; } + return node; + } - /* 删除结点 */ - public TreeNode? remove(int num) + /* 删除结点 */ + public TreeNode? remove(int num) + { + // 若树为空,直接提前返回 + if (root == null) return null; + TreeNode? cur = root, pre = null; + // 循环查找,越过叶结点后跳出 + while (cur != null) { - // 若树为空,直接提前返回 - if (root == null) return null; - TreeNode? cur = root, pre = null; - // 循环查找,越过叶结点后跳出 - while (cur != null) + // 找到待删除结点,跳出循环 + if (cur.val == num) break; + pre = cur; + // 待删除结点在 cur 的右子树中 + if (cur.val < num) cur = cur.right; + // 待删除结点在 cur 的左子树中 + else cur = cur.left; + } + // 若无待删除结点,则直接返回 + if (cur == null || pre == null) return null; + // 子结点数量 = 0 or 1 + if (cur.left == null || cur.right == null) + { + // 当子结点数量 = 0 / 1 时, child = null / 该子结点 + TreeNode? child = cur.left != null ? cur.left : cur.right; + // 删除结点 cur + if (pre.left == cur) { - // 找到待删除结点,跳出循环 - if (cur.val == num) break; - pre = cur; - // 待删除结点在 cur 的右子树中 - if (cur.val < num) cur = cur.right; - // 待删除结点在 cur 的左子树中 - else cur = cur.left; + pre.left = child; } - // 若无待删除结点,则直接返回 - if (cur == null || pre == null) return null; - // 子结点数量 = 0 or 1 - if (cur.left == null || cur.right == null) - { - // 当子结点数量 = 0 / 1 时, child = null / 该子结点 - TreeNode? child = cur.left != null ? cur.left : cur.right; - // 删除结点 cur - if (pre.left == cur) - { - pre.left = child; - } - else - { - pre.right = child; - } - - } - // 子结点数量 = 2 else { - // 获取中序遍历中 cur 的下一个结点 - TreeNode? nex = getInOrderNext(cur.right); - if (nex != null) - { - int tmp = nex.val; - // 递归删除结点 nex - remove(nex.val); - // 将 nex 的值复制给 cur - cur.val = tmp; - } + pre.right = child; } - return cur; } - - /* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */ - private TreeNode? getInOrderNext(TreeNode? root) + // 子结点数量 = 2 + else { - if (root == null) return root; - // 循环访问左子结点,直到叶结点时为最小结点,跳出 - while (root.left != null) + // 获取中序遍历中 cur 的下一个结点 + TreeNode? nex = getInOrderNext(cur.right); + if (nex != null) { - root = root.left; + int tmp = nex.val; + // 递归删除结点 nex + remove(nex.val); + // 将 nex 的值复制给 cur + cur.val = tmp; } - return root; } + return cur; } - public class binary_search_tree + /* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */ + private TreeNode? getInOrderNext(TreeNode? root) { - [Test] - public void Test() + if (root == null) return root; + // 循环访问左子结点,直到叶结点时为最小结点,跳出 + while (root.left != null) { - /* 初始化二叉搜索树 */ - int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - BinarySearchTree bst = new BinarySearchTree(nums); - Console.WriteLine("\n初始化的二叉树为\n"); - PrintUtil.PrintTree(bst.getRoot()); - - /* 查找结点 */ - TreeNode? node = bst.search(7); - Console.WriteLine("\n查找到的结点对象为 " + node + ",结点值 = " + node.val); - - /* 插入结点 */ - node = bst.insert(16); - Console.WriteLine("\n插入结点 16 后,二叉树为\n"); - PrintUtil.PrintTree(bst.getRoot()); - - /* 删除结点 */ - bst.remove(1); - Console.WriteLine("\n删除结点 1 后,二叉树为\n"); - PrintUtil.PrintTree(bst.getRoot()); - bst.remove(2); - Console.WriteLine("\n删除结点 2 后,二叉树为\n"); - PrintUtil.PrintTree(bst.getRoot()); - bst.remove(4); - Console.WriteLine("\n删除结点 4 后,二叉树为\n"); - PrintUtil.PrintTree(bst.getRoot()); + root = root.left; } + return root; + } +} + +public class binary_search_tree +{ + [Test] + public void Test() + { + /* 初始化二叉搜索树 */ + int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + BinarySearchTree bst = new BinarySearchTree(nums); + Console.WriteLine("\n初始化的二叉树为\n"); + PrintUtil.PrintTree(bst.getRoot()); + + /* 查找结点 */ + TreeNode? node = bst.search(7); + Console.WriteLine("\n查找到的结点对象为 " + node + ",结点值 = " + node.val); + + /* 插入结点 */ + node = bst.insert(16); + Console.WriteLine("\n插入结点 16 后,二叉树为\n"); + PrintUtil.PrintTree(bst.getRoot()); + + /* 删除结点 */ + bst.remove(1); + Console.WriteLine("\n删除结点 1 后,二叉树为\n"); + PrintUtil.PrintTree(bst.getRoot()); + bst.remove(2); + Console.WriteLine("\n删除结点 2 后,二叉树为\n"); + PrintUtil.PrintTree(bst.getRoot()); + bst.remove(4); + Console.WriteLine("\n删除结点 4 后,二叉树为\n"); + PrintUtil.PrintTree(bst.getRoot()); } } diff --git a/codes/csharp/chapter_tree/binary_tree.cs b/codes/csharp/chapter_tree/binary_tree.cs index 275a69f93..1f77929fd 100644 --- a/codes/csharp/chapter_tree/binary_tree.cs +++ b/codes/csharp/chapter_tree/binary_tree.cs @@ -7,40 +7,38 @@ using hello_algo.include; using NUnit.Framework; -namespace hello_algo.chapter_tree +namespace hello_algo.chapter_tree; + +public class binary_tree { - - public class binary_tree + [Test] + public void Test() { - [Test] - public void Test() - { - /* 初始化二叉树 */ - // 初始化结点 - TreeNode n1 = new TreeNode(1); - TreeNode n2 = new TreeNode(2); - TreeNode n3 = new TreeNode(3); - TreeNode n4 = new TreeNode(4); - TreeNode n5 = new TreeNode(5); - // 构建引用指向(即指针) - n1.left = n2; - n1.right = n3; - n2.left = n4; - n2.right = n5; - Console.WriteLine("\n初始化二叉树\n"); - PrintUtil.PrintTree(n1); + /* 初始化二叉树 */ + // 初始化结点 + TreeNode n1 = new TreeNode(1); + TreeNode n2 = new TreeNode(2); + TreeNode n3 = new TreeNode(3); + TreeNode n4 = new TreeNode(4); + TreeNode n5 = new TreeNode(5); + // 构建引用指向(即指针) + n1.left = n2; + n1.right = n3; + n2.left = n4; + n2.right = n5; + Console.WriteLine("\n初始化二叉树\n"); + PrintUtil.PrintTree(n1); - /* 插入与删除结点 */ - TreeNode P = new TreeNode(0); - // 在 n1 -> n2 中间插入结点 P - n1.left = P; - P.left = n2; - Console.WriteLine("\n插入结点 P 后\n"); - PrintUtil.PrintTree(n1); - // 删除结点 P - n1.left = n2; - Console.WriteLine("\n删除结点 P 后\n"); - PrintUtil.PrintTree(n1); - } + /* 插入与删除结点 */ + TreeNode P = new TreeNode(0); + // 在 n1 -> n2 中间插入结点 P + n1.left = P; + P.left = n2; + Console.WriteLine("\n插入结点 P 后\n"); + PrintUtil.PrintTree(n1); + // 删除结点 P + n1.left = n2; + Console.WriteLine("\n删除结点 P 后\n"); + PrintUtil.PrintTree(n1); } -} \ No newline at end of file +} diff --git a/codes/csharp/chapter_tree/binary_tree_bfs.cs b/codes/csharp/chapter_tree/binary_tree_bfs.cs index 9a57dbc17..0cbbf62f5 100644 --- a/codes/csharp/chapter_tree/binary_tree_bfs.cs +++ b/codes/csharp/chapter_tree/binary_tree_bfs.cs @@ -7,42 +7,41 @@ using hello_algo.include; using NUnit.Framework; -namespace hello_algo.chapter_tree +namespace hello_algo.chapter_tree; + +public class binary_tree_bfs { - public class binary_tree_bfs + + /* 层序遍历 */ + public List hierOrder(TreeNode root) { - - /* 层序遍历 */ - public List hierOrder(TreeNode root) + // 初始化队列,加入根结点 + Queue queue = new(); + queue.Enqueue(root); + // 初始化一个列表,用于保存遍历序列 + List list = new(); + while (queue.Count != 0) { - // 初始化队列,加入根结点 - Queue queue = new(); - queue.Enqueue(root); - // 初始化一个列表,用于保存遍历序列 - List list = new(); - while (queue.Count != 0) - { - TreeNode node = queue.Dequeue(); // 队列出队 - list.Add(node.val); // 保存结点值 - if (node.left != null) - queue.Enqueue(node.left); // 左子结点入队 - if (node.right != null) - queue.Enqueue(node.right); // 右子结点入队 - } - return list; + TreeNode node = queue.Dequeue(); // 队列出队 + list.Add(node.val); // 保存结点值 + if (node.left != null) + queue.Enqueue(node.left); // 左子结点入队 + if (node.right != null) + queue.Enqueue(node.right); // 右子结点入队 } + return list; + } - [Test] - public void Test() - { - /* 初始化二叉树 */ - // 这里借助了一个从数组直接生成二叉树的函数 - TreeNode? root = TreeNode.ArrToTree(new int?[] { 1, 2, 3, 4, 5, 6, 7 }); - Console.WriteLine("\n初始化二叉树\n"); - PrintUtil.PrintTree(root); + [Test] + public void Test() + { + /* 初始化二叉树 */ + // 这里借助了一个从数组直接生成二叉树的函数 + TreeNode? root = TreeNode.ArrToTree(new int?[] { 1, 2, 3, 4, 5, 6, 7 }); + Console.WriteLine("\n初始化二叉树\n"); + PrintUtil.PrintTree(root); - List list = hierOrder(root); - Console.WriteLine("\n层序遍历的结点打印序列 = " + string.Join(",", list.ToArray())); - } + List list = hierOrder(root); + Console.WriteLine("\n层序遍历的结点打印序列 = " + string.Join(",", list.ToArray())); } } diff --git a/codes/csharp/chapter_tree/binary_tree_dfs.cs b/codes/csharp/chapter_tree/binary_tree_dfs.cs index f8669d782..e142fd585 100644 --- a/codes/csharp/chapter_tree/binary_tree_dfs.cs +++ b/codes/csharp/chapter_tree/binary_tree_dfs.cs @@ -7,62 +7,61 @@ using hello_algo.include; using NUnit.Framework; -namespace hello_algo.chapter_tree +namespace hello_algo.chapter_tree; + +public class binary_tree_dfs { - public class binary_tree_dfs + List list = new(); + + /* 前序遍历 */ + void preOrder(TreeNode? root) { - List list = new(); + if (root == null) return; + // 访问优先级:根结点 -> 左子树 -> 右子树 + list.Add(root.val); + preOrder(root.left); + preOrder(root.right); + } - /* 前序遍历 */ - void preOrder(TreeNode? root) - { - if (root == null) return; - // 访问优先级:根结点 -> 左子树 -> 右子树 - list.Add(root.val); - preOrder(root.left); - preOrder(root.right); - } + /* 中序遍历 */ + void inOrder(TreeNode? root) + { + if (root == null) return; + // 访问优先级:左子树 -> 根结点 -> 右子树 + inOrder(root.left); + list.Add(root.val); + inOrder(root.right); + } - /* 中序遍历 */ - void inOrder(TreeNode? root) - { - if (root == null) return; - // 访问优先级:左子树 -> 根结点 -> 右子树 - inOrder(root.left); - list.Add(root.val); - inOrder(root.right); - } + /* 后序遍历 */ + void postOrder(TreeNode? root) + { + if (root == null) return; + // 访问优先级:左子树 -> 右子树 -> 根结点 + postOrder(root.left); + postOrder(root.right); + list.Add(root.val); + } - /* 后序遍历 */ - void postOrder(TreeNode? root) - { - if (root == null) return; - // 访问优先级:左子树 -> 右子树 -> 根结点 - postOrder(root.left); - postOrder(root.right); - list.Add(root.val); - } + [Test] + public void Test() + { + /* 初始化二叉树 */ + // 这里借助了一个从数组直接生成二叉树的函数 + TreeNode? root = TreeNode.ArrToTree(new int?[] { 1, 2, 3, 4, 5, 6, 7 }); + Console.WriteLine("\n初始化二叉树\n"); + PrintUtil.PrintTree(root); - [Test] - public void Test() - { - /* 初始化二叉树 */ - // 这里借助了一个从数组直接生成二叉树的函数 - TreeNode? root = TreeNode.ArrToTree(new int?[] { 1, 2, 3, 4, 5, 6, 7 }); - Console.WriteLine("\n初始化二叉树\n"); - PrintUtil.PrintTree(root); + list.Clear(); + preOrder(root); + Console.WriteLine("\n前序遍历的结点打印序列 = " + string.Join(",", list.ToArray())); - list.Clear(); - preOrder(root); - Console.WriteLine("\n前序遍历的结点打印序列 = " + string.Join(",", list.ToArray())); + list.Clear(); + inOrder(root); + Console.WriteLine("\n中序遍历的结点打印序列 = " + string.Join(",", list.ToArray())); - list.Clear(); - inOrder(root); - Console.WriteLine("\n中序遍历的结点打印序列 = " + string.Join(",", list.ToArray())); - - list.Clear(); - postOrder(root); - Console.WriteLine("\n后序遍历的结点打印序列 = " + string.Join(",", list.ToArray())); - } + list.Clear(); + postOrder(root); + Console.WriteLine("\n后序遍历的结点打印序列 = " + string.Join(",", list.ToArray())); } } diff --git a/codes/csharp/hello-algo.csproj b/codes/csharp/hello-algo.csproj index d96d728b1..45cb9a39e 100644 --- a/codes/csharp/hello-algo.csproj +++ b/codes/csharp/hello-algo.csproj @@ -11,8 +11,8 @@ - - + + diff --git a/codes/csharp/include/ListNode.cs b/codes/csharp/include/ListNode.cs index 0fe2913eb..eb724b677 100644 --- a/codes/csharp/include/ListNode.cs +++ b/codes/csharp/include/ListNode.cs @@ -2,67 +2,66 @@ // Created Time: 2022-12-16 // Author: mingXta (1195669834@qq.com) -namespace hello_algo.include +namespace hello_algo.include; + +/// +/// Definition for a singly-linked list node +/// +public class ListNode { + public int val; + public ListNode? next; + /// - /// Definition for a singly-linked list node + /// Generate a linked list with an array /// - public class ListNode + /// + public ListNode(int x) { - public int val; - public ListNode? next; - - /// - /// Generate a linked list with an array - /// - /// - public ListNode(int x) - { - val = x; - } - - /// - /// Generate a linked list with an array - /// - /// - /// - public static ListNode? ArrToLinkedList(int[] arr) - { - ListNode dum = new ListNode(0); - ListNode head = dum; - foreach (int val in arr) - { - head.next = new ListNode(val); - head = head.next; - } - return dum.next; - } - - /// - /// Get a list node with specific value from a linked list - /// - /// - /// - /// - public static ListNode? GetListNode(ListNode? head, int val) - { - while (head != null && head.val != val) - { - head = head.next; - } - return head; - } - - public override string? ToString() - { - List list = new(); - var head = this; - while (head != null) - { - list.Add(head.val.ToString()); - head = head.next; - } - return string.Join("->", list); - } + val = x; } -} \ No newline at end of file + + /// + /// Generate a linked list with an array + /// + /// + /// + public static ListNode? ArrToLinkedList(int[] arr) + { + ListNode dum = new ListNode(0); + ListNode head = dum; + foreach (int val in arr) + { + head.next = new ListNode(val); + head = head.next; + } + return dum.next; + } + + /// + /// Get a list node with specific value from a linked list + /// + /// + /// + /// + public static ListNode? GetListNode(ListNode? head, int val) + { + while (head != null && head.val != val) + { + head = head.next; + } + return head; + } + + public override string? ToString() + { + List list = new(); + var head = this; + while (head != null) + { + list.Add(head.val.ToString()); + head = head.next; + } + return string.Join("->", list); + } +} diff --git a/codes/csharp/include/PrintUtil.cs b/codes/csharp/include/PrintUtil.cs index 06e85a93c..3a8f6f35e 100644 --- a/codes/csharp/include/PrintUtil.cs +++ b/codes/csharp/include/PrintUtil.cs @@ -4,121 +4,119 @@ * Author: haptear (haptear@hotmail.com) */ -namespace hello_algo.include +namespace hello_algo.include; + +public class Trunk { - public class Trunk + public Trunk? prev; + public String str; + + public Trunk(Trunk? prev, String str) { - public Trunk? prev; - public String str; + this.prev = prev; + this.str = str; + } +}; - public Trunk(Trunk? prev, String str) - { - this.prev = prev; - this.str = str; - } - }; - - public class PrintUtil +public class PrintUtil +{ + /** + * Print a linked list + * @param head + */ + public static void PrintLinkedList(ListNode head) { - /** - * Print a linked list - * @param head - */ - public static void PrintLinkedList(ListNode head) + List list = new(); + while (head != null) { - List list = new(); - while (head != null) - { - list.Add(head.val.ToString()); - head = head.next; - } - Console.Write(String.Join(" -> ", list)); - } - - /** - * The interface of the tree printer - * This tree printer is borrowed from TECHIE DELIGHT - * https://www.techiedelight.com/c-program-print-binary-tree/ - * @param root - */ - public static void PrintTree(TreeNode? root) - { - PrintTree(root, null, false); - } - - /** - * Print a binary tree - * @param root - * @param prev - * @param isLeft - */ - public static void PrintTree(TreeNode? root, Trunk? prev, bool isLeft) - { - if (root == null) - { - return; - } - - String prev_str = " "; - Trunk trunk = new Trunk(prev, prev_str); - - PrintTree(root.right, trunk, true); - - if (prev == null) - { - trunk.str = "———"; - } - else if (isLeft) - { - trunk.str = "/———"; - prev_str = " |"; - } - else - { - trunk.str = "\\———"; - prev.str = prev_str; - } - - showTrunks(trunk); - Console.WriteLine(" " + root.val); - - if (prev != null) - { - prev.str = prev_str; - } - trunk.str = " |"; - - PrintTree(root.left, trunk, false); - } - - /** - * Helper function to print branches of the binary tree - * @param p - */ - public static void showTrunks(Trunk? p) - { - if (p == null) - { - return; - } - - showTrunks(p.prev); - Console.Write(p.str); - } - - /** - * Print a hash map - * @param - * @param - * @param map - */ - public static void printHashMap(Dictionary map) where K : notnull - { - foreach (var kv in map.Keys) - { - Console.WriteLine(kv.ToString() + " -> " + map[kv]?.ToString()); - } + list.Add(head.val.ToString()); + head = head.next; } + Console.Write(String.Join(" -> ", list)); } + /** + * The interface of the tree printer + * This tree printer is borrowed from TECHIE DELIGHT + * https://www.techiedelight.com/c-program-print-binary-tree/ + * @param root + */ + public static void PrintTree(TreeNode? root) + { + PrintTree(root, null, false); + } + + /** + * Print a binary tree + * @param root + * @param prev + * @param isLeft + */ + public static void PrintTree(TreeNode? root, Trunk? prev, bool isLeft) + { + if (root == null) + { + return; + } + + String prev_str = " "; + Trunk trunk = new Trunk(prev, prev_str); + + PrintTree(root.right, trunk, true); + + if (prev == null) + { + trunk.str = "———"; + } + else if (isLeft) + { + trunk.str = "/———"; + prev_str = " |"; + } + else + { + trunk.str = "\\———"; + prev.str = prev_str; + } + + showTrunks(trunk); + Console.WriteLine(" " + root.val); + + if (prev != null) + { + prev.str = prev_str; + } + trunk.str = " |"; + + PrintTree(root.left, trunk, false); + } + + /** + * Helper function to print branches of the binary tree + * @param p + */ + public static void showTrunks(Trunk? p) + { + if (p == null) + { + return; + } + + showTrunks(p.prev); + Console.Write(p.str); + } + + /** + * Print a hash map + * @param + * @param + * @param map + */ + public static void printHashMap(Dictionary map) where K : notnull + { + foreach (var kv in map.Keys) + { + Console.WriteLine(kv.ToString() + " -> " + map[kv]?.ToString()); + } + } } diff --git a/codes/csharp/include/TreeNode.cs b/codes/csharp/include/TreeNode.cs index 9cd0ac92c..905abc323 100644 --- a/codes/csharp/include/TreeNode.cs +++ b/codes/csharp/include/TreeNode.cs @@ -4,95 +4,94 @@ * Author: haptear (haptear@hotmail.com) */ -namespace hello_algo.include +namespace hello_algo.include; + +public class TreeNode { - public class TreeNode + public int val; // 结点值 + public int height; // 结点高度 + public TreeNode? left; // 左子结点引用 + public TreeNode? right; // 右子结点引用 + + public TreeNode(int x) { - public int val; // 结点值 - public int height; // 结点高度 - public TreeNode? left; // 左子结点引用 - public TreeNode? right; // 右子结点引用 + val = x; + } - public TreeNode(int x) + /** + * Generate a binary tree given an array + * @param arr + * @return + */ + public static TreeNode? ArrToTree(int?[] arr) + { + if (arr.Length == 0 || arr[0] == null) + return null; + + TreeNode root = new TreeNode((int)arr[0]); + Queue queue = new Queue(); + queue.Enqueue(root); + int i = 0; + while (queue.Count != 0) { - val = x; - } - - /** - * Generate a binary tree given an array - * @param arr - * @return - */ - public static TreeNode? ArrToTree(int?[] arr) - { - if (arr.Length == 0 || arr[0] == null) - return null; - - TreeNode root = new TreeNode((int) arr[0]); - Queue queue = new Queue(); - queue.Enqueue(root); - int i = 0; - while (queue.Count != 0) + TreeNode node = queue.Dequeue(); + if (++i >= arr.Length) break; + if (arr[i] != null) { - TreeNode node = queue.Dequeue(); - if (++i >= arr.Length) break; - if (arr[i] != null) - { - node.left = new TreeNode((int) arr[i]); - queue.Enqueue(node.left); - } - if (++i >= arr.Length) break; - if (arr[i] != null) - { - node.right = new TreeNode((int) arr[i]); - queue.Enqueue(node.right); - } + node.left = new TreeNode((int)arr[i]); + queue.Enqueue(node.left); } + if (++i >= arr.Length) break; + if (arr[i] != null) + { + node.right = new TreeNode((int)arr[i]); + queue.Enqueue(node.right); + } + } + return root; + } + + /** + * Serialize a binary tree to a list + * @param root + * @return + */ + public static List TreeToList(TreeNode root) + { + List list = new(); + if (root == null) return list; + Queue queue = new(); + while (queue.Count != 0) + { + TreeNode? node = queue.Dequeue(); + if (node != null) + { + list.Add(node.val); + queue.Enqueue(node.left); + queue.Enqueue(node.right); + } + else + { + list.Add(null); + } + } + return list; + } + + /** + * Get a tree node with specific value in a binary tree + * @param root + * @param val + * @return + */ + public static TreeNode? GetTreeNode(TreeNode? root, int val) + { + if (root == null) + return null; + if (root.val == val) return root; - } - - /** - * Serialize a binary tree to a list - * @param root - * @return - */ - public static List TreeToList(TreeNode root) - { - List list = new(); - if (root == null) return list; - Queue queue = new(); - while (queue.Count != 0) - { - TreeNode? node = queue.Dequeue(); - if (node != null) - { - list.Add(node.val); - queue.Enqueue(node.left); - queue.Enqueue(node.right); - } - else - { - list.Add(null); - } - } - return list; - } - - /** - * Get a tree node with specific value in a binary tree - * @param root - * @param val - * @return - */ - public static TreeNode? GetTreeNode(TreeNode? root, int val) - { - if (root == null) - return null; - if (root.val == val) - return root; - TreeNode? left = GetTreeNode(root.left, val); - TreeNode? right = GetTreeNode(root.right, val); - return left != null ? left : right; - } + TreeNode? left = GetTreeNode(root.left, val); + TreeNode? right = GetTreeNode(root.right, val); + return left != null ? left : right; } } diff --git a/docs/chapter_array_and_linkedlist/array.md b/docs/chapter_array_and_linkedlist/array.md index f2cce92a0..d9a702d8e 100755 --- a/docs/chapter_array_and_linkedlist/array.md +++ b/docs/chapter_array_and_linkedlist/array.md @@ -166,16 +166,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "C#" ```csharp title="array.cs" - /* 随机返回一个数组元素 */ - int RandomAccess(int[] nums) - { - Random random=new(); - // 在区间 [0, nums.Length) 中随机抽取一个数字 - int randomIndex = random.Next(nums.Length); - // 获取并返回随机元素 - int randomNum = nums[randomIndex]; - return randomNum; - } + [class]{array}-[func]{randomAccess} ``` === "Swift" @@ -256,19 +247,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "C#" ```csharp title="array.cs" - /* 扩展数组长度 */ - int[] Extend(int[] nums, int enlarge) - { - // 初始化一个扩展长度后的数组 - int[] res = new int[nums.Length + enlarge]; - // 将原数组中的所有元素复制到新数组 - for (int i = 0; i < nums.Length; i++) - { - res[i] = nums[i]; - } - // 返回扩展后的新数组 - return res; - } + [class]{array}-[func]{extend} ``` === "Swift" @@ -373,26 +352,9 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "C#" ```csharp title="array.cs" - /* 在数组的索引 index 处插入元素 num */ - void Insert(int[] nums, int num, int index) - { - // 把索引 index 以及之后的所有元素向后移动一位 - for (int i = nums.Length - 1; i > index; i--) - { - nums[i] = nums[i - 1]; - } - // 将 num 赋给 index 处元素 - nums[index] = num; - } - /* 删除索引 index 处元素 */ - void Remove(int[] nums, int index) - { - // 把索引 index 之后的所有元素向前移动一位 - for (int i = index; i < nums.Length - 1; i++) - { - nums[i] = nums[i + 1]; - } - } + [class]{array}-[func]{insert} + + [class]{array}-[func]{remove} ``` === "Swift" @@ -487,21 +449,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "C#" ```csharp title="array.cs" - /* 遍历数组 */ - void Traverse(int[] nums) - { - int count = 0; - // 通过索引遍历数组 - for (int i = 0; i < nums.Length; i++) - { - count++; - } - // 直接遍历数组 - foreach (int num in nums) - { - count++; - } - } + [class]{array}-[func]{traverse} ``` === "Swift" @@ -586,16 +534,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "C#" ```csharp title="array.cs" - /* 在数组中查找指定元素 */ - int Find(int[] nums, int target) - { - for (int i = 0; i < nums.Length; i++) - { - if (nums[i] == target) - return i; - } - return -1; - } + [class]{array}-[func]{find} ``` === "Swift" diff --git a/docs/chapter_array_and_linkedlist/linked_list.md b/docs/chapter_array_and_linkedlist/linked_list.md index de6570a2b..50fdd609c 100755 --- a/docs/chapter_array_and_linkedlist/linked_list.md +++ b/docs/chapter_array_and_linkedlist/linked_list.md @@ -435,24 +435,9 @@ comments: true === "C#" ```csharp title="linked_list.cs" - // 在链表的结点 n0 之后插入结点 P - void Insert(ListNode n0, ListNode P) - { - ListNode n1 = n0.next; - n0.next = P; - P.next = n1; - } + [class]{linked_list}-[func]{insert} - // 删除链表的结点 n0 之后的首个结点 - void Remove(ListNode n0) - { - if (n0.next == null) - return; - // n0 -> P -> n1 - ListNode P = n0.next; - ListNode n1 = P.next; - n0.next = n1; - } + [class]{linked_list}-[func]{remove} ``` === "Swift" @@ -556,17 +541,7 @@ comments: true === "C#" ```csharp title="linked_list.cs" - // 访问链表中索引为 index 的结点 - ListNode Access(ListNode head, int index) - { - for (int i = 0; i < index; i++) - { - if (head == null) - return null; - head = head.next; - } - return head; - } + [class]{linked_list}-[func]{access} ``` === "Swift" @@ -652,19 +627,7 @@ comments: true === "C#" ```csharp title="linked_list.cs" - // 在链表中查找值为 target 的首个结点 - int Find(ListNode head, int target) - { - int index = 0; - while (head != null) - { - if (head.val == target) - return index; - head = head.next; - index++; - } - return -1; - } + [class]{linked_list}-[func]{find} ``` === "Swift" diff --git a/docs/chapter_array_and_linkedlist/list.md b/docs/chapter_array_and_linkedlist/list.md index 52b40b5ea..798c6bf9c 100755 --- a/docs/chapter_array_and_linkedlist/list.md +++ b/docs/chapter_array_and_linkedlist/list.md @@ -854,103 +854,7 @@ comments: true === "C#" ```csharp title="my_list.cs" - class MyList - { - private int[] nums; // 数组(存储列表元素) - private int capacity = 10; // 列表容量 - private int size = 0; // 列表长度(即当前元素数量) - private int extendRatio = 2; // 每次列表扩容的倍数 - - /* 构造函数 */ - public MyList() - { - nums = new int[capacity]; - } - - /* 获取列表长度(即当前元素数量)*/ - public int Size() - { - return size; - } - - /* 获取列表容量 */ - public int Capacity() - { - return capacity; - } - - /* 访问元素 */ - public int Get(int index) - { - // 索引如果越界则抛出异常,下同 - if (index < 0 || index >= size) - throw new IndexOutOfRangeException("索引越界"); - return nums[index]; - } - - /* 更新元素 */ - public void Set(int index, int num) - { - if (index < 0 || index >= size) - throw new IndexOutOfRangeException("索引越界"); - nums[index] = num; - } - - /* 尾部添加元素 */ - public void Add(int num) - { - // 元素数量超出容量时,触发扩容机制 - if (size == Capacity()) - ExtendCapacity(); - nums[size] = num; - // 更新元素数量 - size++; - } - - /* 中间插入元素 */ - public void Insert(int index, int num) - { - if (index < 0 || index >= size) - throw new IndexOutOfRangeException("索引越界"); - // 元素数量超出容量时,触发扩容机制 - if (size == Capacity()) - ExtendCapacity(); - // 将索引 index 以及之后的元素都向后移动一位 - for (int j = size - 1; j >= index; j--) - { - nums[j + 1] = nums[j]; - } - nums[index] = num; - // 更新元素数量 - size++; - } - - /* 删除元素 */ - public int Remove(int index) - { - if (index < 0 || index >= size) - throw new IndexOutOfRangeException("索引越界"); - int num = nums[index]; - // 将索引 index 之后的元素都向前移动一位 - for (int j = index; j < size - 1; j++) - { - nums[j] = nums[j + 1]; - } - // 更新元素数量 - size--; - // 返回被删除元素 - return num; - } - - /* 列表扩容 */ - public void ExtendCapacity() - { - // 新建一个长度为 size 的数组,并将原数组拷贝到新数组 - System.Array.Resize(ref nums, Capacity() * extendRatio); - // 更新列表容量 - capacity = nums.Length; - } - } + [class]{MyList}-[func]{} ``` === "Swift" diff --git a/docs/chapter_computational_complexity/space_complexity.md b/docs/chapter_computational_complexity/space_complexity.md index 73155fee2..e375994d1 100755 --- a/docs/chapter_computational_complexity/space_complexity.md +++ b/docs/chapter_computational_complexity/space_complexity.md @@ -641,25 +641,7 @@ $$ === "C#" ```csharp title="space_complexity.cs" - /* 常数阶 */ - void constant(int n) - { - // 常量、变量、对象占用 O(1) 空间 - int a = 0; - int b = 0; - int[] nums = new int[10000]; - ListNode node = new ListNode(0); - // 循环中的变量占用 O(1) 空间 - for (int i = 0; i < n; i++) - { - int c = 0; - } - // 循环中的函数占用 O(1) 空间 - for (int i = 0; i < n; i++) - { - function(); - } - } + [class]{space_complexity}-[func]{constant} ``` === "Swift" @@ -759,24 +741,7 @@ $$ === "C#" ```csharp title="space_complexity.cs" - /* 线性阶 */ - void linear(int n) - { - // 长度为 n 的数组占用 O(n) 空间 - int[] nums = new int[n]; - // 长度为 n 的列表占用 O(n) 空间 - List nodes = new(); - for (int i = 0; i < n; i++) - { - nodes.Add(new ListNode(i)); - } - // 长度为 n 的哈希表占用 O(n) 空间 - Dictionary map = new(); - for (int i = 0; i < n; i++) - { - map.Add(i, i.ToString()); - } - } + [class]{space_complexity}-[func]{linear} ``` === "Swift" @@ -866,13 +831,7 @@ $$ === "C#" ```csharp title="space_complexity.cs" - /* 线性阶(递归实现) */ - void linearRecur(int n) - { - Console.WriteLine("递归 n = " + n); - if (n == 1) return; - linearRecur(n - 1); - } + [class]{space_complexity}-[func]{linearRecur} ``` === "Swift" @@ -952,23 +911,7 @@ $$ === "C#" ```csharp title="space_complexity.cs" - /* 平方阶 */ - void quadratic(int n) - { - // 矩阵占用 O(n^2) 空间 - int[,] numMatrix = new int[n, n]; - // 二维列表占用 O(n^2) 空间 - List> numList = new(); - for (int i = 0; i < n; i++) - { - List tmp = new(); - for (int j = 0; j < n; j++) - { - tmp.Add(0); - } - numList.Add(tmp); - } - } + [class]{space_complexity}-[func]{quadratic} ``` === "Swift" @@ -1053,14 +996,7 @@ $$ === "C#" ```csharp title="space_complexity.cs" - /* 平方阶(递归实现) */ - int quadraticRecur(int n) - { - if (n <= 0) return 0; - // 数组 nums 长度为 n, n-1, ..., 2, 1 - int[] nums = new int[n]; - return quadraticRecur(n - 1); - } + [class]{space_complexity}-[func]{quadraticRecur} ``` === "Swift" @@ -1143,15 +1079,7 @@ $$ === "C#" ```csharp title="space_complexity.cs" - /* 指数阶(建立满二叉树) */ - TreeNode? buildTree(int n) - { - if (n == 0) return null; - TreeNode root = new TreeNode(0); - root.left = buildTree(n - 1); - root.right = buildTree(n - 1); - return root; - } + [class]{space_complexity}-[func]{buildTree} ``` === "Swift" diff --git a/docs/chapter_computational_complexity/space_time_tradeoff.md b/docs/chapter_computational_complexity/space_time_tradeoff.md index b29d34168..da84f069b 100755 --- a/docs/chapter_computational_complexity/space_time_tradeoff.md +++ b/docs/chapter_computational_complexity/space_time_tradeoff.md @@ -86,23 +86,7 @@ comments: true === "C#" ```csharp title="leetcode_two_sum.cs" - class SolutionBruteForce - { - public int[] twoSum(int[] nums, int target) - { - int size = nums.Length; - // 两层循环,时间复杂度 O(n^2) - for (int i = 0; i < size - 1; i++) - { - for (int j = i + 1; j < size; j++) - { - if (nums[i] + nums[j] == target) - return new int[] { i, j }; - } - } - return new int[0]; - } - } + [class]{leetcode_two_sum}-[func]{twoSumBruteForce} ``` === "Swift" @@ -195,25 +179,7 @@ comments: true === "C#" ```csharp title="leetcode_two_sum.cs" - class SolutionHashMap - { - public int[] twoSum(int[] nums, int target) - { - int size = nums.Length; - // 辅助哈希表,空间复杂度 O(n) - Dictionary dic = new(); - // 单层循环,时间复杂度 O(n) - for (int i = 0; i < size; i++) - { - if (dic.ContainsKey(target - nums[i])) - { - return new int[] { dic[target - nums[i]], i }; - } - dic.Add(nums[i], i); - } - return new int[0]; - } - } + [class]{leetcode_two_sum}-[func]{twoSumHashTable} ``` === "Swift" diff --git a/docs/chapter_computational_complexity/time_complexity.md b/docs/chapter_computational_complexity/time_complexity.md index aed9958cc..2e4010bb2 100755 --- a/docs/chapter_computational_complexity/time_complexity.md +++ b/docs/chapter_computational_complexity/time_complexity.md @@ -854,15 +854,7 @@ $$ === "C#" ```csharp title="time_complexity.cs" - /* 常数阶 */ - int constant(int n) - { - int count = 0; - int size = 100000; - for (int i = 0; i < size; i++) - count++; - return count; - } + [class]{time_complexity}-[func]{constant} ``` === "Swift" @@ -950,14 +942,7 @@ $$ === "C#" ```csharp title="time_complexity.cs" - /* 线性阶 */ - int linear(int n) - { - int count = 0; - for (int i = 0; i < n; i++) - count++; - return count; - } + [class]{time_complexity}-[func]{linear} ``` === "Swift" @@ -1047,17 +1032,7 @@ $$ === "C#" ```csharp title="time_complexity.cs" - /* 线性阶(遍历数组) */ - int arrayTraversal(int[] nums) - { - int count = 0; - // 循环次数与数组长度成正比 - foreach(int num in nums) - { - count++; - } - return count; - } + [class]{time_complexity}-[func]{arrayTraversal} ``` === "Swift" @@ -1149,20 +1124,7 @@ $$ === "C#" ```csharp title="time_complexity.cs" - /* 平方阶 */ - int quadratic(int n) - { - int count = 0; - // 循环次数与数组长度成平方关系 - for (int i = 0; i < n; i++) - { - for (int j = 0; j < n; j++) - { - count++; - } - } - return count; - } + [class]{time_complexity}-[func]{quadratic} ``` === "Swift" @@ -1280,29 +1242,7 @@ $$ === "C#" ```csharp title="time_complexity.cs" - /* 平方阶(冒泡排序) */ - int bubbleSort(int[] nums) - { - int count = 0; // 计数器 - // 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for (int i = nums.Length - 1; i > 0; i--) - { - // 内循环:冒泡操作 - for (int j = 0; j < i; j++) - { - if (nums[j] > nums[j + 1]) - { - // 交换 nums[j] 与 nums[j + 1] - int tmp = nums[j]; - nums[j] = nums[j + 1]; - nums[j + 1] = tmp; - count += 3; // 元素交换包含 3 个单元操作 - } - } - } - return count; - } - + [class]{time_complexity}-[func]{bubbleSort} ``` === "Swift" @@ -1414,22 +1354,7 @@ $$ === "C#" ```csharp title="time_complexity.cs" - /* 指数阶(循环实现) */ - int exponential(int n) - { - int count = 0, 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; - } + [class]{time_complexity}-[func]{exponential} ``` === "Swift" @@ -1520,12 +1445,7 @@ $$ === "C#" ```csharp title="time_complexity.cs" - /* 指数阶(递归实现) */ - int expRecur(int n) - { - if (n == 1) return 1; - return expRecur(n - 1) + expRecur(n - 1) + 1; - } + [class]{time_complexity}-[func]{expRecur} ``` === "Swift" @@ -1613,17 +1533,7 @@ $$ === "C#" ```csharp title="time_complexity.cs" - /* 对数阶(循环实现) */ - int logarithmic(float n) - { - int count = 0; - while (n > 1) - { - n = n / 2; - count++; - } - return count; - } + [class]{time_complexity}-[func]{logarithmic} ``` === "Swift" @@ -1710,12 +1620,7 @@ $$ === "C#" ```csharp title="time_complexity.cs" - /* 对数阶(递归实现) */ - int logRecur(float n) - { - if (n <= 1) return 0; - return logRecur(n / 2) + 1; - } + [class]{time_complexity}-[func]{logRecur} ``` === "Swift" @@ -1806,18 +1711,7 @@ $$ === "C#" ```csharp title="time_complexity.cs" - /* 线性对数阶 */ - 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; - } + [class]{time_complexity}-[func]{linearLogRecur} ``` === "Swift" @@ -1921,18 +1815,7 @@ $$ === "C#" ```csharp title="time_complexity.cs" - /* 阶乘阶(递归实现) */ - int factorialRecur(int n) - { - if (n == 0) return 1; - int count = 0; - // 从 1 个分裂出 n 个 - for (int i = 0; i < n; i++) - { - count += factorialRecur(n - 1); - } - return count; - } + [class]{time_complexity}-[func]{factorialRecur} ``` === "Swift" @@ -2146,40 +2029,9 @@ $$ === "C#" ```csharp title="worst_best_time_complexity.cs" - /* 生成一个数组,元素为 { 1, 2, ..., n },顺序被打乱 */ - int[] randomNumbers(int n) - { - int[] nums = new int[n]; - // 生成数组 nums = { 1, 2, 3, ..., n } - for (int i = 0; i < n; i++) - { - nums[i] = i + 1; - } + [class]{worst_best_time_complexity}-[func]{randomNumbers} - // 随机打乱数组元素 - for (int i = 0; i < nums.Length; i++) - { - var index = new Random().Next(i, nums.Length); - var tmp = nums[i]; - var ran = nums[index]; - nums[i] = ran; - nums[index] = tmp; - } - return nums; - } - - /* 查找数组 nums 中数字 1 所在索引 */ - int findOne(int[] nums) - { - for (int i = 0; i < nums.Length; i++) - { - // 当元素 1 在数组头部时,达到最佳时间复杂度 O(1) - // 当元素 1 在数组尾部时,达到最差时间复杂度 O(n) - if (nums[i] == 1) - return i; - } - return -1; - } + [class]{worst_best_time_complexity}-[func]{findOne} ``` === "Swift" diff --git a/docs/chapter_graph/graph_operations.md b/docs/chapter_graph/graph_operations.md index 2ce8e2f11..e153ba57d 100644 --- a/docs/chapter_graph/graph_operations.md +++ b/docs/chapter_graph/graph_operations.md @@ -160,7 +160,7 @@ comments: true === "C#" ```csharp title="graph_adjacency_matrix.cs" - + [class]{GraphAdjMat}-[func]{} ``` === "Swift" @@ -409,7 +409,9 @@ comments: true === "C#" ```csharp title="graph_adjacency_list.cs" + [class]{Vertex}-[func]{} + [class]{GraphAdjList}-[func]{} ``` === "Swift" diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index 2437a9332..739a8efff 100755 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -513,60 +513,9 @@ $$ === "C#" ```csharp title="array_hash_map.cs" - /* 键值对 int->String */ - class Entry - { - public int key; - public String val; - public Entry(int key, String val) - { - this.key = key; - this.val = val; - } - } - - /* 基于数组简易实现的哈希表 */ - class ArrayHashMap - { - private List bucket; - public ArrayHashMap() - { - // 初始化一个长度为 100 的桶(数组) - bucket = new (); - for (int i = 0; i < 100; i++) - { - bucket.Add(null); - } - } - /* 哈希函数 */ - private int hashFunc(int key) - { - int index = key % 100; - return index; - } - /* 查询操作 */ - public String? get(int key) - { - int index = hashFunc(key); - Entry? pair = bucket[index]; - if (pair == null) return null; - return pair.val; - } - /* 添加操作 */ - public void put(int key, String val) - { - Entry pair = new Entry(key, val); - int index = hashFunc(key); - bucket[index]=pair; - } - /* 删除操作 */ - public void remove(int key) - { - int index = hashFunc(key); - // 置为 null ,代表删除 - bucket[index]=null; - } - } + [class]{Entry}-[func]{} + + [class]{ArrayHashMap}-[func]{} ``` === "Swift" diff --git a/docs/chapter_heap/heap.md b/docs/chapter_heap/heap.md index 693c84fa4..988e5fd4b 100644 --- a/docs/chapter_heap/heap.md +++ b/docs/chapter_heap/heap.md @@ -344,7 +344,11 @@ comments: true === "C#" ```csharp title="my_heap.cs" + [class]{MaxHeap}-[func]{left} + [class]{MaxHeap}-[func]{right} + + [class]{MaxHeap}-[func]{parent} ``` === "Swift" @@ -415,7 +419,7 @@ comments: true === "C#" ```csharp title="my_heap.cs" - + [class]{MaxHeap}-[func]{peek} ``` === "Swift" @@ -531,7 +535,9 @@ comments: true === "C#" ```csharp title="my_heap.cs" + [class]{MaxHeap}-[func]{push} + [class]{MaxHeap}-[func]{siftUp} ``` === "Swift" @@ -682,7 +688,9 @@ comments: true === "C#" ```csharp title="my_heap.cs" + [class]{MaxHeap}-[func]{poll} + [class]{MaxHeap}-[func]{siftDown} ``` === "Swift" @@ -759,7 +767,7 @@ comments: true === "C#" ```csharp title="my_heap.cs" - + [class]{MaxHeap}-[func]{MaxHeap} ``` === "Swift" diff --git a/docs/chapter_searching/binary_search.md b/docs/chapter_searching/binary_search.md index 161e14526..759b18fc2 100755 --- a/docs/chapter_searching/binary_search.md +++ b/docs/chapter_searching/binary_search.md @@ -113,25 +113,7 @@ $$ === "C#" ```csharp title="binary_search.cs" - /* 二分查找(双闭区间) */ - int binarySearch(int[] nums, int target) - { - // 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 - int i = 0, j = nums.Length - 1; - // 循环,当搜索区间为空时跳出(当 i > j 时为空) - while (i <= j) - { - int m = (i + j) / 2; // 计算中点索引 m - if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中 - i = m + 1; - else if (nums[m] > target) // 此情况说明 target 在区间 [i, m-1] 中 - j = m - 1; - else // 找到目标元素,返回其索引 - return m; - } - // 未找到目标元素,返回 -1 - return -1; - } + [class]{binary_search}-[func]{binarySearch} ``` === "Swift" @@ -212,25 +194,7 @@ $$ === "C#" ```csharp title="binary_search.cs" - /* 二分查找(左闭右开) */ - int binarySearch1(int[] nums, int target) - { - // 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 - int i = 0, j = nums.Length; - // 循环,当搜索区间为空时跳出(当 i = j 时为空) - while (i < j) - { - int m = (i + j) / 2; // 计算中点索引 m - if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中 - i = m + 1; - else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中 - j = m; - else // 找到目标元素,返回其索引 - return m; - } - // 未找到目标元素,返回 -1 - return -1; - } + [class]{binary_search}-[func]{binarySearch1} ``` === "Swift" diff --git a/docs/chapter_searching/hashing_search.md b/docs/chapter_searching/hashing_search.md index 09ce835cd..89d865ae2 100755 --- a/docs/chapter_searching/hashing_search.md +++ b/docs/chapter_searching/hashing_search.md @@ -70,13 +70,7 @@ comments: true === "C#" ```csharp title="hashing_search.cs" - /* 哈希查找(数组) */ - int hashingSearchArray(Dictionary map, int target) - { - // 哈希表的 key: 目标元素,value: 索引 - // 若哈希表中无此 key ,返回 -1 - return map.GetValueOrDefault(target, -1); - } + [class]{hashing_search}-[func]{hashingSearchArray} ``` === "Swift" @@ -149,14 +143,7 @@ comments: true === "C#" ```csharp title="hashing_search.cs" - /* 哈希查找(链表) */ - ListNode? hashingSearchLinkedList(Dictionary map, int target) - { - - // 哈希表的 key: 目标结点值,value: 结点对象 - // 若哈希表中无此 key ,返回 null - return map.GetValueOrDefault(target); - } + [class]{hashing_search}-[func]{hashingSearchLinkedList} ``` === "Swift" diff --git a/docs/chapter_searching/linear_search.md b/docs/chapter_searching/linear_search.md index 0d18b2233..11591e306 100755 --- a/docs/chapter_searching/linear_search.md +++ b/docs/chapter_searching/linear_search.md @@ -68,20 +68,7 @@ comments: true === "C#" ```csharp title="linear_search.cs" - /* 线性查找(数组) */ - int linearSearchArray(int[] nums, int target) - { - // 遍历数组 - for (int i = 0; i < nums.Length; i++) - { - // 找到目标元素,返回其索引 - if (nums[i] == target) - return i; - } - // 未找到目标元素,返回 -1 - return -1; - } - + [class]{linear_search}-[func]{linearSearchArray} ``` === "Swift" @@ -155,20 +142,7 @@ comments: true === "C#" ```csharp title="linear_search.cs" - /* 线性查找(链表) */ - ListNode? linearSearchLinkedList(ListNode head, int target) - { - // 遍历链表 - while (head != null) - { - // 找到目标结点,返回之 - if (head.val == target) - return head; - head = head.next; - } - // 未找到目标结点,返回 null - return null; - } + [class]{linear_search}-[func]{linearSearchLinkedList} ``` === "Swift" diff --git a/docs/chapter_sorting/bubble_sort.md b/docs/chapter_sorting/bubble_sort.md index 419a473e2..8512c6fc5 100755 --- a/docs/chapter_sorting/bubble_sort.md +++ b/docs/chapter_sorting/bubble_sort.md @@ -120,25 +120,7 @@ comments: true === "C#" ```csharp title="bubble_sort.cs" - /* 冒泡排序 */ - void bubbleSort(int[] nums) - { - // 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for (int i = nums.Length - 1; i > 0; i--) - { - // 内循环:冒泡操作 - for (int j = 0; j < i; j++) - { - if (nums[j] > nums[j + 1]) - { - // 交换 nums[j] 与 nums[j + 1] - int tmp = nums[j]; - nums[j] = nums[j + 1]; - nums[j + 1] = tmp; - } - } - } - } + [class]{bubble_sort}-[func]{bubbleSort} ``` === "Swift" @@ -252,28 +234,7 @@ comments: true === "C#" ```csharp title="bubble_sort.cs" - /* 冒泡排序(标志优化)*/ - void bubbleSortWithFlag(int[] nums) - { - // 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for (int i = nums.Length - 1; i > 0; i--) - { - bool flag = false; // 初始化标志位 - // 内循环:冒泡操作 - for (int j = 0; j < i; j++) - { - if (nums[j] > nums[j + 1]) - { - // 交换 nums[j] 与 nums[j + 1] - int tmp = nums[j]; - nums[j] = nums[j + 1]; - nums[j + 1] = tmp; - flag = true; // 记录交换元素 - } - } - if (!flag) break; // 此轮冒泡未交换任何元素,直接跳出 - } - } + [class]{bubble_sort}-[func]{bubbleSortWithFlag} ``` === "Swift" diff --git a/docs/chapter_sorting/insertion_sort.md b/docs/chapter_sorting/insertion_sort.md index 8db214a44..0281fd272 100755 --- a/docs/chapter_sorting/insertion_sort.md +++ b/docs/chapter_sorting/insertion_sort.md @@ -98,22 +98,7 @@ comments: true === "C#" ```csharp title="insertion_sort.cs" - /* 插入排序 */ - void insertionSort(int[] nums) - { - // 外循环:base = nums[1], nums[2], ..., nums[n-1] - for (int i = 1; i < nums.Length; i++) - { - int bas = nums[i], j = i - 1; - // 内循环:将 base 插入到左边的正确位置 - while (j >= 0 && nums[j] > bas) - { - nums[j + 1] = nums[j]; // 1. 将 nums[j] 向右移动一位 - j--; - } - nums[j + 1] = bas; // 2. 将 base 赋值到正确位置 - } - } + [class]{insertion_sort}-[func]{insertionSort} ``` === "Swift" diff --git a/docs/chapter_sorting/merge_sort.md b/docs/chapter_sorting/merge_sort.md index 6aa3063f5..e794996e5 100755 --- a/docs/chapter_sorting/merge_sort.md +++ b/docs/chapter_sorting/merge_sort.md @@ -264,46 +264,9 @@ comments: true === "C#" ```csharp title="merge_sort.cs" - /* 合并左子数组和右子数组 */ - // 左子数组区间 [left, mid] - // 右子数组区间 [mid + 1, right] - void merge(int[] nums, int left, int mid, int right) - { - // 初始化辅助数组 - int[] tmp = nums[left..(right + 1)]; - // 左子数组的起始索引和结束索引 - int leftStart = left - left, leftEnd = mid - left; - // 右子数组的起始索引和结束索引 - int rightStart = mid + 1 - left, rightEnd = right - left; - // i, j 分别指向左子数组、右子数组的首元素 - int i = leftStart, j = rightStart; - // 通过覆盖原数组 nums 来合并左子数组和右子数组 - for (int k = left; k <= right; k++) - { - // 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++ - if (i > leftEnd) - nums[k] = tmp[j++]; - // 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++ - else if (j > rightEnd || tmp[i] <= tmp[j]) - nums[k] = tmp[i++]; - // 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++ - else - nums[k] = tmp[j++]; - } - } + [class]{merge_sort}-[func]{merge} - /* 归并排序 */ - void mergeSort(int[] nums, int left, int right) - { - // 终止条件 - if (left >= right) return; // 当子数组长度为 1 时终止递归 - // 划分阶段 - int mid = (left + right) / 2; // 计算中点 - mergeSort(nums, left, mid); // 递归左子数组 - mergeSort(nums, mid + 1, right); // 递归右子数组 - // 合并阶段 - merge(nums, left, mid, right); - } + [class]{merge_sort}-[func]{mergeSort} ``` === "Swift" diff --git a/docs/chapter_sorting/quick_sort.md b/docs/chapter_sorting/quick_sort.md index 3ef6eac05..fdc847265 100755 --- a/docs/chapter_sorting/quick_sort.md +++ b/docs/chapter_sorting/quick_sort.md @@ -113,30 +113,9 @@ comments: true === "C#" ```csharp title="quick_sort.cs" - /* 元素交换 */ - void swap(int[] nums, int i, int j) - { - int tmp = nums[i]; - nums[i] = nums[j]; - nums[j] = tmp; - } + [class]{QuickSort}-[func]{swap} - /* 哨兵划分 */ - int partition(int[] nums, int left, int right) - { - // 以 nums[left] 作为基准数 - int i = left, j = right; - while (i < j) - { - while (i < j && nums[j] >= nums[left]) - j--; // 从右向左找首个小于基准数的元素 - while (i < j && nums[i] <= nums[left]) - i++; // 从左向右找首个大于基准数的元素 - swap(nums, i, j); // 交换这两个元素 - } - swap(nums, i, left); // 将基准数交换至两子数组的分界线 - return i; // 返回基准数的索引 - } + [class]{QuickSort}-[func]{partition} ``` === "Swift" @@ -225,19 +204,7 @@ comments: true === "C#" ```csharp title="quick_sort.cs" - /* 快速排序 */ - void quickSort(int[] nums, int left, int right) - { - // 子数组长度为 1 时终止递归 - if (left >= right) - return; - // 哨兵划分 - int pivot = partition(nums, left, right); - // 递归左子数组、右子数组 - quickSort(nums, left, pivot - 1); - quickSort(nums, pivot + 1, right); - } - + [class]{QuickSort}-[func]{quickSort} ``` === "Swift" @@ -355,29 +322,9 @@ comments: true === "C#" ```csharp title="quick_sort.cs" - /* 选取三个元素的中位数 */ - int medianThree(int[] nums, int left, int mid, int right) - { - // 使用了异或操作来简化代码 - // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right])) - return left; - else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right])) - return mid; - else - return right; - } + [class]{QuickSortMedian}-[func]{medianThree} - /* 哨兵划分(三数取中值) */ - int partition(int[] nums, int left, int right) - { - // 选取三个候选元素的中位数 - int med = medianThree(nums, left, (left + right) / 2, right); - // 将中位数交换至数组最左端 - swap(nums, left, med); - // 以 nums[left] 作为基准数 - // 下同省略... - } + [class]{QuickSortMedian}-[func]{partition} ``` === "Swift" @@ -460,27 +407,7 @@ comments: true === "C#" ```csharp title="quick_sort.cs" - /* 快速排序(尾递归优化) */ - void quickSort(int[] nums, int left, int right) - { - // 子数组长度为 1 时终止 - while (left < right) - { - // 哨兵划分操作 - int 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] - } - } - } + [class]{QuickSortTailCall}-[func]{quickSort} ``` === "Swift" diff --git a/docs/chapter_stack_and_queue/deque.md b/docs/chapter_stack_and_queue/deque.md index c84a05806..1956f5cf2 100644 --- a/docs/chapter_stack_and_queue/deque.md +++ b/docs/chapter_stack_and_queue/deque.md @@ -607,7 +607,9 @@ comments: true === "C#" ```csharp title="linkedlist_deque.cs" + [class]{ListNode}-[func]{} + [class]{LinkedListDeque}-[func]{} ``` === "Swift" diff --git a/docs/chapter_stack_and_queue/queue.md b/docs/chapter_stack_and_queue/queue.md index 87bc8d189..71ef6c75a 100755 --- a/docs/chapter_stack_and_queue/queue.md +++ b/docs/chapter_stack_and_queue/queue.md @@ -371,62 +371,7 @@ comments: true === "C#" ```csharp title="linkedlist_queue.cs" - /* 基于链表实现的队列 */ - class LinkedListQueue - { - private ListNode? front, rear; // 头结点 front ,尾结点 rear - private int queSize = 0; - public LinkedListQueue() - { - front = null; - rear = null; - } - /* 获取队列的长度 */ - public int size() - { - return queSize; - } - /* 判断队列是否为空 */ - public bool isEmpty() - { - return size() == 0; - } - /* 入队 */ - public void push(int num) - { - // 尾结点后添加 num - ListNode node = new ListNode(num); - // 如果队列为空,则令头、尾结点都指向该结点 - if (front == null) - { - front = node; - rear = node; - // 如果队列不为空,则将该结点添加到尾结点后 - } - else if (rear != null) - { - rear.next = node; - rear = node; - } - queSize++; - } - /* 出队 */ - public int poll() - { - int num = peek(); - // 删除头结点 - front = front?.next; - queSize--; - return num; - } - /* 访问队首元素 */ - public int peek() - { - if (size() == 0 || front == null) - throw new Exception(); - return front.val; - } - } + [class]{LinkedListQueue}-[func]{} ``` === "Swift" @@ -570,71 +515,7 @@ comments: true === "C#" ```csharp title="array_queue.cs" - /* 基于环形数组实现的队列 */ - class ArrayQueue - { - private int[] nums; // 用于存储队列元素的数组 - private int front; // 队首指针,指向队首元素 - private int queSize; // 队列长度 - - public ArrayQueue(int capacity) - { - nums = new int[capacity]; - front = queSize = 0; - } - - /* 获取队列的容量 */ - public int capacity() - { - return nums.Length; - } - - /* 获取队列的长度 */ - public int size() - { - return queSize; - } - - /* 判断队列是否为空 */ - public bool isEmpty() - { - return queSize == 0; - } - - /* 入队 */ - public void push(int num) - { - if (queSize == capacity()) - { - Console.WriteLine("队列已满"); - return; - } - // 计算尾指针,指向队尾索引 + 1 - // 通过取余操作,实现 rear 越过数组尾部后回到头部 - int rear = (front + queSize) % capacity(); - // 尾结点后添加 num - nums[rear] = num; - queSize++; - } - - /* 出队 */ - public int poll() - { - int num = peek(); - // 队首指针向后移动一位,若越过尾部则返回到数组头部 - front = (front + 1) % capacity(); - queSize--; - return num; - } - - /* 访问队首元素 */ - public int peek() - { - if (isEmpty()) - throw new Exception(); - return nums[front]; - } - } + [class]{ArrayQueue}-[func]{} ``` === "Swift" diff --git a/docs/chapter_stack_and_queue/stack.md b/docs/chapter_stack_and_queue/stack.md index 68acaceb1..7d7c93004 100755 --- a/docs/chapter_stack_and_queue/stack.md +++ b/docs/chapter_stack_and_queue/stack.md @@ -374,49 +374,7 @@ comments: true === "C#" ```csharp title="linkedlist_stack.cs" - /* 基于链表实现的栈 */ - class LinkedListStack - { - private ListNode stackPeek; // 将头结点作为栈顶 - private int stkSize = 0; // 栈的长度 - public LinkedListStack() - { - stackPeek = null; - } - /* 获取栈的长度 */ - public int size() - { - return stkSize; - } - /* 判断栈是否为空 */ - public bool isEmpty() - { - return size() == 0; - } - /* 入栈 */ - public void push(int num) - { - ListNode node = new ListNode(num); - node.next = stackPeek; - stackPeek = node; - stkSize++; - } - /* 出栈 */ - public int pop() - { - int num = peek(); - stackPeek = stackPeek?.next; - stkSize--; - return num; - } - /* 访问栈顶元素 */ - public int peek() - { - if (size() == 0) - throw new Exception(); - return stackPeek.val; - } - } + [class]{LinkedListStack}-[func]{} ``` === "Swift" @@ -537,47 +495,7 @@ comments: true === "C#" ```csharp title="array_stack.cs" - /* 基于数组实现的栈 */ - class ArrayStack - { - private List stack; - public ArrayStack() - { - // 初始化列表(动态数组) - stack = new(); - } - /* 获取栈的长度 */ - public int size() - { - return stack.Count(); - } - /* 判断栈是否为空 */ - public bool isEmpty() - { - return size() == 0; - } - /* 入栈 */ - public void push(int num) - { - stack.Add(num); - } - /* 出栈 */ - public int pop() - { - if (isEmpty()) - throw new Exception(); - var val = peek(); - stack.RemoveAt(size() - 1); - return val; - } - /* 访问栈顶元素 */ - public int peek() - { - if (isEmpty()) - throw new Exception(); - return stack[size() - 1]; - } - } + [class]{ArrayStack}-[func]{} ``` === "Swift" diff --git a/docs/chapter_tree/avl_tree.md b/docs/chapter_tree/avl_tree.md index 8d16a9556..e498978b2 100755 --- a/docs/chapter_tree/avl_tree.md +++ b/docs/chapter_tree/avl_tree.md @@ -253,19 +253,9 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "C#" ```csharp title="avl_tree.cs" - /* 获取结点高度 */ - public int height(TreeNode? node) - { - // 空结点高度为 -1 ,叶结点高度为 0 - return node == null ? -1 : node.height; - } + [class]{AVLTree}-[func]{height} - /* 更新结点高度 */ - private void updateHeight(TreeNode node) - { - // 结点高度等于最高子树高度 + 1 - node.height = Math.Max(height(node.left), height(node.right)) + 1; - } + [class]{AVLTree}-[func]{updateHeight} ``` === "Swift" @@ -349,14 +339,7 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "C#" ```csharp title="avl_tree.cs" - /* 获取平衡因子 */ - public int balanceFactor(TreeNode? node) - { - // 空结点平衡因子为 0 - if (node == null) return 0; - // 结点平衡因子 = 左子树高度 - 右子树高度 - return height(node.left) - height(node.right); - } + [class]{AVLTree}-[func]{balanceFactor} ``` === "Swift" @@ -460,20 +443,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "C#" ```csharp title="avl_tree.cs" - /* 右旋操作 */ - TreeNode? rightRotate(TreeNode? node) - { - TreeNode? child = node.left; - TreeNode? grandChild = child?.right; - // 以 child 为原点,将 node 向右旋转 - child.right = node; - node.left = grandChild; - // 更新结点高度 - updateHeight(node); - updateHeight(child); - // 返回旋转后子树的根结点 - return child; - } + [class]{AVLTree}-[func]{rightRotate} ``` === "Swift" @@ -559,20 +529,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "C#" ```csharp title="avl_tree.cs" - /* 左旋操作 */ - TreeNode? leftRotate(TreeNode? node) - { - TreeNode? child = node.right; - TreeNode? grandChild = child?.left; - // 以 child 为原点,将 node 向左旋转 - child.left = node; - node.right = grandChild; - // 更新结点高度 - updateHeight(node); - updateHeight(child); - // 返回旋转后子树的根结点 - return child; - } + [class]{AVLTree}-[func]{leftRotate} ``` === "Swift" @@ -694,44 +651,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "C#" ```csharp title="avl_tree.cs" - /* 执行旋转操作,使该子树重新恢复平衡 */ - TreeNode? rotate(TreeNode? node) - { - // 获取结点 node 的平衡因子 - int balanceFactorInt = balanceFactor(node); - // 左偏树 - if (balanceFactorInt > 1) - { - if (balanceFactor(node.left) >= 0) - { - // 右旋 - return rightRotate(node); - } - else - { - // 先左旋后右旋 - node.left = leftRotate(node?.left); - return rightRotate(node); - } - } - // 右偏树 - if (balanceFactorInt < -1) - { - if (balanceFactor(node.right) <= 0) - { - // 左旋 - return leftRotate(node); - } - else - { - // 先右旋后左旋 - node.right = rightRotate(node?.right); - return leftRotate(node); - } - } - // 平衡树,无需旋转,直接返回 - return node; - } + [class]{AVLTree}-[func]{rotate} ``` === "Swift" @@ -889,30 +809,9 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "C#" ```csharp title="avl_tree.cs" - /* 插入结点 */ - public TreeNode? insert(int val) - { - root = insertHelper(root, val); - return root; - } + [class]{AVLTree}-[func]{insert} - /* 递归插入结点(辅助函数) */ - private TreeNode? insertHelper(TreeNode? node, int val) - { - if (node == null) return new TreeNode(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; - } + [class]{AVLTree}-[func]{insertHelper} ``` === "Swift" @@ -1186,48 +1085,11 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "C#" ```csharp title="avl_tree.cs" - /* 删除结点 */ - public TreeNode? remove(int val) - { - root = removeHelper(root, val); - return root; - } + [class]{AVLTree}-[func]{remove} - /* 递归删除结点(辅助函数) */ - private TreeNode? removeHelper(TreeNode? node, int val) - { - if (node == null) return null; - /* 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 == null || node.right == null) - { - TreeNode? child = node.left != null ? node.left : node.right; - // 子结点数量 = 0 ,直接删除 node 并返回 - if (child == null) - return null; - // 子结点数量 = 1 ,直接删除 node - else - node = child; - } - else - { - // 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 - TreeNode? temp = getInOrderNext(node.right); - node.right = removeHelper(node.right, temp.val); - node.val = temp.val; - } - } - updateHeight(node); // 更新结点高度 - /* 2. 执行旋转操作,使该子树重新恢复平衡 */ - node = rotate(node); - // 返回子树的根结点 - return node; - } + [class]{AVLTree}-[func]{removeHelper} + + [class]{AVLTree}-[func]{getInOrderNext} ``` === "Swift" diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index 1bf777ec2..814d04bb4 100755 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -98,23 +98,7 @@ comments: true === "C#" ```csharp title="binary_search_tree.cs" - /* 查找结点 */ - TreeNode? search(int num) - { - TreeNode? cur = root; - // 循环查找,越过叶结点后跳出 - while (cur != null) - { - // 目标结点在 cur 的右子树中 - if (cur.val < num) cur = cur.right; - // 目标结点在 cur 的左子树中 - else if (cur.val > num) cur = cur.left; - // 找到目标结点,跳出循环 - else break; - } - // 返回目标结点 - return cur; - } + [class]{BinarySearchTree}-[func]{search} ``` === "Swift" @@ -214,33 +198,7 @@ comments: true === "C#" ```csharp title="binary_search_tree.cs" - /* 插入结点 */ - TreeNode? insert(int num) - { - // 若树为空,直接提前返回 - if (root == null) return null; - TreeNode? cur = root, pre = null; - // 循环查找,越过叶结点后跳出 - while (cur != null) - { - // 找到重复结点,直接返回 - if (cur.val == num) return null; - pre = cur; - // 插入位置在 cur 的右子树中 - if (cur.val < num) cur = cur.right; - // 插入位置在 cur 的左子树中 - else cur = cur.left; - } - - // 插入结点 val - TreeNode node = new TreeNode(num); - if (pre != null) - { - if (pre.val < num) pre.right = node; - else pre.left = node; - } - return node; - } + [class]{BinarySearchTree}-[func]{insert} ``` === "Swift" @@ -411,68 +369,9 @@ comments: true === "C#" ```csharp title="binary_search_tree.cs" - /* 删除结点 */ - TreeNode? remove(int num) - { - // 若树为空,直接提前返回 - if (root == null) return null; - TreeNode? cur = root, pre = null; - // 循环查找,越过叶结点后跳出 - while (cur != null) - { - // 找到待删除结点,跳出循环 - if (cur.val == num) break; - pre = cur; - // 待删除结点在 cur 的右子树中 - if (cur.val < num) cur = cur.right; - // 待删除结点在 cur 的左子树中 - else cur = cur.left; - } - // 若无待删除结点,则直接返回 - if (cur == null || pre == null) return null; - // 子结点数量 = 0 or 1 - if (cur.left == null || cur.right == null) - { - // 当子结点数量 = 0 / 1 时, child = null / 该子结点 - TreeNode? child = cur.left != null ? cur.left : cur.right; - // 删除结点 cur - if (pre.left == cur) - { - pre.left = child; - } - else - { - pre.right = child; - } - } - // 子结点数量 = 2 - else - { - // 获取中序遍历中 cur 的下一个结点 - TreeNode? nex = getInOrderNext(cur.right); - if (nex != null) - { - int tmp = nex.val; - // 递归删除结点 nex - remove(nex.val); - // 将 nex 的值复制给 cur - cur.val = tmp; - } - } - return cur; - } + [class]{BinarySearchTree}-[func]{remove} - /* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */ - private TreeNode? getInOrderNext(TreeNode? root) - { - if (root == null) return root; - // 循环访问左子结点,直到叶结点时为最小结点,跳出 - while (root.left != null) - { - root = root.left; - } - return root; - } + [class]{BinarySearchTree}-[func]{getInOrderNext} ``` === "Swift" diff --git a/docs/chapter_tree/binary_tree_traversal.md b/docs/chapter_tree/binary_tree_traversal.md index f481628c9..d5640327a 100755 --- a/docs/chapter_tree/binary_tree_traversal.md +++ b/docs/chapter_tree/binary_tree_traversal.md @@ -85,26 +85,7 @@ comments: true === "C#" ```csharp title="binary_tree_bfs.cs" - /* 层序遍历 */ - public List hierOrder(TreeNode root) - { - // 初始化队列,加入根结点 - Queue queue = new(); - queue.Enqueue(root); - // 初始化一个列表,用于保存遍历序列 - List list = new(); - while (queue.Count != 0) - { - TreeNode node = queue.Dequeue(); // 队列出队 - list.Add(node.val); // 保存结点值 - if (node.left != null) - queue.Enqueue(node.left); // 左子结点入队 - if (node.right != null) - queue.Enqueue(node.right); // 右子结点入队 - } - return list; - } - + [class]{binary_tree_bfs}-[func]{hierOrder} ``` === "Swift" @@ -235,35 +216,11 @@ comments: true === "C#" ```csharp title="binary_tree_dfs.cs" - /* 前序遍历 */ - void preOrder(TreeNode? root) - { - if (root == null) return; - // 访问优先级:根结点 -> 左子树 -> 右子树 - list.Add(root.val); - preOrder(root.left); - preOrder(root.right); - } + [class]{binary_tree_dfs}-[func]{preOrder} - /* 中序遍历 */ - void inOrder(TreeNode? root) - { - if (root == null) return; - // 访问优先级:左子树 -> 根结点 -> 右子树 - inOrder(root.left); - list.Add(root.val); - inOrder(root.right); - } + [class]{binary_tree_dfs}-[func]{inOrder} - /* 后序遍历 */ - void postOrder(TreeNode? root) - { - if (root == null) return; - // 访问优先级:左子树 -> 右子树 -> 根结点 - postOrder(root.left); - postOrder(root.right); - list.Add(root.val); - } + [class]{binary_tree_dfs}-[func]{postOrder} ``` === "Swift" diff --git a/docs/utils/build_markdown.py b/docs/utils/build_markdown.py index 3756751b8..65c6828db 100755 --- a/docs/utils/build_markdown.py +++ b/docs/utils/build_markdown.py @@ -15,6 +15,7 @@ from docs.utils.extract_code_java import ExtractCodeBlocksJava from docs.utils.extract_code_cpp import ExtractCodeBlocksCpp from docs.utils.extract_code_jsts import ExtractCodeBlocksJSTS from docs.utils.extract_code_swift import ExtractCodeBlocksSwift +from docs.utils.extract_code_csharp import ExtractCodeBlocksCSharp def build_markdown(md_path): @@ -42,8 +43,12 @@ def build_markdown(md_path): extractor = extractor_dict[lang] # Get code blocks if file_name not in code_blocks_dict: - code_blocks_dict[file_name] = extractor.extract( + code_blocks = extractor.extract( file_path=osp.dirname(md_path).replace("docs/", f"codes/{lang}/") + f"/{file_name}") + if code_blocks is None: + i += 1 + continue + code_blocks_dict[file_name] = code_blocks header_line = i class_label = src_match[1] @@ -90,6 +95,7 @@ extractor_dict = { "javascript": ExtractCodeBlocksJSTS(), "typescript": ExtractCodeBlocksJSTS(), "swift": ExtractCodeBlocksSwift(), + "csharp": ExtractCodeBlocksCSharp(), } diff --git a/docs/utils/deploy.sh b/docs/utils/deploy.sh index 6f3e68b5a..280d95119 100644 --- a/docs/utils/deploy.sh +++ b/docs/utils/deploy.sh @@ -1,14 +1,27 @@ -# This script is borrowed from https://gist.github.com/cobyism/4730490 +python docs/utils/build_markdown.py +while true; do + read -p "Do you wish to deploy the site? [y] [n]" yn + case $yn in + [Yy]* ) make install; break;; + [Nn]* ) exit;; + * ) echo "Please answer yes[y] or no[n].";; + esac +done + +# push the built docs cd build git add . git commit -m "build" git push -u origin docs cd .. +# Build mkdocs mkdocs build --clean +# deploy the site cd site git add . git commit -m "deploy" git push -u origin gh-pages +cd.. diff --git a/docs/utils/extract_code_csharp.py b/docs/utils/extract_code_csharp.py new file mode 100644 index 000000000..7a0be0175 --- /dev/null +++ b/docs/utils/extract_code_csharp.py @@ -0,0 +1,28 @@ +""" +File: extract_code_csharp.py +Created Time: 2023-02-07 +Author: Krahets (krahets@163.com) +""" + +import re +import glob +import sys, os.path as osp +sys.path.append(osp.dirname(osp.dirname(osp.dirname(osp.abspath(__file__))))) +from docs.utils.extract_code_java import ExtractCodeBlocksJava + + +class ExtractCodeBlocksCSharp(ExtractCodeBlocksJava): + def __init__(self) -> None: + super().__init__() + + # Pattern to match function names and class names + self.func_pattern = r'(\s*)(public|private|)\s*(static|)\s*(|\S+)\s*(\w+)(\(.*\))' + self.class_pattern = r'(public|)\s*(class|struct)\s+(\w+)\s*\n' + + self.func_pattern_keys = ["total", "ind", "scope", "static", "return", "label", "args"] + self.class_pattern_keys = ["total", "scope", "type", "label"] + +# for code_path in glob.glob("codes/csharp/chapter_*/array.cs"): +# ext = ExtractCodeBlocksCSharp() +# res = ext.extract(code_path) +# pass \ No newline at end of file diff --git a/docs/utils/extract_code_java.py b/docs/utils/extract_code_java.py index 6d5c61b64..d86a27d1f 100644 --- a/docs/utils/extract_code_java.py +++ b/docs/utils/extract_code_java.py @@ -31,6 +31,9 @@ class ExtractCodeBlocksJava: """ Extract classes and functions from a markdown document """ + if not osp.isfile(file_path): + return None + self.file_path = file_path with open(file_path) as f: self.lines = f.readlines() diff --git a/docs/utils/extract_code_jsts.py b/docs/utils/extract_code_jsts.py index ab714bf56..86568149c 100644 --- a/docs/utils/extract_code_jsts.py +++ b/docs/utils/extract_code_jsts.py @@ -21,8 +21,3 @@ class ExtractCodeBlocksJSTS(ExtractCodeBlocksJava): self.func_pattern_keys = ["total", "ind", "prefix", "label", ":", "return"] self.class_pattern_keys = ["total", "scope", "label"] - - -# for code_path in glob.glob("codes/cpp/chapter_*/my_heap.cpp"): -# ext = ExtractCodeBlocksCpp() -# ext.extract(code_path) diff --git a/docs/utils/extract_code_python.py b/docs/utils/extract_code_python.py index 1618f87cf..e2f32c7ed 100755 --- a/docs/utils/extract_code_python.py +++ b/docs/utils/extract_code_python.py @@ -49,7 +49,3 @@ class ExtractCodeBlocksPython(ExtractCodeBlocksJava): remove_empty_lines(func) for func in funcs.values(): remove_empty_lines(func) - - -# ext = ExtractCodeBlocksPython() -# ext.extract("codes/python/chapter_array_and_linkedlist/my_list.py") diff --git a/docs/utils/extract_code_swift.py b/docs/utils/extract_code_swift.py index 915c908de..565935231 100644 --- a/docs/utils/extract_code_swift.py +++ b/docs/utils/extract_code_swift.py @@ -21,8 +21,3 @@ class ExtractCodeBlocksSwift(ExtractCodeBlocksJava): self.func_pattern_keys = ["total", "ind", "scope", "static", "func", "label"] self.class_pattern_keys = ["total", "scope", "label"] - - -# for code_path in glob.glob("codes/cpp/chapter_*/my_heap.cpp"): -# ext = ExtractCodeBlocksCpp() -# ext.extract(code_path)