Fix some codes and a figure.

This commit is contained in:
krahets 2023-06-05 01:03:39 +08:00
parent 2532f06c7f
commit 698c2e7fe5
8 changed files with 48 additions and 46 deletions

View file

@ -5,39 +5,41 @@
*/ */
/* 二分查找最左一个元素 */ /* 二分查找最左一个元素 */
function binary_search_left_edge(nums, target) { function binarySearchLeftEdge(nums, target) {
let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1] let i = 0,
j = nums.length - 1; // 初始化双闭区间 [0, n-1]
while (i <= j) { while (i <= j) {
let m = Math.floor((i + j) / 2); // 计算中点索引 m let m = Math.floor((i + j) / 2); // 计算中点索引 m
if (nums[m] < target) { if (nums[m] < target) {
i = m + 1; // target 在区间 [m+1, j] 中 i = m + 1; // target 在区间 [m+1, j] 中
} else if (nums[m] > target) { } else if (nums[m] > target) {
j = m - 1; // target 在区间 [i, m-1] 中 j = m - 1; // target 在区间 [i, m-1] 中
} else { } else {
j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中 j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中
} }
} }
if (i == nums.length || nums[i] != target) { if (i == nums.length || nums[i] != target) {
return -1; // 未找到目标元素,返回 -1 return -1; // 未找到目标元素,返回 -1
} }
return i; return i;
} }
/* 二分查找最右一个元素 */ /* 二分查找最右一个元素 */
function binary_search_right_edge(nums, target) { function binarySearchRightEdge(nums, target) {
let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1] let i = 0,
j = nums.length - 1; // 初始化双闭区间 [0, n-1]
while (i <= j) { while (i <= j) {
let m = Math.floor((i + j) / 2); // 计算中点索引 m let m = Math.floor((i + j) / 2); // 计算中点索引 m
if (nums[m] < target) { if (nums[m] < target) {
i = m + 1; // target 在区间 [m+1, j] 中 i = m + 1; // target 在区间 [m+1, j] 中
} else if (nums[m] > target) { } else if (nums[m] > target) {
j = m - 1; // target 在区间 [i, m-1] 中 j = m - 1; // target 在区间 [i, m-1] 中
} else { } else {
i = m + 1; // 首个大于 target 的元素在区间 [m+1, j] 中 i = m + 1; // 首个大于 target 的元素在区间 [m+1, j] 中
} }
} }
if (j == nums.length || nums[j] != target) { if (j == nums.length || nums[j] != target) {
return -1; // 未找到目标元素,返回 -1 return -1; // 未找到目标元素,返回 -1
} }
return j; return j;
} }
@ -47,9 +49,9 @@ let target = 6;
const nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; const nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15];
// 二分查找最左一个元素 // 二分查找最左一个元素
let index_left = binary_search_left_edge(nums, target); let index_left = binarySearchLeftEdge(nums, target);
console.log("数组中最左一个元素 6 的索引 = ", index_left); console.log('数组中最左一个元素 6 的索引 = ', index_left);
// 二分查找最右一个元素 // 二分查找最右一个元素
let index_right = binary_search_right_edge(nums, target); let index_right = binarySearchRightEdge(nums, target);
console.log("数组中最右一个元素 6 的索引 = ", index_right); console.log('数组中最右一个元素 6 的索引 = ', index_right);

View file

