单向链表的创建和遍历方法详解
发布时间: 2024-05-02 02:53:47 阅读量: 89 订阅数: 52
创建和遍历链表
![单向链表的创建和遍历方法详解](https://img-blog.csdnimg.cn/20210320210202867.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MzY4MDA3,size_16,color_FFFFFF,t_70)
# 1. 单向链表的基本概念和数据结构**
单向链表是一种线性数据结构,由一系列节点组成,每个节点包含一个数据元素和指向下一个节点的指针。与数组不同,单向链表中的节点在内存中不一定是连续存储的,它们通过指针连接在一起。
单向链表节点的数据结构通常包括两个成员:
* **data:**存储数据元素,可以是任何数据类型。
* **next:**指向下一个节点的指针,如果当前节点是链表的最后一个节点,则为 `NULL`。
# 2. 单向链表的创建和初始化
### 2.1 创建单向链表的步骤
创建单向链表的过程主要包括以下步骤:
1. **定义节点结构:**首先,定义一个节点结构,该结构包含数据域和指向下一个节点的指针域。
2. **分配内存:**为每个节点分配内存空间。
3. **设置数据域:**将数据存储在节点的数据域中。
4. **设置指针域:**将节点的指针域指向下一个节点,或者在最后一个节点的情况下指向 `NULL`。
### 2.2 单向链表节点的数据结构
单向链表的节点通常使用以下数据结构:
```cpp
struct Node {
int data; // 数据域
Node* next; // 指向下一个节点的指针域
};
```
### 2.3 初始化单向链表
初始化单向链表涉及以下步骤:
1. **分配头节点:**为头节点分配内存空间。
2. **设置头节点指针:**将头节点指针设置为 `NULL`,表示空链表。
```cpp
Node* head = NULL; // 头节点指针
```
### 代码示例
以下代码演示了如何创建和初始化一个单向链表:
```cpp
#include <iostream>
using namespace std;
struct Node {
int data;
Node* next;
};
int main() {
// 创建节点
Node* node1 = new Node;
node1->data = 10;
Node* node2 = new Node;
node2->data = 20;
// 设置指针域
node1->next = node2;
node2->next = NULL;
// 初始化头节点
Node* head = node1;
// 遍历链表
Node* current = head;
while (current != NULL) {
cout << current->data << " ";
current = current->next;
}
return 0;
}
```
### 代码逻辑分析
1. 创建两个节点 `node1` 和 `node2`,并为它们分配内存空间。
2. 设置节点 `node1` 的数据域为 10,节点 `node2` 的数据域为 20。
3. 将节点 `node1` 的指针域指向节点 `node2`,将节点 `node2` 的指针域指向 `NULL`。
4. 将头节点指针 `head` 指向节点 `node1`,表示链表的开始。
5. 遍历链表,从头节点开始,依次访问每个节点并打印其数据域。
# 3.1 头部插入
头部插入是指将新节点插入到链表的头部,成为新的头节点。具体步骤如下:
1. 创建新节点:创建一个新的节点,并为其分配数据和指针。
2. 将新节点的指针指向原头节点:将新节点的 `next` 指针指向原头节点。
3. 更新头节点指针:将链表的头节点指针指向新节点。
```python
def insert_at_head(self, data):
"""
在链表头部插入一个新节点
参数:
data: 要插入的数据
"""
new_node = Node(data)
new_node.next = self.head
self.head = new_node
```
**代码逻辑逐行解读:**
* `new_node = Node(data)`:创建一个新的节点,并为其分配数据。
* `new_node.next = self.head`:将新节点的 `next` 指针指向原头节点。
* `self.head = new_node`:更新链表的头节点指针指向新节点。
**参数说明:**
* `data`:要插入到链表头部的数据。
### 3.2 尾部插入
尾部插入是指将新节点插入到链表的尾部,成为新的尾节点。具体步骤如下:
1. 创建新节点:创建一个新的节点,并为其分配数据和指针。
2. 遍历链表找到尾节点:遍历链表,直到找到 `next` 指针为 `None` 的尾节点。
3. 将新节点的指针指向 `None`:将新节点的 `next` 指针指向 `None`。
4. 将尾节点的指针指向新节点:将尾节点的 `next` 指针指向新节点。
```python
def insert_at_tail(self, data):
"""
在链表尾部插入一个新节点
参数:
data: 要插入的数据
"""
new_node = Node(data)
if self.head is None:
self.head = new_node
else:
current = self.head
while current.next is not None:
current = current.next
current.next = new_node
```
**代码逻辑逐行解读:**
* `new_node = Node(data)`:创建一个新的节点,并为其分配数据。
* `if self.head is None:`:判断链表是否为空,如果是,则将新节点作为头节点。
* `else:`:如果链表不为空,则执行以下操作:
* `current = self.head`:将当前指针指向头节点。
* `while current.next is not None:`:遍历链表,直到找到尾节点。
* `current = current.next`:将当前指针指向下一个节点。
* `current.next = new_node`:将尾节点的 `next` 指针指向新节点。
**参数说明:**
* `data`:要插入到链表尾部的数据。
### 3.3 中间插入
中间插入是指将新节点插入到链表的指定位置,成为该位置的下一个节点。具体步骤如下:
1. 创建新节点:创建一个新的节点,并为其分配数据和指针。
2. 遍历链表找到插入位置的前一个节点:遍历链表,直到找到要插入位置的前一个节点。
3. 将新节点的指针指向插入位置的前一个节点的下一个节点:将新节点的 `next` 指针指向插入位置的前一个节点的 `next` 指针。
4. 将插入位置的前一个节点的指针指向新节点:将插入位置的前一个节点的 `next` 指针指向新节点。
```python
def insert_at_index(self, index, data):
"""
在链表指定位置插入一个新节点
参数:
index: 要插入的位置
data: 要插入的数据
"""
if index < 0 or index > self.length():
raise IndexError("Index out of range")
new_node = Node(data)
if index == 0:
self.insert_at_head(data)
else:
current = self.head
for _ in range(index - 1):
current = current.next
new_node.next = current.next
current.next = new_node
```
**代码逻辑逐行解读:**
* `if index < 0 or index > self.length():`:判断插入位置是否合法,如果非法,则抛出 `IndexError` 异常。
* `new_node = Node(data)`:创建一个新的节点,并为其分配数据。
* `if index == 0:`:判断是否在头部插入,如果是,则调用 `insert_at_head` 方法。
* `else:`:如果不在头部插入,则执行以下操作:
* `current = self.head`:将当前指针指向头节点。
* `for _ in range(index - 1):`:遍历链表,找到插入位置的前一个节点。
* `current = current.next`:将当前指针指向下一个节点。
* `new_node.next = current.next`:将新节点的 `next` 指针指向插入位置的前一个节点的 `next` 指针。
* `current.next = new_node`:将插入位置的前一个节点的 `next` 指针指向新节点。
**参数说明:**
* `index`:要插入的位置。
* `data`:要插入的数据。
### 3.4 头部删除
头部删除是指删除链表的第一个节点,并将头节点指针指向下一个节点。具体步骤如下:
1. 判断链表是否为空:如果链表为空,则返回。
2. 将头节点指针指向下一个节点:将链表的头节点指针指向原头节点的下一个节点。
3. 删除原头节点:释放原头节点的内存空间。
```python
def delete_at_head(self):
"""
删除链表头部节点
"""
if self.head is None:
return
self.head = self.head.next
```
**代码逻辑逐行解读:**
* `if self.head is None:`:判断链表是否为空,如果是,则返回。
* `self.head = self.head.next`:将链表的头节点指针指向原头节点的下一个节点。
### 3.5 尾部删除
尾部删除是指删除链表的最后一个节点,并将尾节点指针指向最后一个节点的前一个节点。具体步骤如下:
1. 判断链表是否为空:如果链表为空,则返回。
2. 遍历链表找到尾节点的前一个节点:遍历链表,直到找到尾节点的前一个节点。
3. 将尾节点的前一个节点的指针指向 `None`:将尾节点的前一个节点的 `next` 指针指向 `None`。
4. 删除尾节点:释放尾节点的内存空间。
```python
def delete_at_tail(self):
"""
删除链表尾部节点
"""
if self.head is None:
return
if self.head.next is None:
self.head = None
else:
current = self.head
while current.next.next is not None:
current = current.next
current.next = None
```
**代码逻辑逐行解读:**
* `if self.head is None:`:判断链表是否为空,如果是,则返回。
* `if self.head.next is None:`:判断链表是否只有一个节点,如果是,则将头节点指针指向 `None`。
* `else:`:如果链表有多个节点,则执行以下操作:
* `current = self.head`:将当前指针指向头节点。
* `while current.next.next is not None:`:遍历链表,找到尾节点的前一个节点。
* `current = current.next`:将当前指针指向下一个节点。
* `current.next = None`:将尾节点的前一个节点的 `next` 指针指向 `None`。
### 3.6 中间删除
中间删除是指删除链表中指定位置的节点,并将该节点的前一个节点的指针指向该节点的下一个节点。具体步骤如下:
1. 判断链表是否为空:如果链表为空,则返回。
2. 判断删除位置是否合法:如果删除位置不合法,则抛出 `IndexError` 异常。
3. 遍历链表找到删除位置的前一个节点:遍历链表,直到找到删除位置的前一个节点。
4. 将删除位置的前一个节点的指针指向删除位置的下一个节点:将删除位置的前一个节点的 `next` 指针指向删除位置的下一个节点。
5. 删除删除位置的节点:释放删除位置的节点的内存空间。
```python
def delete_at_index(self, index):
"""
删除链表指定位置的节点
参数:
index: 要删除的位置
"""
if index < 0 or index >= self.length():
raise IndexError("
# 4. 单向链表的遍历方法
### 4.1 顺序遍历
顺序遍历是指从链表头结点开始,依次访问每个节点,直到链表尾结点。实现顺序遍历的方法如下:
```python
def traverse_forward(head):
"""
顺序遍历单向链表
:param head: 链表头结点
"""
current = head
while current is not None:
print(current.data)
current = current.next
```
**代码逻辑分析:**
1. 初始化当前指针 `current` 为链表头结点。
2. 循环遍历链表,直到 `current` 指向 `None`(即链表尾结点)。
3. 在每次循环中,打印当前节点的数据 `current.data`。
4. 将 `current` 指针移动到下一个节点。
### 4.2 逆序遍历
逆序遍历是指从链表尾结点开始,依次访问每个节点,直到链表头结点。实现逆序遍历的方法如下:
```python
def traverse_backward(head):
"""
逆序遍历单向链表
:param head: 链表头结点
"""
if head is None:
return
# 递归调用逆序遍历链表的剩余部分
traverse_backward(head.next)
# 打印当前节点的数据
print(head.data)
```
**代码逻辑分析:**
1. 递归基线:如果链表为空(`head` 为 `None`),则返回。
2. 递归调用:逆序遍历链表的剩余部分(`head.next`)。
3. 打印当前节点的数据。
### 4.3 查找特定元素
查找特定元素是指给定一个值,在链表中找到包含该值的节点。实现查找特定元素的方法如下:
```python
def find_element(head, target):
"""
查找单向链表中特定元素
:param head: 链表头结点
:param target: 要查找的元素
:return: 包含目标元素的节点,如果没有找到则返回 None
"""
current = head
while current is not None:
if current.data == target:
return current
current = current.next
return None
```
**代码逻辑分析:**
1. 初始化当前指针 `current` 为链表头结点。
2. 循环遍历链表,直到 `current` 指向 `None`(即链表尾结点)。
3. 在每次循环中,检查当前节点的数据 `current.data` 是否等于目标元素 `target`。
4. 如果找到目标元素,则返回包含该元素的节点。
5. 如果遍历完整个链表都没有找到目标元素,则返回 `None`。
### 4.4 删除特定元素
删除特定元素是指给定一个值,从链表中删除包含该值的节点。实现删除特定元素的方法如下:
```python
def delete_element(head, target):
"""
删除单向链表中特定元素
:param head: 链表头结点
:param target: 要删除的元素
:return: 删除后的链表头结点
"""
if head is None:
return None
# 如果头结点就是要删除的元素
if head.data == target:
return head.next
# 否则,递归删除链表的剩余部分
head.next = delete_element(head.next, target)
return head
```
**代码逻辑分析:**
1. 递归基线:如果链表为空(`head` 为 `None`),则返回 `None`。
2. 如果头结点就是要删除的元素,则返回头结点的下一个节点。
3. 否则,递归删除链表的剩余部分(`head.next`)。
4. 将头结点的 `next` 指针指向递归删除后的链表。
5. 返回删除后的链表头结点。
# 5. 单向链表的应用场景
单向链表是一种基础的数据结构,在计算机科学和软件开发中有着广泛的应用。本章将探讨单向链表在不同场景中的应用,包括队列和栈的实现、广度优先搜索和深度优先搜索、链表的排序和合并。
### 5.1 队列和栈的实现
队列和栈是两种基本的数据结构,分别遵循先进先出(FIFO)和后进先出(LIFO)的原则。使用单向链表可以轻松实现队列和栈。
**队列的实现:**
```python
class Queue:
def __init__(self):
self.head = None
self.tail = None
def enqueue(self, value):
new_node = Node(value)
if self.tail is None:
self.head = new_node
else:
self.tail.next = new_node
self.tail = new_node
def dequeue(self):
if self.head is None:
return None
value = self.head.value
self.head = self.head.next
if self.head is None:
self.tail = None
return value
```
**栈的实现:**
```python
class Stack:
def __init__(self):
self.top = None
def push(self, value):
new_node = Node(value)
new_node.next = self.top
self.top = new_node
def pop(self):
if self.top is None:
return None
value = self.top.value
self.top = self.top.next
return value
```
### 5.2 广度优先搜索和深度优先搜索
广度优先搜索(BFS)和深度优先搜索(DFS)是两种常见的图搜索算法。使用单向链表可以方便地实现BFS和DFS。
**广度优先搜索(BFS):**
BFS从根节点开始,逐层遍历图中的所有节点。使用队列来存储待访问的节点,每次从队列中取出一个节点,访问其所有未访问的邻接节点,并将其加入队列中。
```python
def bfs(graph, root):
queue = [root]
visited = set()
while queue:
node = queue.pop(0)
if node not in visited:
visited.add(node)
for neighbor in graph[node]:
if neighbor not in visited:
queue.append(neighbor)
```
**深度优先搜索(DFS):**
DFS从根节点开始,沿着一條路徑一直向下探索,直到遇到死胡同。使用栈来存储待访问的节点,每次从栈中取出一个节点,访问其所有未访问的邻接节点,并将其加入栈中。
```python
def dfs(graph, root):
stack = [root]
visited = set()
while stack:
node = stack.pop()
if node not in visited:
visited.add(node)
for neighbor in graph[node]:
if neighbor not in visited:
stack.append(neighbor)
```
### 5.3 链表的排序和合并
单向链表也可以用于对数据进行排序和合并。
**链表排序:**
使用归并排序算法可以对链表进行排序。归并排序将链表分成两个较小的子链表,对子链表进行排序,然后合并排序后的子链表。
```python
def merge_sort(head):
if head is None or head.next is None:
return head
mid = get_middle(head)
left_half = merge_sort(head)
right_half = merge_sort(mid.next)
return merge(left_half, right_half)
def merge(left, right):
dummy = Node(0)
current = dummy
while left and right:
if left.value < right.value:
current.next = left
left = left.next
else:
current.next = right
right = right.next
current = current.next
current.next = left or right
return dummy.next
```
**链表合并:**
将两个有序链表合并为一个有序链表。使用两个指针分别指向两个链表的头部,比较两个指针指向的节点的值,将较小的节点加入到合并后的链表中,然后移动相应的指针。
```python
def merge_lists(head1, head2):
dummy = Node(0)
current = dummy
while head1 and head2:
if head1.value < head2.value:
current.next = head1
head1 = head1.next
else:
current.next = head2
head2 = head2.next
current = current.next
current.next = head1 or head2
return dummy.next
```
# 6.1 循环单向链表
在单向链表的基础上,循环单向链表将最后一个节点的next指针指向第一个节点,形成一个闭合的环形结构。这种结构具有以下优点:
- **无需维护尾节点指针:**由于最后一个节点的next指针指向第一个节点,因此不需要维护尾节点指针。
- **遍历效率更高:**在循环单向链表中,遍历时无需判断是否到达尾节点,可以一直遍历下去。
- **空间占用更小:**由于不需要维护尾节点指针,因此循环单向链表的空间占用更小。
### 创建循环单向链表
创建循环单向链表的步骤如下:
1. 创建一个头节点,并将其next指针指向自身。
2. 根据需要插入节点,并将其next指针指向头节点。
```python
class Node:
def __init__(self, data):
self.data = data
self.next = None
class CircularLinkedList:
def __init__(self):
self.head = None
def insert(self, data):
new_node = Node(data)
if self.head is None:
self.head = new_node
new_node.next = self.head
else:
current = self.head
while current.next != self.head:
current = current.next
current.next = new_node
new_node.next = self.head
```
### 遍历循环单向链表
遍历循环单向链表的方法如下:
1. 从头节点开始遍历。
2. 每次遍历一个节点,将next指针指向的节点作为下一个节点。
3. 当下一个节点等于头节点时,遍历结束。
```python
def traverse(self):
current = self.head
while current.next != self.head:
print(current.data)
current = current.next
print(current.data)
```
0
0