回溯法
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。 若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。 而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。
例题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.