Algorithm and data structure interview guide - detailed list

list

Immutable array length reduces practicality . In practice, we may not be able to determine in advance how much data needs to be stored, which makes the choice of array length difficult. If the length is too small, the array needs to be frequently expanded when data is continuously added; if the length is too large, memory space will be wasted.

To solve this problem, a data structure called "dynamic array" emerged, which is an array of variable length, also often called "list". Lists are implemented based on arrays, inherit the advantages of arrays, and can be dynamically expanded while the program is running. We can freely add elements to the list without worrying about exceeding the capacity limit.

List common operations

initialization list

We usually use two initialization methods: "no initial value" and "with initial value".

=== “Python”

```python title="list.py"
# 初始化列表
# 无初始值
list1: list[int] = []
# 有初始值
list: list[int] = [1, 3, 2, 5, 4]
```

=== “C++”

```cpp title="list.cpp"
/* 初始化列表 */
// 需注意,C++ 中 vector 即是本文描述的 list
// 无初始值
vector<int> list1;
// 有初始值
vector<int> list = { 1, 3, 2, 5, 4 };
```

=== “Java”

```java title="list.java"
/* 初始化列表 */
// 无初始值
List<Integer> list1 = new ArrayList<>();
// 有初始值(注意数组的元素类型需为 int[] 的包装类 Integer[])
Integer[] numbers = new Integer[] { 1, 3, 2, 5, 4 };
List<Integer> list = new ArrayList<>(Arrays.asList(numbers));
```

=== “C#”

```csharp title="list.cs"
/* 初始化列表 */
// 无初始值
List<int> list1 = new ();
// 有初始值
int[] numbers = new int[] { 1, 3, 2, 5, 4 };
List<int> list = numbers.ToList();
```

=== “Go”

```go title="list_test.go"
/* 初始化列表 */
// 无初始值
list1 := []int
// 有初始值
list := []int{1, 3, 2, 5, 4}
```

=== “Swift”

```swift title="list.swift"
/* 初始化列表 */
// 无初始值
let list1: [Int] = []
// 有初始值
var list = [1, 3, 2, 5, 4]
```

=== “JS”

```javascript title="list.js"
/* 初始化列表 */
// 无初始值
const list1 = [];
// 有初始值
const list = [1, 3, 2, 5, 4];
```

=== “TS”

```typescript title="list.ts"
/* 初始化列表 */
// 无初始值
const list1: number[] = [];
// 有初始值
const list: number[] = [1, 3, 2, 5, 4];
```

=== “Dart”

```dart title="list.dart"
/* 初始化列表 */
// 无初始值
List<int> list1 = [];
// 有初始值
List<int> list = [1, 3, 2, 5, 4];
```

=== “Rust”

```rust title="list.rs"
/* 初始化列表 */
// 无初始值
let list1: Vec<i32> = Vec::new();
// 有初始值
let list2: Vec<i32> = vec![1, 3, 2, 5, 4];
```

=== “C”

```c title="list.c"
// C 未提供内置动态数组
```

=== “Zig”

```zig title="list.zig"
// 初始化列表
var list = std.ArrayList(i32).init(std.heap.page_allocator);
defer list.deinit();
try list.appendSlice(&[_]i32{ 1, 3, 2, 5, 4 });
```

access element

Lists are essentially arrays, so they can be run in O ( 1 ) O(1)Access and update elements in O ( 1 ) time, which is very efficient.

=== “Python”

```python title="list.py"
# 访问元素
num: int = list[1]  # 访问索引 1 处的元素

# 更新元素
list[1] = 0    # 将索引 1 处的元素更新为 0
```

=== “C++”

```cpp title="list.cpp"
/* 访问元素 */
int num = list[1];  // 访问索引 1 处的元素

/* 更新元素 */
list[1] = 0;  // 将索引 1 处的元素更新为 0
```

=== “Java”

```java title="list.java"
/* 访问元素 */
int num = list.get(1);  // 访问索引 1 处的元素

/* 更新元素 */
list.set(1, 0);  // 将索引 1 处的元素更新为 0
```

