Chúng tôi đã thảo luận về một giải pháp lặp lại để đảo ngược danh sách được liên kết trong bài viết trước. Trong bài đăng này, chúng tôi sẽ đề cập đến việc thực hiện đệ quy của nó
Sau đây là cách triển khai đệ quy đơn giản hoạt động bằng cách sửa con trỏ .next
của các nút của danh sách và cuối cùng là con trỏ đầu. Có lẽ phần khó nhất là chấp nhận khái niệm rằng reverse[&rest, head]
đảo ngược phần còn lại. Sau đó, có một mẹo để lấy một nút phía trước ở cuối danh sách. Chúng tôi khuyên bạn nên vẽ một bản vẽ để xem thủ thuật hoạt động như thế nào
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include
#include
// Một nút danh sách liên kết
struct Nút
{
int dữ liệu;
struct Nút* tiếp theo;
};
// Hàm trợ giúp để in danh sách liên kết đã cho
void printList[struct Nút* head]
{
struct Nút* ptr = head;
trong khi [ptr]
{
printf["%d —> ", ptr->data];
ptr = ptr->next;
}
printf["NULL\n"]dữ liệu = data;
newNode->next = *head;
*head = newNode;
}
// Hàm đệ quy để đảo ngược danh sách liên kết đã cho. Nó đảo ngược
// danh sách liên kết đã cho bằng cách cố định con trỏ đầu và sau đó `. tiếp theo`
// con trỏ của mọi nút theo thứ tự ngược lại
void recursiveReverse[struct Nút* head, struct Node** headRef]
{
struct Nút* đầu tiên;
struct Nút* phần còn lại;
// trường hợp cơ sở danh sách trống
nếu [đầu == NULL] {
trả lại;
}
đầu = đầu; // suppose first = {1, 2, 3}
nghỉ ngơi = đầu tiên->next; // rest = {2, 3}
// trường hợp cơ bản. danh sách chỉ có một nút
nếu [nghỉ ngơi == NULL]
{
// sửa con trỏ đầu ở đây
*headRef = đầu tiên;
trả lại;
}
// đảo ngược đệ quy trường hợp {2, 3} nhỏ hơn
// sau. phần còn lại = {3, 2}
recursiveReverse[rest, headRef];
// đặt mục đầu tiên vào cuối danh sách
nghỉ ngơi->tiếp theo = first;
đầu tiên->tiếp theo = NULL; // [tricky step — make a drawing]
}
// Đảo ngược danh sách liên kết đã cho. Hàm lấy một con trỏ
// [tham chiếu] đến con trỏ đầu
void reverse[struct Nút** head] {
recursiveReverse[*head, head];
}
int chính[void]
{
// phím nhập
int phím[] = { 1, 2, 3, 4, 5, 6 };
int n = sizeof[keys]/sizeof[keys[0]];
struct Nút* đầu = NULL;
cho [int i = n - 1; i >=0; i--] {
đẩy[&đầu, keys[i]];
}
lùi[&ngửa];
printList[đầu];
return 0;
}
Tải xuống Chạy mã
Đầu ra.
6 —> 5 —> 4 —> 3 —> 2 —> 1 —> NULL
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include
#include
sử dụng không gian tên std;
// Một nút danh sách liên kết
struct Nút
{
int dữ liệu;
Nút* tiếp theo;
};
// Hàm trợ giúp để in danh sách liên kết đã cho
void printList[Nút* head]
{
Nút* ptr = head;
trong khi [ptr]
{
cout =0; i--] {
đẩy[đầu, keys[i]];
}
lùi[đầu];
printList[đầu];
return 0;
}
Tải xuống Chạy mã
Đầu ra.
6 —> 5 —> 4 —> 3 —> 2 —> 1 —> nullptr
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// Một nút danh sách liên kết
lớp Nút
{
int dữ liệu;
Nút tiếp theo;
Nút[int dữ liệu] {
cái này. dữ liệu = dữ liệu;
}
}
lớp Chính
{
// Hàm trợ giúp để in danh sách liên kết đã cho
công khai tĩnh vô hiệu printList[Node head]
{
Nút ptr = đầu;
trong khi [ptr . = null]
{
Hệ thống. ra. in[ptr. dữ liệu + " —> "];
ptr = ptr. tiếp theo;
}
Hệ thống. ra. println["null"];
}
// Hàm trợ giúp để chèn một nút mới vào đầu danh sách được liên kết
công khai tĩnh Nút đẩy[Node head, int data]
{
Nút nút = mới Node[data];
nút. tiếp theo = đầu;
return node;
}
// Hàm đệ quy để đảo ngược danh sách liên kết đã cho. Nó đảo ngược
// danh sách được liên kết đã cho bằng cách cố định con trỏ đầu và sau đó `. tiếp`
// con trỏ của mọi nút theo thứ tự đảo ngược
công khai tĩnh Nút nghịch[Node head, Node headRef]
{
Nút đầu tiên, nghỉ ngơi;
// trường hợp cơ sở danh sách trống
nếu [đầu == null] {
return headRef;
}
đầu = đầu; // suppose first = {1, 2, 3}
nghỉ ngơi = trước. tiếp theo; // phần còn lại = {2, 3}
// trường hợp cơ bản. danh sách chỉ có một nút
nếu [nghỉ ngơi == null]
{
// sửa con trỏ đầu ở đây
headRef = đầu tiên;
return headRef;
}
// đảo ngược đệ quy trường hợp {2, 3} nhỏ hơn
// sau. phần còn lại = {3, 2}
headRef = reverse[rest, headRef];
// đặt mục đầu tiên vào cuối danh sách
nghỉ ngơi. tiếp theo = đầu tiên;
đầu tiên. tiếp theo = null; =0; i--] {
đầu = đẩy[head, keys[i]];
}
đầu = lùi[head];
inDanh sách[đầu];
}
}
Tải xuống Chạy mã
Đầu ra.
6 —> 5 —> 4 —> 3 —> 2 —> 1 —> null
con trăn
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# Nút danh sách được liên kết
lớp Nút.
def __init__[self, data, next=None]:
bản thân. dữ liệu = dữ liệu
bản thân. tiếp theo = tiếp theo
# Hàm in danh sách liên kết cho trước
def printList[đầu]:
ptr = đầu
while ptr.
in[ptr. dữ liệu, kết thúc=']
ptr = ptr. tiếp theo
in['Không']
# Hàm đệ quy để đảo ngược danh sách liên kết đã cho. Nó đảo ngược
# đã cho danh sách liên kết bằng cách cố định con trỏ đầu và sau đó `. tiếp theo`
# con trỏ của mọi nút theo thứ tự ngược lại
def ngược[đầu, headRef]:
# trường hợp cơ sở danh sách trống
nếu đầu là Không có:
return headRef
đầu = đầu # suppose first = [1, 2, 3]
nghỉ ngơi = trước. tiếp theo # rest = [2, 3]
# trường hợp cơ bản. danh sách chỉ có một nút
nếu nghỉ ngơi là Không:
# sửa con trỏ theo đầu tại đây
headRef = đầu tiên
return headRef
# đảo ngược đệ quy trường hợp {2, 3} nhỏ hơn
# sau. còn lại = [3, 2]
headRef = reverse[rest, headRef]
# đặt mục đầu tiên vào cuối danh sách
nghỉ ngơi. tiếp theo = đầu tiên
đầu tiên. tiếp theo = Không có # [
return headRef
# Đảo ngược danh sách liên kết đã cho
def reverseList[head]:
quay lại ngược lại[đầu, head]
if __name__ == '__main__'.
đầu = Không
cho i trong đảo ngược[range[6]]:
đầu = Nút[i + 1, head]
đầu = reverseList[head]
printList[đầu]
Tải xuống Chạy mã
Đầu ra.
6 —> 5 —> 4 —> 3 —> 2 —> 1 —> Không có
Chúng ta cũng có thể giải quyết vấn đề này bằng cách chỉ chuyển tham chiếu đến con trỏ head đến hàm, như minh họa bên dưới
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include
#include
// Một nút danh sách liên kết
struct Nút
{
int dữ liệu;
struct Nút* tiếp theo;
};
// Hàm trợ giúp để in danh sách liên kết đã cho
void printList[struct Nút* head]
{
struct Nút* ptr = head;
trong khi [ptr]
{
printf["%d —> ", ptr->data];
ptr = ptr->next;
}
printf["NULL\n"]dữ liệu = data;
newNode->next = *head;
*head = newNode;
}
// Hàm đệ quy đảo ngược danh sách liên kết. Nó đảo ngược đã cho
// danh sách được liên kết bằng cách cố định con trỏ đầu và sau đó `. con trỏ next`
// của mọi nút theo thứ tự ngược lại
void reverse[struct Nút** head]
{
struct Nút* đầu tiên;
struct Nút* phần còn lại;
// trường hợp cơ sở danh sách trống
nếu [*đầu == NULL] {
trả lại;
}
đầu = *đầu; // suppose first = {1, 2, 3}
nghỉ ngơi = đầu tiên->next; // rest = {2, 3}
// trường hợp cơ sở còn lại trống
nếu [nghỉ ngơi == NULL] {
trả lại;
}
đảo ngược[&nghỉ ngơi]; // recursively reverse the smaller {2, 3} case
// sau. phần còn lại = {3, 2}
đầu tiên->tiếp theo->next = first; // put the first item at the end of the list
đầu tiên->tiếp theo = NULL; // [tricky step — make a drawing]
*đầu = nghỉ ngơi; // fix the head pointer
}
int chính[void]
{
// phím nhập
int phím[] = { 1, 2, 3, 4, 5, 6 };
int n = sizeof[keys]/sizeof[keys[0]];
struct Nút* đầu = NULL;
cho [int i = n - 1; i >=0; i--] {
đẩy[&đầu, keys[i]];
}
lùi[&ngửa];
printList[đầu];
return 0;
}
Tải xuống Chạy mã
Đầu ra.
6 —> 5 —> 4 —> 3 —> 2 —> 1 —> NULL
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include
#include
sử dụng không gian tên std;
// Một nút danh sách liên kết
struct Nút
{
int dữ liệu;
Nút* tiếp theo;
};
// Hàm trợ giúp để in danh sách liên kết đã cho
void printList[Nút* head]
{
Nút* ptr = head;
trong khi [ptr]
{
cout tiếp theo = nullptr; // [tricky step — make a drawing]
headRef = nghỉ ngơi; // fix the head pointer
}
int chính[]
{
// phím nhập
vectơ keys = { 1, 2, 3, 4, 5, 6 };
Nút* đầu = nullptr;
cho [int i = keys.kích thước[] - 1; i >=0; i--] {
đẩy[đầu, keys[i]];
}
lùi[đầu];
printList[đầu];
return 0;
}
Tải xuống Chạy mã
Đầu ra.
6 —> 5 —> 4 —> 3 —> 2 —> 1 —> nullptr
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// Một nút danh sách liên kết
lớp Nút
{
int dữ liệu;
Nút tiếp theo;
Nút[int dữ liệu] {
cái này. dữ liệu = dữ liệu;
}
}
lớp Chính
{
// Hàm trợ giúp để chèn một nút mới vào đầu danh sách được liên kết
công khai tĩnh Nút đẩy[Node head, int data]
{
Nút nút = mới Node[data];
nút. tiếp theo = đầu;
return node;
}
// Hàm trợ giúp để in danh sách liên kết đã cho
công khai tĩnh vô hiệu printList[Node head]
{
Nút ptr = đầu;
trong khi [ptr . = null]
{
Hệ thống. ra. in[ptr. dữ liệu + " —> "];
ptr = ptr. tiếp theo;
}
Hệ thống. ra. println["null"];
}
// Hàm đệ quy đảo ngược danh sách liên kết.
// Nó đảo ngược danh sách liên kết đã cho bằng cách cố định con trỏ đầu và
// sau đó `. next` con trỏ của mọi nút theo thứ tự ngược lại
công khai tĩnh Nút nghịch[Node head]
{
Nút đầu tiên, nghỉ ngơi;
// trường hợp cơ sở danh sách trống
nếu [đầu == null] {
trả về đầu;
}
đầu = đầu; // suppose first = {1, 2, 3}
nghỉ ngơi = trước. tiếp theo; // phần còn lại = {2, 3}
// trường hợp cơ sở còn lại trống
nếu [nghỉ ngơi == null] {
trả về đầu;
}
nghỉ ngơi = đảo ngược[rest]; // recursively reverse the smaller {2, 3} case
// sau. phần còn lại = {3, 2}
đầu tiên. tiếp theo. tiếp theo = đầu tiên; 5 —> 4 —> 3 —> 2 —> 1 —> null
con trăn
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# Nút danh sách được liên kết
lớp Nút.
def __init__[self, data, next=None]:
bản thân. dữ liệu = dữ liệu
bản thân. tiếp theo = tiếp theo
# Hàm in danh sách liên kết cho trước
def printList[đầu]:
ptr = đầu
while ptr.
in[ptr. dữ liệu, kết thúc=']
ptr = ptr. tiếp theo
in['Không']
# Hàm đệ quy đảo ngược danh sách liên kết
# Nó đảo ngược danh sách liên kết đã cho bằng cách cố định con trỏ đầu và
# sau đó `. con trỏ next` của mọi nút theo thứ tự ngược lại
def nghịch[đầu]:
# trường hợp cơ sở danh sách trống
nếu đầu là Không có:
về đầu
đầu = đầu # suppose first = [1, 2, 3]
nghỉ ngơi = trước. tiếp theo # rest = [2, 3]
# trường hợp cơ sở còn lại trống
nếu nghỉ ngơi là Không:
về đầu
nghỉ ngơi = đảo ngược[rest] # recursively reverse the smaller {2, 3} case
# sau. còn lại = [3, 2]
đầu tiên. tiếp theo. tiếp theo = đầu tiên # đặt
đầu tiên. tiếp theo = Không có # [
đầu = nghỉ ngơi # fix the head pointer
trả về đầu
if __name__ == '__main__'.
đầu = Không
cho i trong đảo ngược[range[6]]:
đầu = Nút[i + 1, head]
đầu = lùi[head]
printList[đầu]
Tải xuống Chạy mã
Đầu ra.
6 —> 5 —> 4 —> 3 —> 2 —> 1 —> Không có
Chúng ta có thể đơn giản hóa đoạn mã trên bằng cách chuyển thông tin nút trước đó cho hàm. Sau đây là cách triển khai đệ quy đơn giản của nó trong C, C++, Java và Python