深度优先遍历,起初学习深度优先一般都是用在图上的节点遍历。图的深度优先遍历是最直观的。
详情见:https://blog.csdn.net/zuihongyan518/article/details/80823924
摘抄如下:
深度遍历算法的基本思想:
图的深度遍历算法粗略的可以分为以下三步骤:
(1)首先选定一个未被访问过的顶点V作为起始顶点(或者访问指定的起始顶点V),并将其标记为已访问过;
(2)然后搜索与顶点V邻接的所有顶点,判断这些顶点是否被访问过,如果有未被访问过的顶点,则任选一个顶点W进行访问;再选取与顶点W邻接的未被访问过的任一个顶点并进行访问,依次重复进行。当一个顶点的所有的邻接顶点都被访问过时,则依次回退到最近被访问的顶点。若该顶点还有其他邻接顶点未被访问,则从这些未被访问的顶点中取出一个并重复上述过程,直到与起始顶点V相通的所有顶点都被访问过为止。
(3)若此时图中依然有顶点未被访问,则再选取其中一个顶点作为起始顶点并访问之,转(2)。反之,则遍历结束。
那么问题来了,我们如何判断起始顶点V的邻接顶点是否被访问过呢?
解决办法:为每个顶点设立一个“访问标志Visited”。首先将图中每个顶点的访问标志设为 “0”或FALSE表示未访问,“1”或true表示已访问, 之后搜索图中每个顶点,如果未被访问,则以该顶点为起始点,进行深度优先遍历,否则继续检查下一顶点。
全排列是非常典型的深度优先搜索题目。
详细题解链接如下,大神讲的非常清楚了:
最厉害的是这张图,讲清了一个全排列如何变成一个深度优先的路径搜索问题。
起点是一个空集【】,遍历所有可能与之链接的节点,并加入path,返回的条件:是所有节点都遍历过,即i>n。如果仅仅一次遍历,则会出现集合【1,2,3】之后就返回了,所以要回溯 visited[i]=0; ,这样在依次回退到原先访问过的节点后,还可以再考虑其他节点。
对二叉树而言:
对于二叉树而言,深度优先就是依次选择遍历路径root->left 和 root->right,如果此路不通 if(root==NULL) return NULL,就返回去找一条能继续走的路径。二叉树的前序遍历,后序,中序,都是选一个点作为访问起点,进行深度遍历吧。
1.如何删除节点
链表和树结构等这种由指针构成的数据结构,将一个节点赋值为空,删除一个节点,需要找它的父节点,让父节点指向空。直接root=NULL没有用。
if (pre != NULL && pre->left == root) pre->left = NULL;
if (pre != NULL && pre->right == root) pre->right = NULL;
// root=NULL;//wrong
2. 返回结果的位置应该在哪里?
将结果返回给ret的赋值操作的位置。开始放在dfs里面,出错如下:
输入:
[1,2,3,4,5]
输出:
[[4,5],[3]]
预期:
[[4,5,3],[2],[1]]
[4,5,3]因为不在一颗子树上,被截断。
dfs(root->left,returnSize,returnColumnSizes,ret,index,path);
dfs(root->right,returnSize,returnColumnSizes,ret,index,path);
ret[*returnSize]=malloc(sizeof(int)*(index)); //wrong
memcpy(ret[*returnSize],path,sizeof(int)*(index));
(*returnColumnSizes)[*returnSize]=index;
(*returnSize)++;
index=0;
3.一遍查找之后退出了,需要再查找
while(root->left||root->right){
}
void dfs(struct TreeNode* root,int *index,int *path,struct TreeNode* pre ){
if(root==NULL)return;
//printf("%d\n",root->val);
if(root->left==NULL&&root->right==NULL){
path[*index]=root->val;
(*index)++;
if (pre != NULL && pre->left == root) pre->left = NULL;
if (pre != NULL && pre->right == root) pre->right = NULL;
// root=NULL;
return;
}
pre=root;
dfs(root->left,index,path,pre);
dfs(root->right,index,path,pre);
}
int** findLeaves(struct TreeNode* root, int* returnSize, int** returnColumnSizes){
int **ret=malloc(sizeof (int*)*100000);
int index=0;
*returnSize=0;
if(root==NULL)return NULL;
*returnColumnSizes=malloc(sizeof(int)*100000);
int *path=malloc(sizeof(int)*100000);
struct TreeNode* pre;
while(root->left||root->right){
dfs(root,&index,path,pre);
ret[*returnSize]=malloc(sizeof(int)*(index));
memcpy(ret[*returnSize],path,sizeof(int)*(index));
(*returnColumnSizes)[*returnSize]=index;
(*returnSize)++;
index=0;
}
ret[*returnSize]=malloc(sizeof(int));
ret[*returnSize][0]=root->val;
(*returnColumnSizes)[*returnSize]=1;
(*returnSize)++;
return ret;
}
全排列LeetCode题目 :
void dfs(int *arr, int len, int *path,int index, int **ret, int *ret_index,int *visited){
if(index==len){
ret[*ret_index]= malloc(sizeof(int)*len);
memcpy(ret[*ret_index],path,sizeof(int)*len);
(*ret_index)++;
return;
}
for(int i=0;i<len;i++){
if(visited[i]==0){
visited[i]=1;
path[index]=arr[i];
dfs(arr,len,path,index+1,ret,ret_index,visited);
visited[i]=0;//回溯主要体现在这一步
}
}
}
#define LEN 0xfff
int** permute(int* arr, int len, int* returnSize, int** returnColumnSizes){
int **ret = (int **)malloc(sizeof(int*)*LEN);
int *path = (int *)malloc(sizeof(int) * len);
int index = 0;
int i;
int ret_index=0;
int *visited= (int *)malloc(sizeof(int)*len);
memset(visited,0,sizeof(int) * len);
dfs(arr,len,path,index,ret,&ret_index,visited);
*returnColumnSizes = malloc(sizeof(int)*ret_index);
for(i=0; i<ret_index; i++){
(*returnColumnSizes )[i] = len;
}
// printf("ret_index:%d\n", ret_index);
*returnSize = ret_index;
return ret;
}
void dfs(int n, char *path,int index, char*ret, int *ret_index,int *visited,int k)
函数中, int *ret_index为什么要用 *ret_index,而不是 int ret_index。因为, int ret_index是局部变量,会随着函数退栈而发生变化,但是实际上,我们希望这个ret_index是一直累加的,所以需要一个外部变量,不随着函数退栈进栈发生改变。
char * getPermutation(int n, int k){
char *ret=(char*)malloc(sizeof(char)* (n+1));
char *path = (char*)malloc(sizeof(char)* n);
int index = 0;
int i;
int ret_index=0;
int *visited= (int *)malloc(sizeof(int)*(n+1));
memset(visited,0,sizeof(int)*(n+1));
dfs(n,path,index,ret,&ret_index,visited,k);
return ret;
}
void dfs(int n, char *path,int index, char*ret, int *ret_index,int *visited,int k){
if(*ret_index>k-1)return;
if(index==n){
if((*ret_index)==k-1){
memcpy(ret, path,n);
ret[n]='\0';
}
(*ret_index)++;
return;
}
for(int i=1;i<=n;i++){
if(visited[i]==0){
visited[i]=1;
path[index]=i+'0';
dfs(n,path,index+1,ret,ret_index,visited,k);
visited[i]=0;
}
}
}