=== “C#”

```csharp title="list.cs"
/* 访问元素 */
int num = list[1];  // 访问索引 1 处的元素

/* 更新元素 */
list[1] = 0;  // 将索引 1 处的元素更新为 0
```

=== “Go”

```go title="list_test.go"
/* 访问元素 */
num := list[1]  // 访问索引 1 处的元素

/* 更新元素 */
list[1] = 0     // 将索引 1 处的元素更新为 0
```

=== “Swift”

```swift title="list.swift"
/* 访问元素 */
let num = list[1] // 访问索引 1 处的元素

/* 更新元素 */
list[1] = 0 // 将索引 1 处的元素更新为 0
```

=== “JS”

```javascript title="list.js"
/* 访问元素 */
const num = list[1];  // 访问索引 1 处的元素

/* 更新元素 */
list[1] = 0;  // 将索引 1 处的元素更新为 0
```

=== “TS”

```typescript title="list.ts"
/* 访问元素 */
const num: number = list[1];  // 访问索引 1 处的元素

/* 更新元素 */
list[1] = 0;  // 将索引 1 处的元素更新为 0
```

=== “Dart”

```dart title="list.dart"
/* 访问元素 */
int num = list[1];  // 访问索引 1 处的元素

/* 更新元素 */
list[1] = 0;  // 将索引 1 处的元素更新为 0
```

=== “Rust”

```rust title="list.rs"
/* 访问元素 */
let num: i32 = list[1];    // 访问索引 1 处的元素
/* 更新元素 */
list[1] = 0;               // 将索引 1 处的元素更新为 0
```

=== “C”

```c title="list.c"
// C 未提供内置动态数组
```

=== “Zig”

```zig title="list.zig"
// 访问元素
var num = list.items[1]; // 访问索引 1 处的元素

// 更新元素
list.items[1] = 0; // 将索引 1 处的元素更新为 0  
```

Inserting and deleting elements

Compared to arrays, lists can add and remove elements freely. The time complexity of adding an element to the end of the list is O ( 1 ) O(1)O ( 1 ) , but the efficiency of inserting and deleting elements is still the same as that of the array, and the time complexity isO (n) O(n)O ( n )

=== “Python”

```python title="list.py"
# 清空列表
list.clear()

# 尾部添加元素
list.append(1)
list.append(3)
list.append(2)
list.append(5)
list.append(4)

# 中间插入元素
list.insert(3, 6)  # 在索引 3 处插入数字 6

# 删除元素
list.pop(3)        # 删除索引 3 处的元素
```

=== “C++”

```cpp title="list.cpp"
/* 清空列表 */
list.clear();

/* 尾部添加元素 */
list.push_back(1);
list.push_back(3);
list.push_back(2);
list.push_back(5);
list.push_back(4);

/* 中间插入元素 */
list.insert(list.begin() + 3, 6);  // 在索引 3 处插入数字 6

/* 删除元素 */
list.erase(list.begin() + 3);      // 删除索引 3 处的元素
```

=== “Java”

```java title="list.java"
/* 清空列表 */
list.clear();

/* 尾部添加元素 */
list.add(1);
list.add(3);
list.add(2);
list.add(5);
list.add(4);

/* 中间插入元素 */
list.add(3, 6);  // 在索引 3 处插入数字 6

/* 删除元素 */
list.remove(3);  // 删除索引 3 处的元素
```

=== “C#”

```csharp title="list.cs"
/* 清空列表 */
list.Clear();

/* 尾部添加元素 */
list.Add(1);
list.Add(3);
list.Add(2);
list.Add(5);
list.Add(4);

/* 中间插入元素 */
list.Insert(3, 6);

/* 删除元素 */
list.RemoveAt(3);
```

=== “Go”

```go title="list_test.go"
/* 清空列表 */
list = nil

/* 尾部添加元素 */
list = append(list, 1)
list = append(list, 3)
list = append(list, 2)
list = append(list, 5)
list = append(list, 4)

/* 中间插入元素 */
list = append(list[:3], append([]int{6}, list[3:]...)...) // 在索引 3 处插入数字 6

/* 删除元素 */
list = append(list[:3], list[4:]...) // 删除索引 3 处的元素
```