@ -5,7 +5,7 @@
*/ */
/* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */ /* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */
function sift_down(nums, n, i) { function siftDown(nums, n, i) {
while (true) { while (true) {
// 判断节点 i, l, r 中值最大的节点,记为 ma // 判断节点 i, l, r 中值最大的节点,记为 ma
let l = 2 * i + 1; let l = 2 * i + 1;
@ -29,21 +29,21 @@ function sift_down(nums, n, i) {
} }
/* 堆排序 */ /* 堆排序 */
function heap_sort(nums) { function heapSort(nums) {
// 建堆操作:堆化除叶节点以外的其他所有节点 // 建堆操作:堆化除叶节点以外的其他所有节点
for (let i = Math.floor(nums.length / 2) - 1; i >= 0; i--) { for (let i = Math.floor(nums.length / 2) - 1; i >= 0; i--) {
sift_down(nums, nums.length, i); siftDown(nums, nums.length, i);
} }
// 从堆中提取最大元素,循环 n-1 轮 // 从堆中提取最大元素,循环 n-1 轮
for (let i = nums.length - 1; i > 0; i--) { for (let i = nums.length - 1; i > 0; i--) {
// 交换根节点与最右叶节点(即交换首元素与尾元素) // 交换根节点与最右叶节点(即交换首元素与尾元素)
[nums[0], nums[i]] = [nums[i], nums[0]]; [nums[0], nums[i]] = [nums[i], nums[0]];
// 以根节点为起点,从顶至底进行堆化 // 以根节点为起点,从顶至底进行堆化
sift_down(nums, i, 0); siftDown(nums, i, 0);
} }
} }
/* Driver Code */ /* Driver Code */
const nums = [4, 1, 3, 1, 5, 2]; const nums = [4, 1, 3, 1, 5, 2];
heap_sort(nums); heapSort(nums);
console.log("堆排序完成后 nums =", nums); console.log('堆排序完成后 nums =', nums);

View file

@ -5,7 +5,7 @@
*/ */
/* 选择排序 */ /* 选择排序 */
function selection_sort(nums) { function selectionSort(nums) {
let n = nums.length; let n = nums.length;
// 外循环:未排序区间为 [i, n-1] // 外循环:未排序区间为 [i, n-1]
for (let i = 0; i < n - 1; i++) { for (let i = 0; i < n - 1; i++) {
@ -13,7 +13,7 @@ function selection_sort(nums) {
let k = i; let k = i;
for (let j = i + 1; j < n; j++) { for (let j = i + 1; j < n; j++) {
if (nums[j] < nums[k]) { if (nums[j] < nums[k]) {
k = j; // 记录最小元素的索引 k = j; // 记录最小元素的索引
} }
} }
// 将该最小元素与未排序区间的首个元素交换 // 将该最小元素与未排序区间的首个元素交换
@ -23,5 +23,5 @@ function selection_sort(nums) {
/* Driver Code */ /* Driver Code */
const nums = [4, 1, 3, 1, 5, 2]; const nums = [4, 1, 3, 1, 5, 2];
selection_sort(nums); selectionSort(nums);
console.log("选择排序完成后 nums =", nums); console.log('选择排序完成后 nums =', nums);

View file

@ -5,7 +5,7 @@
*/ */
/* 二分查找最左一个元素 */ /* 二分查找最左一个元素 */
function binary_search_left_edge(nums: number[], target: number): number { function binarySearchLeftEdge(nums: number[], target: number): number {
let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1] let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1]
while (i <= j) { while (i <= j) {
let m = Math.floor((i + j) / 2); // 计算中点索引 m let m = Math.floor((i + j) / 2); // 计算中点索引 m
@ -24,7 +24,7 @@ function binary_search_left_edge(nums: number[], target: number): number {
} }
/* 二分查找最右一个元素 */ /* 二分查找最右一个元素 */
function binary_search_right_edge(nums: number[], target: number): number { function binarySearchRightEdge(nums: number[], target: number): number {
let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1] let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1]
while (i <= j) { while (i <= j) {
let m = Math.floor((i + j) / 2); // 计算中点索引 m let m = Math.floor((i + j) / 2); // 计算中点索引 m
@ -47,9 +47,9 @@ let target: number = 6;
const nums: number[] = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; const nums: number[] = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15];
// 二分查找最左一个元素 // 二分查找最左一个元素
let index_left: number = binary_search_left_edge(nums, target); let index_left: number = binarySearchLeftEdge(nums, target);
console.log("数组中最左一个元素 6 的索引 = ", index_left); console.log("数组中最左一个元素 6 的索引 = ", index_left);
// 二分查找最右一个元素 // 二分查找最右一个元素
let index_right: number = binary_search_right_edge(nums, target); let index_right: number = binarySearchRightEdge(nums, target);
console.log("数组中最右一个元素 6 的索引 = ", index_right); console.log("数组中最右一个元素 6 的索引 = ", index_right);

View file

@ -5,7 +5,7 @@
*/ */
/* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */ /* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */
function sift_down(nums: number[], n: number, i: number): void { function siftDown(nums: number[], n: number, i: number): void {
while (true) { while (true) {
// 判断节点 i, l, r 中值最大的节点,记为 ma // 判断节点 i, l, r 中值最大的节点,记为 ma
let l = 2 * i + 1; let l = 2 * i + 1;
@ -29,23 +29,23 @@ function sift_down(nums: number[], n: number, i: number): void {
} }
/* 堆排序 */ /* 堆排序 */
function heap_sort(nums: number[]): void { function heapSort(nums: number[]): void {
// 建堆操作:堆化除叶节点以外的其他所有节点 // 建堆操作:堆化除叶节点以外的其他所有节点
for (let i = Math.floor(nums.length / 2) - 1; i >= 0; i--) { for (let i = Math.floor(nums.length / 2) - 1; i >= 0; i--) {
sift_down(nums, nums.length, i); siftDown(nums, nums.length, i);
} }
// 从堆中提取最大元素,循环 n-1 轮 // 从堆中提取最大元素,循环 n-1 轮
for (let i = nums.length - 1; i > 0; i--) { for (let i = nums.length - 1; i > 0; i--) {
// 交换根节点与最右叶节点(即交换首元素与尾元素) // 交换根节点与最右叶节点(即交换首元素与尾元素)
[nums[0], nums[i]] = [nums[i], nums[0]]; [nums[0], nums[i]] = [nums[i], nums[0]];
// 以根节点为起点,从顶至底进行堆化 // 以根节点为起点,从顶至底进行堆化
sift_down(nums, i, 0); siftDown(nums, i, 0);
} }
} }
/* Driver Code */ /* Driver Code */
const nums: number[] = [4, 1, 3, 1, 5, 2]; const nums: number[] = [4, 1, 3, 1, 5, 2];
heap_sort(nums); heapSort(nums);
console.log("堆排序完成后 nums =", nums); console.log('堆排序完成后 nums =', nums);
export { }; export {};

View file

@ -5,7 +5,7 @@
*/ */
/* 选择排序 */ /* 选择排序 */
function selection_sort(nums: number[]): void { function selectionSort(nums: number[]): void {
let n = nums.length; let n = nums.length;
// 外循环:未排序区间为 [i, n-1] // 外循环:未排序区间为 [i, n-1]
for (let i = 0; i < n - 1; i++) { for (let i = 0; i < n - 1; i++) {
@ -13,7 +13,7 @@ function selection_sort(nums: number[]): void {
let k = i; let k = i;
for (let j = i + 1; j < n; j++) { for (let j = i + 1; j < n; j++) {
if (nums[j] < nums[k]) { if (nums[j] < nums[k]) {
k = j; // 记录最小元素的索引 k = j; // 记录最小元素的索引
} }
} }
// 将该最小元素与未排序区间的首个元素交换 // 将该最小元素与未排序区间的首个元素交换
@ -23,7 +23,7 @@ function selection_sort(nums: number[]): void {
/* Driver Code */ /* Driver Code */
const nums: number[] = [4, 1, 3, 1, 5, 2]; const nums: number[] = [4, 1, 3, 1, 5, 2];
selection_sort(nums); selectionSort(nums);
console.log("选择排序完成后 nums =", nums); console.log('选择排序完成后 nums =', nums);
export { }; export {};

View file

@ -592,7 +592,7 @@ $T(n)$ 是一次函数,说明时间增长趋势是线性的,因此可以得
根据定义,确定 $f(n)$ 之后,我们便可得到时间复杂度 $O(f(n))$ 。那么如何确定渐近上界 $f(n)$ 呢?总体分为两步:首先统计操作数量,然后判断渐近上界。 根据定义,确定 $f(n)$ 之后,我们便可得到时间复杂度 $O(f(n))$ 。那么如何确定渐近上界 $f(n)$ 呢?总体分为两步:首先统计操作数量,然后判断渐近上界。
### 1) 统计操作数量 ### 第一步:统计操作数量
针对代码,逐行从上到下计算即可。然而,由于上述 $c \cdot f(n)$ 中的常数项 $c$ 可以取任意大小,**因此操作数量 $T(n)$ 中的各种系数、常数项都可以被忽略**。根据此原则,可以总结出以下计数简化技巧: 针对代码,逐行从上到下计算即可。然而,由于上述 $c \cdot f(n)$ 中的常数项 $c$ 可以取任意大小,**因此操作数量 $T(n)$ 中的各种系数、常数项都可以被忽略**。根据此原则,可以总结出以下计数简化技巧:
@ -808,7 +808,7 @@ $$
} }
``` ```
### 2) 判断渐近上界 ### 第二步:判断渐近上界
**时间复杂度由多项式 $T(n)$ 中最高阶的项来决定**。这是因为在 $n$ 趋于无穷大时,最高阶的项将发挥主导作用,其他项的影响都可以被忽略。 **时间复杂度由多项式 $T(n)$ 中最高阶的项来决定**。这是因为在 $n$ 趋于无穷大时,最高阶的项将发挥主导作用,其他项的影响都可以被忽略。

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 61 KiB