Java搜索算法

回溯法

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。 若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。 而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。

例题1 全排列
在这里插入图片描述
思路一在这里插入图片描述
思路二

在这里插入图片描述
代码:

class Solution {
    public void backtrack(int n, ArrayList<Integer> nums,List<List<Integer>> output,int first) {
        if (first == n)
            output.add(new ArrayList<Integer>(nums));

        for (int i = first; i < n; i++) {
            Collections.swap(nums, first, i);      // place i-th integer first 
            // in the current permutation  
            backtrack(n, nums, output, first + 1);   // use next integers to complete the permutations
            Collections.swap(nums, first, i);          // backtrack
        }
    }

    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> output = new LinkedList();
        ArrayList<Integer> nums_lst = new ArrayList<Integer>();
        for (int num : nums)
            nums_lst.add(num);

        int n = nums.length;
        backtrack(n, nums_lst, output, 0);
        return output;
    }
}

回溯法通过递归对一条分支进行遍历,达到叶子结点时候,需要返回其父母结点的状态,然后再遍历剩下的叶子结点,回溯法类似于深度优先搜索算法(DFS)。

例题2 组合
在这里插入图片描述
实现:
在这里插入图片描述
代码:

class Solution {

    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>>comset=new LinkedList();
        if(n<k)
            return comset;
        helper(n,k,comset,new LinkedList<Integer>(),1);
        return comset;

    }
    public void helper(int n1,int k1,List<List<Integer>>comset,LinkedList<Integer>com,int first)
    {
        if(com.size()==k1)
            comset.add(new LinkedList<Integer>(com));
        else{
            for(int i=first;i<=n1;i++){
                com.add(i);
                helper(n1,k1,comset,com,i+1);
                com.removeLast();
            }
        }
    }
}

递归和回溯的区别:
递归是一直向下递归到最后,然后从下往上逐步返回。
回溯是当递归到叶子结点的时候可以返回重新递归其他的结点。

树的深度优先遍历(DFS)和广度优先遍历(BFS)

在这里插入图片描述
在这里插入图片描述

 // 二叉树数据结构
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class TreeNode {
    int data;
    TreeNode leftNode;
    TreeNode rightNode;
    public TreeNode() {
    }
    public TreeNode(int d) {
        data=d;
    }
    public TreeNode(TreeNode left,TreeNode right,int d) {
        leftNode=left;
        rightNode=right;
        data=d;
    }
}

public class DeepFirstSort {
    public static void main(String[] args) {
        TreeNode head=new TreeNode(1);
        TreeNode second=new TreeNode(2);
        TreeNode three=new TreeNode(3);
        TreeNode four=new TreeNode(4);
        TreeNode five=new TreeNode(5);
        TreeNode six=new TreeNode(6);
        TreeNode seven=new TreeNode(7);
        head.rightNode=three;
        head.leftNode=second;
        second.rightNode=five;
        second.leftNode=four;
        three.rightNode=seven;
        three.leftNode=six;
        System.out.print("广度优先遍历结果:");
        new DeepFirstSort().BroadFirstSearch(head);
        System.out.println();
        System.out.print("深度优先遍历结果:");
        new DeepFirstSort().depthFirstSearch(head);
    }
    //广度优先遍历

    public void BroadFirstSearch(TreeNode nodeHead) {
        if(nodeHead==null) {
            return;
        }
        Queue<TreeNode> myQueue=new LinkedList<>();
        myQueue.add(nodeHead);
        while(!myQueue.isEmpty()) {
            TreeNode node=myQueue.poll();
            System.out.print(node.data+" ");
            if(null!=node.leftNode) {
                myQueue.add(node.leftNode);    //深度优先遍历,我们在这里采用每一行从左到右遍历
            }
            if(null!=node.rightNode) {
                myQueue.add(node.rightNode);
            }
        }
    }
    
    //深度优先遍历

    public void depthFirstSearch(TreeNode nodeHead) {
        if(nodeHead==null) {
            return;
        }
        Stack<TreeNode> myStack=new Stack<>();
        myStack.add(nodeHead);
        while(!myStack.isEmpty()) {
            TreeNode node=myStack.pop();    //弹出栈顶元素
            System.out.print(node.data+" ");
            if(node.rightNode!=null) {
                myStack.push(node.rightNode);    //深度优先遍历,先遍历左边,后遍历右边,栈先进后出
            }
            if(node.leftNode!=null) {
                myStack.push(node.leftNode);
            }
        }
    }
}

