深度优先遍历(C语言)

深度优先遍历,起初学习深度优先一般都是用在图上的节点遍历。图的深度优先遍历是最直观的。

详情见:https://blog.csdn.net/zuihongyan518/article/details/80823924

摘抄如下:

深度遍历算法的基本思想:

图的深度遍历算法粗略的可以分为以下三步骤:

   (1)首先选定一个未被访问过的顶点V作为起始顶点(或者访问指定的起始顶点V),并将其标记为已访问过;

   (2)然后搜索与顶点V邻接的所有顶点,判断这些顶点是否被访问过,如果有未被访问过的顶点,则任选一个顶点W进行访问;再选取与顶点W邻接的未被访问过的任一个顶点并进行访问,依次重复进行。当一个顶点的所有的邻接顶点都被访问过时,则依次回退到最近被访问的顶点。若该顶点还有其他邻接顶点未被访问,则从这些未被访问的顶点中取出一个并重复上述过程,直到与起始顶点V相通的所有顶点都被访问过为止。

   (3)若此时图中依然有顶点未被访问,则再选取其中一个顶点作为起始顶点并访问之,转(2)。反之,则遍历结束。

那么问题来了,我们如何判断起始顶点V的邻接顶点是否被访问过呢?

     解决办法:为每个顶点设立一个“访问标志Visited”。首先将图中每个顶点的访问标志设为 “0”或FALSE表示未访问,“1”或true表示已访问,  之后搜索图中每个顶点,如果未被访问,则以该顶点为起始点,进行深度优先遍历,否则继续检查下一顶点。


全排列是非常典型的深度优先搜索题目。

详细题解链接如下,大神讲的非常清楚了:

https://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liweiw/

最厉害的是这张图,讲清了一个全排列如何变成一个深度优先的路径搜索问题。

起点是一个空集【】,遍历所有可能与之链接的节点,并加入path,返回的条件:是所有节点都遍历过,即i>n。如果仅仅一次遍历,则会出现集合【1,2,3】之后就返回了,所以要回溯 visited[i]=0; ,这样在依次回退到原先访问过的节点后,还可以再考虑其他节点。


对二叉树而言: 

对于二叉树而言,深度优先就是依次选择遍历路径root->left  和 root->right,如果此路不通 if(root==NULL) return NULL,就返回去找一条能继续走的路径。二叉树的前序遍历,后序,中序,都是选一个点作为访问起点,进行深度遍历吧。

366. 寻找二叉树的叶子节点

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题目 :

46. 全排列 

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;
    
}

 

60. 第k个排列

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;
        }
    }
}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值