=== “Swift”

```swift title="list.swift"
/* 清空列表 */
list.removeAll()

/* 尾部添加元素 */
list.append(1)
list.append(3)
list.append(2)
list.append(5)
list.append(4)

/* 中间插入元素 */
list.insert(6, at: 3) // 在索引 3 处插入数字 6

/* 删除元素 */
list.remove(at: 3) // 删除索引 3 处的元素
```

=== “JS”

```javascript title="list.js"
/* 清空列表 */
list.length = 0;

/* 尾部添加元素 */
list.push(1);
list.push(3);
list.push(2);
list.push(5);
list.push(4);

/* 中间插入元素 */
list.splice(3, 0, 6);

/* 删除元素 */
list.splice(3, 1);
```

=== “TS”

```typescript title="list.ts"
/* 清空列表 */
list.length = 0;

/* 尾部添加元素 */
list.push(1);
list.push(3);
list.push(2);
list.push(5);
list.push(4);

/* 中间插入元素 */
list.splice(3, 0, 6);

/* 删除元素 */
list.splice(3, 1);
```

=== “Dart”

```dart title="list.dart"
/* 清空列表 */
list.clear();

/* 尾部添加元素 */
list.add(1);
list.add(3);
list.add(2);
list.add(5);
list.add(4);

/* 中间插入元素 */
list.insert(3, 6); // 在索引 3 处插入数字 6

/* 删除元素 */
list.removeAt(3); // 删除索引 3 处的元素
```

=== “Rust”

```rust title="list.rs"
/* 清空列表 */
list.clear();

/* 尾部添加元素 */
list.push(1);
list.push(3);
list.push(2);
list.push(5);
list.push(4);

/* 中间插入元素 */
list.insert(3, 6);  // 在索引 3 处插入数字 6

/* 删除元素 */
list.remove(3);    // 删除索引 3 处的元素
```

=== “C”

```c title="list.c"
// C 未提供内置动态数组
```

=== “Zig”

```zig title="list.zig"
// 清空列表
list.clearRetainingCapacity();

// 尾部添加元素
try list.append(1);
try list.append(3);
try list.append(2);
try list.append(5);
try list.append(4);

// 中间插入元素
try list.insert(3, 6); // 在索引 3 处插入数字 6

// 删除元素
_ = list.orderedRemove(3); // 删除索引 3 处的元素
```

Traverse the list

Like arrays, lists can be traversed based on index, or individual elements can be traversed directly.

=== “Python”

```python title="list.py"
# 通过索引遍历列表
count = 0
for i in range(len(list)):
    count += 1

# 直接遍历列表元素
count = 0
for n in list:
    count += 1
```

=== “C++”

```cpp title="list.cpp"
/* 通过索引遍历列表 */
int count = 0;
for (int i = 0; i < list.size(); i++) {
    count++;
}

/* 直接遍历列表元素 */
count = 0;
for (int n : list) {
    count++;
}
```

=== “Java”

```java title="list.java"
/* 通过索引遍历列表 */
int count = 0;
for (int i = 0; i < list.size(); i++) {
    count++;
}

/* 直接遍历列表元素 */
count = 0;
for (int n : list) {
    count++;
}
```

=== “C#”

```csharp title="list.cs"
/* 通过索引遍历列表 */
int count = 0;
for (int i = 0; i < list.Count; i++) {
    count++;
}

/* 直接遍历列表元素 */
count = 0;
foreach (int n in list) {
    count++;
}
```

=== “Go”

```go title="list_test.go"
/* 通过索引遍历列表 */
count := 0
for i := 0; i < len(list); i++ {
    count++
}

/* 直接遍历列表元素 */
count = 0
for range list {
    count++
}
```

=== “Swift”

```swift title="list.swift"
/* 通过索引遍历列表 */
var count = 0
for _ in list.indices {
    count += 1
}

/* 直接遍历列表元素 */
count = 0
for _ in list {
    count += 1
}
```