图的深度优先遍历(DFS)和广度优先遍历(BFS)

图的深度优先遍历类似于二叉树中的先序遍历
图的广度优先遍历类似于二叉树中的层次遍历

public class Graph {
    private final int MAX_VERTS = 20;
    private Vertex vertexList[];// 顶点数组
    private int adjMat[][];// 邻接矩阵
    private int nVerts;// 当前顶点总数
    private StackX theStack;
    private Queue theQueue;

    public static void main(String[] args) {
        Graph theGraph = new Graph();
        theGraph.addVertex('A');
        theGraph.addVertex('B');
        theGraph.addVertex('C');
        theGraph.addVertex('D');
        theGraph.addVertex('E');

        theGraph.addEdge(0, 1);
        theGraph.addEdge(1, 2);
        theGraph.addEdge(0, 3);
        theGraph.addEdge(3, 4);
        System.out.print("visits:");
        // theGraph.dfs();
        theGraph.bfs();
        System.out.println();
    }

    public Graph() {// 构造图
        vertexList = new Vertex[MAX_VERTS];
        adjMat = new int[MAX_VERTS][MAX_VERTS];
        nVerts = 0;
        for (int i = 0; i < MAX_VERTS; i++) {
            for (int j = 0; j < MAX_VERTS; j++) {
                adjMat[i][j] = 0;
            }
        }
        theStack = new StackX();
        theQueue = new Queue();
    }
    
    public void addVertex(char lab) {// 添加顶点
        vertexList[nVerts++] = new Vertex(lab);
    }

    public void addEdge(int start, int end) {// 添加边
        adjMat[start][end] = 1;
        adjMat[end][start] = 1;
    }

    public void displayVertex(int v) {// 打印数组中v位置下的顶点名
        System.out.print(vertexList[v].lable);
    }

    public int getAdjUnvisitedVertex(int v) {// 获取和v邻接的未访问的顶点
        for (int i = 0; i < nVerts; i++) {
            if (adjMat[v][i] == 1 && vertexList[i].wasVisited == false) {
                return i;
            }
        }
        return -1;
    }

    public void dfs() {// 深度优先搜索
        vertexList[0].wasVisited = true;
        displayVertex(0);
        theStack.push(0);
        
        while (!theStack.isEmpty()) {
            int v = getAdjUnvisitedVertex(theStack.peek());
            if (v == -1) {
                theStack.pop();
            } else {
                vertexList[v].wasVisited = true;
                displayVertex(v);
                theStack.push(v);
            }
        }
        
        for (int i = 0; i < nVerts; i++) {
            vertexList[i].wasVisited = false;// 重置,防止后边再次使用dfs
        }
    }


    public void bfs() {// 广度优先搜索
        vertexList[0].wasVisited = true;
        displayVertex(0);
        theQueue.insert(0);
        int v2;
        
        while (!theQueue.isEmpty()) {
            int v1 = theQueue.remove();
            while ((v2 = getAdjUnvisitedVertex(v1)) != -1) {
                vertexList[v2].wasVisited = true;
                displayVertex(v2);
                theQueue.insert(v2);
            }
        }
        
        for (int j = 0; j < nVerts; j++) {
            vertexList[j].wasVisited = false;
        }
    }
}



class StackX {// 自定义栈
    private final int SIZE = 20;
    private int[] st;
    private int top;
    
    public StackX() {
        st = new int[SIZE];
        top = -1;
    }
    
    public void push(int j) {
        st[++top] = j;
    }
    
    public int pop() {
        if (top == 0) {
            return -1;
        }
        return st[--top];
    }
    
    public int peek() {
        return st[top];
    }
    
    public boolean isEmpty() {
        return (top == -1);
    }
}

class Queue {
    private final int SIZE = 20;
    private int[] queArray;
    private int front;
    private int rear;

    public Queue() {
        queArray = new int[SIZE];
        front = 0;
        rear = -1;
    }
    
    public void insert(int j) {// 入队
        if (rear == SIZE - 1) {
            rear = -1;
        }
        queArray[++rear] = j;
    }
    
    public int remove() {// 出队
        if (!isEmpty()) {
            return queArray[front++];
        } else {
            return -1;
        }

    }

    public boolean isEmpty() {
        return (rear + 1 == front);
    }
}

class Vertex {
    public char lable;// 名字
    public boolean wasVisited;
    
    public Vertex(char lab) {
        lable = lab;
        wasVisited = false;
    }
}

二叉搜索树

链接: https://blog.csdn.net/u011676300/article/details/80715249.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值