g函数返回后,f函数对应的栈中的数据没有任何变化,这就是回溯算法的核心。
可以这样思考,先逆序打印从第二个节点开始的子表,最后再将第一个节点打印出来。
1 #include <iostream> 2 #include <cstring> 3 #include "DTString.h" 4 5 using namespace std; 6 using namespace DTLib; 7 8 struct Node 9 { 10 int value; 11 Node* next; 12 }; 13 14 Node* create_list(int v, int len) // v:数据元素从哪一个之开始。 len:长度 15 { 16 Node* ret = NULL; 17 Node* slider = NULL; 18 19 for(int i=0; i<len; i++) 20 { 21 Node* n = new Node(); 22 23 n->value = v++; 24 n->next = NULL; 25 26 if( slider == NULL ) 27 { 28 slider = n; 29 ret = n; 30 } 31 else 32 { 33 slider->next = n; 34 slider = n; 35 } 36 } 37 38 return ret; 39 } 40 41 void destroy_list(Node* list) 42 { 43 while( list ) 44 { 45 Node* del = list; 46 47 list = list->next; 48 49 delete del; 50 } 51 } 52 53 void print_list(Node* list) 54 { 55 while( list ) 56 { 57 cout << list->value << "->"; 58 59 list = list->next; 60 } 61 62 cout << "NULL" << endl; 63 } 64 65 66 67 void r_print_even(Node* list) 68 { 69 if( list != NULL) 70 { 71 r_print_even(list->next); 72 73 if( (list->value % 2) == 0 ) 74 { 75 cout << list->value << endl; 76 } 77 } 78 } 79 80 int main() 81 { 82 Node* list = create_list(2, 5); 83 84 print_list(list); 85 86 r_print_even(list); 87 88 destroy_list(list); 89 90 return 0; 91 }
逆序打印栈的增长与退栈示意图:
退栈打印的过程就是回溯的过程。
递归调用的时候只是先将参数保存在栈上,这时这个参数还没有用到,只是让指针指向了相应的节点,退栈的时候才用到。
类似于走迷宫,走到一个路口时先做个标记,这个标记暂时不用,回来的时候再用。根据标记找来时的路。
回溯的本质就是做标记,这样方便回退。
八皇后:
放皇后的时候只需要关注箭头的方向,因为其他的方向还没有放任何东西。
当我们发现某一行的任何一个位置都不能放皇后的时候,就开始要回溯了。因为,这证明了上一行放置皇后的地方是错误的。
当我们发现第i行的任何一个位置都不能放置皇后了,这就证明了第i-1行放置的位置是错误的。
如果发现第i-1行也没有地方可以放置皇后了,这意味着还要继续回退,退到i-2行,这就是回溯。
理论上,每放置一个皇后要判断8个方向,但是我们从第一行开始放置皇后,有规律的放,因此,只需要考虑三个方向。
如果判断一个位置的左下角对角线是否已经放置了皇后,那就在这个位置的基础上,在xy坐标上不断的减一。因此,方向数据很重要。左下角方向数据是(-1,-1)。
原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9678384.html
时间: 2024-10-01 12:56:42