=== “JS”

```javascript title="list.js"
/* 通过索引遍历列表 */
let count = 0;
for (let i = 0; i < list.length; i++) {
    count++;
}

/* 直接遍历列表元素 */
count = 0;
for (const n of list) {
    count++;
}
```

=== “TS”

```typescript title="list.ts"
/* 通过索引遍历列表 */
let count = 0;
for (let i = 0; i < list.length; i++) {
    count++;
}

/* 直接遍历列表元素 */
count = 0;
for (const n of list) {
    count++;
}
```

=== “Dart”

```dart title="list.dart"
/* 通过索引遍历列表 */
int count = 0;
for (int i = 0; i < list.length; i++) {
    count++;
}

/* 直接遍历列表元素 */
count = 0;
for (int n in list) {
    count++;
}
```

=== “Rust”

```rust title="list.rs"
/* 通过索引遍历列表 */
let mut count = 0;
for (index, value) in list.iter().enumerate() {
    count += 1;
}

/* 直接遍历列表元素 */
let mut count = 0;
for value in list.iter() {
    count += 1;
}
```

=== “C”

```c title="list.c"
// C 未提供内置动态数组
```

=== “Zig”

```zig title="list.zig"
// 通过索引遍历列表
var count: i32 = 0;
var i: i32 = 0;
while (i < list.items.len) : (i += 1) {
    count += 1;
}

// 直接遍历列表元素
count = 0;
for (list.items) |_| {
    count += 1;
}
```

splice list

Given a new list list1, we can concatenate the list to the end of the original list.

=== “Python”

```python title="list.py"
# 拼接两个列表
list1: list[int] = [6, 8, 7, 10, 9]
list += list1  # 将列表 list1 拼接到 list 之后
```

=== “C++”

```cpp title="list.cpp"
/* 拼接两个列表 */
vector<int> list1 = { 6, 8, 7, 10, 9 };
// 将列表 list1 拼接到 list 之后
list.insert(list.end(), list1.begin(), list1.end());
```

=== “Java”

```java title="list.java"
/* 拼接两个列表 */
List<Integer> list1 = new ArrayList<>(Arrays.asList(new Integer[] { 6, 8, 7, 10, 9 }));
list.addAll(list1);  // 将列表 list1 拼接到 list 之后
```

=== “C#”

```csharp title="list.cs"
/* 拼接两个列表 */
List<int> list1 = new() { 6, 8, 7, 10, 9 };
list.AddRange(list1);  // 将列表 list1 拼接到 list 之后
```

=== “Go”

```go title="list_test.go"
/* 拼接两个列表 */
list1 := []int{6, 8, 7, 10, 9}
list = append(list, list1...)  // 将列表 list1 拼接到 list 之后
```

=== “Swift”

```swift title="list.swift"
/* 拼接两个列表 */
let list1 = [6, 8, 7, 10, 9]
list.append(contentsOf: list1) // 将列表 list1 拼接到 list 之后
```

=== “JS”

```javascript title="list.js"
/* 拼接两个列表 */
const list1 = [6, 8, 7, 10, 9];
list.push(...list1);  // 将列表 list1 拼接到 list 之后
```

=== “TS”

```typescript title="list.ts"
/* 拼接两个列表 */
const list1: number[] = [6, 8, 7, 10, 9];
list.push(...list1);  // 将列表 list1 拼接到 list 之后
```

=== “Dart”

```dart title="list.dart"
/* 拼接两个列表 */
List<int> list1 = [6, 8, 7, 10, 9];
list.addAll(list1);  // 将列表 list1 拼接到 list 之后
```

=== “Rust”

```rust title="list.rs"
/* 拼接两个列表 */
let list1: Vec<i32> = vec![6, 8, 7, 10, 9];
list.extend(list1);
```

=== “C”

```c title="list.c"
// C 未提供内置动态数组
```

=== “Zig”

