mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-11 19:30:59 +00:00
build
This commit is contained in:
@@ -38,6 +38,10 @@ Essentially, **the row-by-row placing strategy serves as a pruning function**, a
|
||||
|
||||
To satisfy column constraints, we can use a boolean array `cols` of length $n$ to track whether a queen occupies each column. Before each placement decision, `cols` is used to prune the columns that already have queens, and it is dynamically updated during backtracking.
|
||||
|
||||
!!! tip
|
||||
|
||||
Note that the origin of the chessboard is located in the upper left corner, where the row index increases from top to bottom, and the column index increases from left to right.
|
||||
|
||||
How about the diagonal constraints? Let the row and column indices of a cell on the chessboard be $(row, col)$. By selecting a specific main diagonal, we notice that the difference $row - col$ is the same for all cells on that diagonal, **meaning that $row - col$ is a constant value on that diagonal**.
|
||||
|
||||
Thus, if two cells satisfy $row_1 - col_1 = row_2 - col_2$, they are definitely on the same main diagonal. Using this pattern, we can utilize the array `diags1` shown in Figure 13-18 to track whether a queen is on any main diagonal.
|
||||
|
||||
@@ -20,27 +20,27 @@ If vertices are viewed as nodes and edges as references (pointers) connecting th
|
||||
|
||||
<p align="center"> Figure 9-1 Relationship between linked lists, trees, and graphs </p>
|
||||
|
||||
## 9.1.1 Common types of graphs
|
||||
## 9.1.1 Common types and terminologies of graphs
|
||||
|
||||
Based on whether edges have direction, graphs can be divided into <u>undirected graphs</u> and <u>directed graphs</u>, as shown in Figure 9-2.
|
||||
Graphs can be divided into <u>undirected graphs</u> and <u>directed graphs</u> depending on whether edges have direction, as shown in Figure 9-2.
|
||||
|
||||
- In undirected graphs, edges represent a "bidirectional" connection between two vertices, for example, the "friendship" in WeChat or QQ.
|
||||
- In directed graphs, edges have directionality, that is, the edges $A \rightarrow B$ and $A \leftarrow B$ are independent of each other, for example, the "follow" and "be followed" relationship on Weibo or TikTok.
|
||||
- In undirected graphs, edges represent a "bidirectional" connection between two vertices, for example, the "friends" in Facebook.
|
||||
- In directed graphs, edges have directionality, that is, the edges $A \rightarrow B$ and $A \leftarrow B$ are independent of each other. For example, the "follow" and "followed" relationship on Instagram or TikTok.
|
||||
|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> Figure 9-2 Directed and undirected graphs </p>
|
||||
|
||||
Based on whether all vertices are connected, graphs can be divided into <u>connected graphs</u> and <u>disconnected graphs</u>, as shown in Figure 9-3.
|
||||
Depending on whether all vertices are connected, graphs can be divided into <u>connected graphs</u> and <u>disconnected graphs</u>, as shown in Figure 9-3.
|
||||
|
||||
- For connected graphs, it is possible to reach any other vertex starting from a certain vertex.
|
||||
- For disconnected graphs, there is at least one vertex that cannot be reached from a certain starting vertex.
|
||||
- For connected graphs, it is possible to reach any other vertex starting from an arbitrary vertex.
|
||||
- For disconnected graphs, there is at least one vertex that cannot be reached from an arbitrary starting vertex.
|
||||
|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> Figure 9-3 Connected and disconnected graphs </p>
|
||||
|
||||
We can also add a weight variable to edges, resulting in <u>weighted graphs</u> as shown in Figure 9-4. For example, in mobile games like "Honor of Kings", the system calculates the "closeness" between players based on shared gaming time, and this closeness network can be represented with a weighted graph.
|
||||
We can also add a weight variable to edges, resulting in <u>weighted graphs</u> as shown in Figure 9-4. For example, in Instagram, the system sorts your follower and following list by the level of interaction between you and other users (likes, views, comments, etc.). Such an interaction network can be represented by a weighted graph.
|
||||
|
||||
{ class="animation-figure" }
|
||||
|
||||
@@ -54,7 +54,7 @@ Graph data structures include the following commonly used terms.
|
||||
|
||||
## 9.1.2 Representation of graphs
|
||||
|
||||
Common representations of graphs include "adjacency matrices" and "adjacency lists". The following examples use undirected graphs.
|
||||
Common representations of graphs include "adjacency matrix" and "adjacency list". The following examples use undirected graphs.
|
||||
|
||||
### 1. Adjacency matrix
|
||||
|
||||
@@ -69,10 +69,10 @@ As shown in Figure 9-5, let the adjacency matrix be $M$, and the list of vertice
|
||||
Adjacency matrices have the following characteristics.
|
||||
|
||||
- A vertex cannot be connected to itself, so the elements on the main diagonal of the adjacency matrix are meaningless.
|
||||
- For undirected graphs, edges in both directions are equivalent, thus the adjacency matrix is symmetric about the main diagonal.
|
||||
- By replacing the elements of the adjacency matrix from $1$ and $0$ to weights, it can represent weighted graphs.
|
||||
- For undirected graphs, edges in both directions are equivalent, thus the adjacency matrix is symmetric with regard to the main diagonal.
|
||||
- By replacing the elements of the adjacency matrix from $1$ and $0$ to weights, we can represent weighted graphs.
|
||||
|
||||
When representing graphs with adjacency matrices, it is possible to directly access matrix elements to obtain edges, thus operations of addition, deletion, lookup, and modification are very efficient, all with a time complexity of $O(1)$. However, the space complexity of the matrix is $O(n^2)$, which consumes more memory.
|
||||
When representing graphs with adjacency matrices, it is possible to directly access matrix elements to obtain edges, resulting in efficient operations of addition, deletion, lookup, and modification, all with a time complexity of $O(1)$. However, the space complexity of the matrix is $O(n^2)$, which consumes more memory.
|
||||
|
||||
### 2. Adjacency list
|
||||
|
||||
@@ -96,7 +96,7 @@ As shown in Table 9-1, many real-world systems can be modeled with graphs, and c
|
||||
|
||||
| | Vertices | Edges | Graph Computing Problem |
|
||||
| --------------- | ---------------- | --------------------------------------------- | -------------------------------- |
|
||||
| Social Networks | Users | Friendships | Potential Friend Recommendations |
|
||||
| Social Networks | Users | Follow / Followed | Potential Following Recommendations |
|
||||
| Subway Lines | Stations | Connectivity Between Stations | Shortest Route Recommendations |
|
||||
| Solar System | Celestial Bodies | Gravitational Forces Between Celestial Bodies | Planetary Orbit Calculations |
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ icon: material/graphql
|
||||
|
||||
!!! abstract
|
||||
|
||||
In the journey of life, we are like individual nodes, connected by countless invisible edges.
|
||||
In the journey of life, each of us is a node, connected by countless invisible edges.
|
||||
|
||||
Each encounter and parting leaves a distinctive imprint on this vast network graph.
|
||||
Each encounter and parting leaves a unique imprint on this vast graph of life.
|
||||
|
||||
## Chapter contents
|
||||
|
||||
|
||||
@@ -6,16 +6,16 @@ comments: true
|
||||
|
||||
### 1. Key review
|
||||
|
||||
- A heap is a complete binary tree, which can be divided into a max heap and a min heap based on its property. The top element of a max (min) heap is the largest (smallest).
|
||||
- A heap is a complete binary tree that can be categorized as either a max heap or a min heap based on its building property, where the top element of a max heap is the largest and the top element of a min heap is the smallest.
|
||||
- A priority queue is defined as a queue with dequeue priority, usually implemented using a heap.
|
||||
- Common operations of a heap and their corresponding time complexities include: element insertion into the heap $O(\log n)$, removing the top element from the heap $O(\log n)$, and accessing the top element of the heap $O(1)$.
|
||||
- A complete binary tree is well-suited to be represented by an array, thus heaps are commonly stored using arrays.
|
||||
- Heapify operations are used to maintain the properties of the heap and are used in both heap insertion and removal operations.
|
||||
- The time complexity of inserting $n$ elements into a heap and building the heap can be optimized to $O(n)$, which is highly efficient.
|
||||
- The time complexity of building a heap given an input of $n$ elements can be optimized to $O(n)$, which is highly efficient.
|
||||
- Top-k is a classic algorithm problem that can be efficiently solved using the heap data structure, with a time complexity of $O(n \log k)$.
|
||||
|
||||
### 2. Q & A
|
||||
|
||||
**Q**: Is the "heap" in data structures the same concept as the "heap" in memory management?
|
||||
|
||||
The two are not the same concept, even though they are both referred to as "heap". The heap in computer system memory is part of dynamic memory allocation, where the program can use it to store data during execution. The program can request a certain amount of heap memory to store complex structures like objects and arrays. When these data are no longer needed, the program needs to release this memory to prevent memory leaks. Compared to stack memory, the management and usage of heap memory need to be more cautious, as improper use may lead to memory leaks and dangling pointers.
|
||||
The two are not the same concept, even though they are both referred to as "heap". The heap in computer system memory is part of dynamic memory allocation, where the program can use it to store data during execution. The program can request a certain amount of heap memory to store complex structures like objects and arrays. When the allocated data is no longer needed, the program needs to release this memory to prevent memory leaks. Compared to stack memory, the management and usage of heap memory demands more caution, as improper use may lead to memory leaks and dangling pointers.
|
||||
|
||||
@@ -63,4 +63,4 @@ From cooking a meal to interstellar travel, almost all problem-solving involves
|
||||
|
||||
!!! tip
|
||||
|
||||
If concepts such as data structures, algorithms, arrays, and binary search still seem somewhat obsecure, I encourage you to continue reading. This book will gently guide you into the realm of understanding data structures and algorithms.
|
||||
If concepts such as data structures, algorithms, arrays, and binary search still seem somewhat obscure, I encourage you to continue reading. This book will gently guide you into the realm of understanding data structures and algorithms.
|
||||
|
||||
@@ -6,9 +6,9 @@ comments: true
|
||||
|
||||
This open-source project aims to create a free, and beginner-friendly crash course on data structures and algorithms.
|
||||
|
||||
- Using animated illustrations, it delivers structured insights into data structures and algorithmic concepts, ensuring comprehensibility and a smooth learning curve.
|
||||
- Run code with just one click, supporting Java, C++, Python, Go, JS, TS, C#, Swift, Rust, Dart, Zig and other languages.
|
||||
- Readers are encouraged to engage with each other in the discussion area for each section, questions and comments are usually answered within two days.
|
||||
- Animated illustrations, easy-to-understand content, and a smooth learning curve help beginners explore the "knowledge map" of data structures and algorithms.
|
||||
- Run code with just one click, helping readers improve their programming skills and understand the working principle of algorithms and the underlying implementation of data structures.
|
||||
- Promoting learning by teaching, feel free to ask questions and share insights. Let's grow together through discussion.
|
||||
|
||||
## 0.1.1 Target audience
|
||||
|
||||
@@ -38,7 +38,7 @@ The main content of the book is shown in Figure 0-1.
|
||||
|
||||
This book is continuously improved with the joint efforts of many contributors from the open-source community. Thanks to each writer who invested their time and energy, listed in the order generated by GitHub: krahets, codingonion, nuomi1, Gonglja, Reanon, justin-tse, danielsss, hpstory, S-N-O-R-L-A-X, night-cruise, msk397, gvenusleo, RiverTwilight, gyt95, zhuoqinyue, Zuoxun, Xia-Sang, mingXta, FangYuan33, GN-Yu, IsChristina, xBLACKICEx, guowei-gong, Cathay-Chen, mgisr, JoseHung, qualifier1024, pengchzn, Guanngxu, longsizhuo, L-Super, what-is-me, yuan0221, lhxsm, Slone123c, WSL0809, longranger2, theNefelibatas, xiongsp, JeffersonHuang, hongyun-robot, K3v123, yuelinxin, a16su, gaofer, malone6, Wonderdch, xjr7670, DullSword, Horbin-Magician, NI-SW, reeswell, XC-Zero, XiaChuerwu, yd-j, iron-irax, huawuque404, MolDuM, Nigh, KorsChen, foursevenlove, 52coder, bubble9um, youshaoXG, curly210102, gltianwen, fanchenggang, Transmigration-zhou, FloranceYeh, FreddieLi, ShiMaRing, lipusheng, Javesun99, JackYang-hellobobo, shanghai-Jerry, 0130w, Keynman, psychelzh, logan-qiu, ZnYang2018, MwumLi, 1ch0, Phoenix0415, qingpeng9802, Richard-Zhang1019, QiLOL, Suremotoo, Turing-1024-Lee, Evilrabbit520, GaochaoZhu, ZJKung, linzeyan, hezhizhen, ZongYangL, beintentional, czruby, coderlef, dshlstarr, szu17dmy, fbigm, gledfish, hts0000, boloboloda, iStig, jiaxianhua, wenjianmin, keshida, kilikilikid, lclc6, lwbaptx, liuxjerry, lucaswangdev, lyl625760, chadyi, noobcodemaker, selear, siqyka, syd168, 4yDX3906, tao363, wangwang105, weibk, yabo083, yi427, yishangzhang, zhouLion, baagod, ElaBosak233, xb534, luluxia, yanedie, thomasq0, YangXuanyi and th1nk3r-ing.
|
||||
|
||||
The code review work for this book was completed by codingonion, Gonglja, gvenusleo, hpstory, justin‐tse, krahets, night-cruise, nuomi1, and Reanon (listed in alphabetical order). Thanks to them for their time and effort, ensuring the standardization and uniformity of the code in various languages.
|
||||
The code review work for this book was completed by codingonion, Gonglja, gvenusleo, hpstory, justin‐tse, khoaxuantu, krahets, night-cruise, nuomi1, and Reanon (listed in alphabetical order). Thanks to them for their time and effort, ensuring the standardization and uniformity of the code in various languages.
|
||||
|
||||
Throughout the creation of this book, numerous individuals provided invaluable assistance, including but not limited to:
|
||||
|
||||
|
||||
@@ -181,8 +181,7 @@ The code is shown as follows:
|
||||
|
||||
Bucket sort is suitable for handling very large data sets. For example, if the input data includes 1 million elements, and system memory limitations prevent loading all the data at once, you can divide the data into 1,000 buckets and sort each bucket separately before merging the results.
|
||||
|
||||
- **Time complexity is $O(n + k)$**: Assuming the elements are evenly distributed across the buckets, the number of elements in each bucket is $n/k$. Assuming sorting a single bucket takes $O(n/k \log(n/k))$ time, sorting all buckets takes $O(n \log(n/k))$ time. **When the number of buckets $k$ is relatively large, the time complexity tends towards $O(n)$**. Merging the results requires traversing all buckets and elements, taking $O(n + k)$ time.
|
||||
- **Adaptive sorting**: In the worst case, all data is distributed into a single bucket, and sorting that bucket takes $O(n^2)$ time.
|
||||
- **Time complexity is $O(n + k)$**: Assuming the elements are evenly distributed across the buckets, the number of elements in each bucket is $n/k$. Assuming sorting a single bucket takes $O(n/k \log(n/k))$ time, sorting all buckets takes $O(n \log(n/k))$ time. **When the number of buckets $k$ is relatively large, the time complexity tends towards $O(n)$**. Merging the results requires traversing all buckets and elements, taking $O(n + k)$ time. In the worst case, all data is distributed into a single bucket, and sorting that bucket takes $O(n^2)$ time.
|
||||
- **Space complexity is $O(n + k)$, non-in-place sorting**: It requires additional space for $k$ buckets and a total of $n$ elements.
|
||||
- Whether bucket sort is stable depends on whether the algorithm used to sort elements within the buckets is stable.
|
||||
|
||||
|
||||
@@ -325,7 +325,7 @@ The overall process of quick sort is shown in Figure 11-9.
|
||||
|
||||
## 11.5.2 Algorithm features
|
||||
|
||||
- **Time complexity of $O(n \log n)$, adaptive sorting**: In average cases, the recursive levels of pivot partitioning are $\log n$, and the total number of loops per level is $n$, using $O(n \log n)$ time overall. In the worst case, each round of pivot partitioning divides an array of length $n$ into two sub-arrays of lengths $0$ and $n - 1$, reaching $n$ recursive levels, and using $O(n^2)$ time overall.
|
||||
- **Time complexity of $O(n \log n)$, non-adaptive sorting**: In average cases, the recursive levels of pivot partitioning are $\log n$, and the total number of loops per level is $n$, using $O(n \log n)$ time overall. In the worst case, each round of pivot partitioning divides an array of length $n$ into two sub-arrays of lengths $0$ and $n - 1$, reaching $n$ recursive levels, and using $O(n^2)$ time overall.
|
||||
- **Space complexity of $O(n)$, in-place sorting**: In completely reversed input arrays, reaching the worst recursion depth of $n$, using $O(n)$ stack frame space. The sorting operation is performed on the original array without the aid of additional arrays.
|
||||
- **Non-stable sorting**: In the final step of pivot partitioning, the pivot may be swapped to the right of equal elements.
|
||||
|
||||
|
||||
@@ -41,14 +41,12 @@ Stable sorting is a necessary condition for multi-level sorting scenarios. Suppo
|
||||
('E', 23)
|
||||
```
|
||||
|
||||
**Adaptability**: <u>Adaptive sorting</u> has a time complexity that depends on the input data, i.e., the best time complexity, worst time complexity, and average time complexity are not exactly equal.
|
||||
|
||||
Adaptability needs to be assessed according to the specific situation. If the worst time complexity is worse than the average, it suggests that the performance of the sorting algorithm might deteriorate under certain data, hence it is seen as a negative attribute; whereas, if the best time complexity is better than the average, it is considered a positive attribute.
|
||||
**Adaptability**: <u>Adaptive sorting</u> leverages existing order information within the input data to reduce computational effort, achieving more optimal time efficiency. The best-case time complexity of adaptive sorting algorithms is typically better than their average-case time complexity.
|
||||
|
||||
**Comparison-based**: <u>Comparison-based sorting</u> relies on comparison operators ($<$, $=$, $>$) to determine the relative order of elements and thus sort the entire array, with the theoretical optimal time complexity being $O(n \log n)$. Meanwhile, <u>non-comparison sorting</u> does not use comparison operators and can achieve a time complexity of $O(n)$, but its versatility is relatively poor.
|
||||
|
||||
## 11.1.2 Ideal sorting algorithm
|
||||
|
||||
**Fast execution, in-place, stable, positively adaptive, and versatile**. Clearly, no sorting algorithm that combines all these features has been found to date. Therefore, when selecting a sorting algorithm, it is necessary to decide based on the specific characteristics of the data and the requirements of the problem.
|
||||
**Fast execution, in-place, stable, adaptive, and versatile**. Clearly, no sorting algorithm that combines all these features has been found to date. Therefore, when selecting a sorting algorithm, it is necessary to decide based on the specific characteristics of the data and the requirements of the problem.
|
||||
|
||||
Next, we will learn about various sorting algorithms together and analyze the advantages and disadvantages of each based on the above evaluation dimensions.
|
||||
|
||||
@@ -13,7 +13,7 @@ comments: true
|
||||
- Bucket sort consists of three steps: data bucketing, sorting within buckets, and merging results. It also embodies the divide-and-conquer strategy, suitable for very large datasets. The key to bucket sort is the even distribution of data.
|
||||
- Counting sort is a special case of bucket sort, which sorts by counting the occurrences of each data point. Counting sort is suitable for large datasets with a limited range of data and requires that data can be converted to positive integers.
|
||||
- Radix sort sorts data by sorting digit by digit, requiring data to be represented as fixed-length numbers.
|
||||
- Overall, we hope to find a sorting algorithm that has high efficiency, stability, in-place operation, and positive adaptability. However, like other data structures and algorithms, no sorting algorithm can meet all these conditions simultaneously. In practical applications, we need to choose the appropriate sorting algorithm based on the characteristics of the data.
|
||||
- Overall, we hope to find a sorting algorithm that has high efficiency, stability, in-place operation, and adaptability. However, like other data structures and algorithms, no sorting algorithm can meet all these conditions simultaneously. In practical applications, we need to choose the appropriate sorting algorithm based on the characteristics of the data.
|
||||
- Figure 11-19 compares mainstream sorting algorithms in terms of efficiency, stability, in-place nature, and adaptability.
|
||||
|
||||
{ class="animation-figure" }
|
||||
|
||||
@@ -767,21 +767,21 @@ It can be observed that **the right and left rotation operations are logically s
|
||||
[class]{AVLTree}-[func]{leftRotate}
|
||||
```
|
||||
|
||||
### 3. Right-left rotation
|
||||
### 3. Left-right rotation
|
||||
|
||||
For the unbalanced node 3 shown in Figure 7-30, using either left or right rotation alone cannot restore balance to the subtree. In this case, a "left rotation" needs to be performed on `child` first, followed by a "right rotation" on `node`.
|
||||
|
||||
{ class="animation-figure" }
|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> Figure 7-30 Right-left rotation </p>
|
||||
<p align="center"> Figure 7-30 Left-right rotation </p>
|
||||
|
||||
### 4. Left-right rotation
|
||||
### 4. Right-left rotation
|
||||
|
||||
As shown in Figure 7-31, for the mirror case of the above unbalanced binary tree, a "right rotation" needs to be performed on `child` first, followed by a "left rotation" on `node`.
|
||||
|
||||
{ class="animation-figure" }
|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> Figure 7-31 Left-right rotation </p>
|
||||
<p align="center"> Figure 7-31 Right-left rotation </p>
|
||||
|
||||
### 5. Choice of rotation
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ A <u>binary tree</u> is a non-linear data structure that represents the hierarch
|
||||
Left *TreeNode
|
||||
Right *TreeNode
|
||||
}
|
||||
/* 构造方法 */
|
||||
/* Constructor */
|
||||
func NewTreeNode(v int) *TreeNode {
|
||||
return &TreeNode{
|
||||
Left: nil, // Pointer to left child node
|
||||
@@ -145,7 +145,7 @@ A <u>binary tree</u> is a non-linear data structure that represents the hierarch
|
||||
}
|
||||
|
||||
impl TreeNode {
|
||||
/* 构造方法 */
|
||||
/* Constructor */
|
||||
fn new(val: i32) -> Rc<RefCell<Self>> {
|
||||
Rc::new(RefCell::new(Self {
|
||||
val,
|
||||
@@ -162,12 +162,12 @@ A <u>binary tree</u> is a non-linear data structure that represents the hierarch
|
||||
/* Binary tree node */
|
||||
typedef struct TreeNode {
|
||||
int val; // Node value
|
||||
int height; // 节点高度
|
||||
int height; // Node height
|
||||
struct TreeNode *left; // Pointer to left child node
|
||||
struct TreeNode *right; // Pointer to right child node
|
||||
} TreeNode;
|
||||
|
||||
/* 构造函数 */
|
||||
/* Constructor */
|
||||
TreeNode *newTreeNode(int val) {
|
||||
TreeNode *node;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user