```zig title="list.zig"
// 拼接两个列表
var list1 = std.ArrayList(i32).init(std.heap.page_allocator);
defer list1.deinit();
try list1.appendSlice(&[_]i32{ 6, 8, 7, 10, 9 });
try list.insertSlice(list.items.len, list1.items); // 将列表 list1 拼接到 list 之后
```

sorted list

After sorting the list, we can use the "binary search" and "double pointer" algorithms that are often examined in array algorithm problems.

=== “Python”

```python title="list.py"
# 排序列表
list.sort()  # 排序后,列表元素从小到大排列
```

=== “C++”

```cpp title="list.cpp"
/* 排序列表 */
sort(list.begin(), list.end());  // 排序后,列表元素从小到大排列
```

=== “Java”

```java title="list.java"
/* 排序列表 */
Collections.sort(list);  // 排序后,列表元素从小到大排列
```

=== “C#”

```csharp title="list.cs"
/* 排序列表 */
list.Sort(); // 排序后,列表元素从小到大排列
```

=== “Go”

```go title="list_test.go"
/* 排序列表 */
sort.Ints(list)  // 排序后,列表元素从小到大排列
```

=== “Swift”

```swift title="list.swift"
/* 排序列表 */
list.sort() // 排序后,列表元素从小到大排列
```

=== “JS”

```javascript title="list.js"
/* 排序列表 */  
list.sort((a, b) => a - b);  // 排序后,列表元素从小到大排列
```

=== “TS”

```typescript title="list.ts"
/* 排序列表 */
list.sort((a, b) => a - b);  // 排序后,列表元素从小到大排列
```

=== “Dart”

```dart title="list.dart"
/* 排序列表 */
list.sort(); // 排序后,列表元素从小到大排列
```

=== “Rust”

```rust title="list.rs"
/* 排序列表 */
list.sort(); // 排序后,列表元素从小到大排列
```

=== “C”

```c title="list.c"
// C 未提供内置动态数组
```

=== “Zig”

```zig title="list.zig"
// 排序列表
std.sort.sort(i32, list.items, {}, comptime std.sort.asc(i32));
```

List implementation

Many programming languages ​​provide built-in lists, such as Java, C++, Python, etc. Their implementation is relatively complex, and the setting of each parameter is also very sophisticated, such as initial capacity, expansion multiple, etc. Interested readers can check the source code to learn.

In order to deepen our understanding of how lists work, we try to implement a simplified version of the list, including the following three key designs.

  • Initial capacity : Choose a reasonable initial capacity of the array. In this example, we choose 10 as the initial capacity.
  • Quantity record : Declare a variable size to record the current number of elements in the list, and update it in real time as elements are inserted and deleted. Based on this variable, we can locate the end of the list and determine whether expansion is needed.
  • Expansion mechanism : If the list capacity is full when elements are inserted, expansion is required. First create a larger array based on the expansion multiple, and then move all elements of the current array to the new array in sequence. In this example, we stipulate that the array will be expanded to 2 times the previous size each time.

=== “Python”

```python title="my_list.py"
[class]{MyList}-[func]{}
```

=== “C++”

```cpp title="my_list.cpp"
[class]{MyList}-[func]{}
```

=== “Java”

```java title="my_list.java"
[class]{MyList}-[func]{}
```

=== “C#”

```csharp title="my_list.cs"
[class]{MyList}-[func]{}
```

=== “Go”

```go title="my_list.go"
[class]{myList}-[func]{}
```

=== “Swift”

```swift title="my_list.swift"
[class]{MyList}-[func]{}
```

=== “JS”

```javascript title="my_list.js"
[class]{MyList}-[func]{}
```

=== “TS”

```typescript title="my_list.ts"
[class]{MyList}-[func]{}
```

=== “Dart”

```dart title="my_list.dart"
[class]{MyList}-[func]{}
```

=== “Rust”

```rust title="my_list.rs"
[class]{MyList}-[func]{}
```

=== “C”

```c title="my_list.c"
[class]{myList}-[func]{}
```

=== “Zig”

```zig title="my_list.zig"
[class]{MyList}-[func]{}
```

Guess you like

Origin blog.csdn.net/zy_dreamer/article/details/132865256