因为这学期上算法课,因为要准备蓝桥杯国赛,所以复习记录一下几个经典的算法 (T_T)。。。
1.子集遍历
子集遍历的算法思想:
使用深度优先搜索,用堆栈记录路径。
子集树:
1.访问根节点。
2.若当前访问为非叶节点:
(a)将0压栈;
(b)递归访问左子树;
(c)将0弹出,将1压栈;
(d)递归访问右子树;
(e)将1弹出。
3.若当前访问为叶节点,就根据栈中的内容打印。
import java.util.ArrayList;
import java.util.Scanner;
/**
* @author: cuttle
* @Date: 2020/9/16 16:32
* @Description: 子集遍历算法
*/
public class SubsetsEnumeration {
static ArrayList<Object> arr = new ArrayList<>();//作为栈
static Object[] obj;
public static void main(String[]args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入集合的元素数目n为:");
int n = sc.nextInt();
System.out.println("请输入" + n + "个集合元素:");
obj = new Object[n];
for(int i = 0;i < n;i++){
obj[i] = sc.next();
}
long begin = System.currentTimeMillis();
subsetting(n);
long end = System.currentTimeMillis();
System.out.println("集合元素数目n为" + n +"时,花费的时间为:" + (end - begin) + "ms");
}
public static void subsetting(int n){
if(n > 0){
arr.add(0);//将0压栈
subsetting(n -1);//递归访问左子树
arr.set(arr.size() - 1,1);//将0弹出,将1压栈
subsetting(n -1 );//递归访问右子树
arr.remove(arr.size() -1 );//将1弹出
}else{
System.out.print("{ ");
for (int i = 0;i < arr.size();i++) {
if(arr.get(i).equals(1)){
System.out.print(obj[i] + " ");
}
}
System.out.print("}");
System.out.println();
}
}
}
时间复杂度:T(n) = n × 2 n
2.全排列
全排列的算法思想:
使用深度优先搜索排列树。
排列树:
import java.util.Scanner;
/**
* @author: cuttle
* @Date: 2020/9/16 20:12
* @Description: 全排列遍历
*/
public class PermutationsEnumeration {
static Object[] obj;
public static void main(String[]args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入全排列的规模n:");
int n = sc.nextInt();
obj = new Object[n];
System.out.println("请顺序输入结点号列表:");
for(int i = 0;i < n;i++){
obj[i] = sc.next();
}
long begin = System.currentTimeMillis();
permuting(0);
long end = System.currentTimeMillis();
System.out.println("全排列的规模n为" + n + "时,花费的时间为" + (end - begin) + "ms" );
}
public static void permuting(int i){
if(i < obj.length - 1){
for(int j = i;j < obj.length;j++){
swap(obj,i,j);
permuting(i + 1);
swap(obj,i,j);
}
}else{
for (Object o:obj) {
System.out.print(o+" ");
}
System.out.println();
}
}
public static void swap(Object[] x,int i,int j){
Object temp = x[i];
x[i] = x[j];
x[j] = temp;
}
}
时间复杂度:T(n) = n × n!
3.图的广度优先搜索
图的广度搜索BFS的算法思想:
1.置所有顶点为未访问;
2.从第一个顶点开始循环访问未访问的顶点:
(a)将当前顶点v置为访问;
(b)将v推入队列Q;
(c)若队列Q不为空:
弹出队首顶点u;访问u的所有邻居顶点;若某邻居结点w未被访问过,则将其置为未访问并推入Q;
import java.util.ArrayList;
import java.util.Scanner;
/**
* @author: cuttle
* @Date: 2020/9/24 19:03
* @Description: 图的广度优先搜索算法
*/
public class BFS {
static ArrayList<Object> queue = new ArrayList<>();//作为队列
static int n;//记录图的顶点个数
static int[][] matrix;//存储图的邻接矩阵
static Object[] nodeName;//存储图的顶点名称
static boolean[] visited;//记录顶点是否访问
static int start;//起始顶点序号
public static void main(String[]args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入图的顶点个数:");
n = sc.nextInt();
matrix = new int[n][n];
nodeName = new Object[n];
visited = new boolean[n];
System.out.println("请输入" + n + "个顶点的名称:");
for(int i = 0;i < n;i++){
nodeName[i] = sc.next();
visited[i] = false;
}
System.out.println("请输入图的邻接矩阵:");
for(int i = 0;i < n;i++){
for(int j = 0;j < n;j++){
matrix[i][j] = sc.nextInt();
}
}
System.out.println("请输入起始顶点[1,"+ n +"]:");
start = sc.nextInt();
graphBFS(start);
}
public static void graphBFS(int start){
visited[start -1] = true;
queue.add(start -1);
System.out.print(nodeName[start - 1] + " ");
while(queue.size() != 0){
int j = (Integer) queue.get(0);
queue.remove(0);
for(int i = 0;i < matrix.length;i++){
if(matrix[j][i] == 1 && visited[i] == false){
visited[i] = true;
queue.add(i);
System.out.print(nodeName[i] + " ");
}
}
}
//检查是否还存在未被访问过的
for(int i = 0;i < visited.length;i++){
if(visited[i] == false){
graphBFS(i + 1);
}
}
}
}
4.图的深度优先搜索
图的深度搜索DFS的算法思想:
1.置所有顶点为未访问;选取一个顶点v作为起始顶点;
2.访问顶点v,将顶点v置为访问;
3.选择v的一个邻居顶点u:
(a)若u访问过,则转3;
(b)若u未访问过,则将u作为新的v对第2步进行递归;
import java.util.Scanner;
/**
* @author: cuttle
* @Date: 2020/9/24 20:16
* @Description: 图的深度优先搜索算法
*/
public class DFS {
static int n;//记录图的顶点个数
static int[][] matrix;//存储图的邻接矩阵
static Object[] nodeName;//存储图的顶点名称
static boolean[] visited;//记录顶点是否访问
static int start;//起始顶点序号
public static void main(String[]args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入图的顶点个数:");
n = sc.nextInt();
matrix = new int[n][n];
nodeName = new Object[n];
visited = new boolean[n];
System.out.println("请输入" + n + "个顶点的名称:");
for(int i = 0;i < n;i++){
nodeName[i] = sc.next();
visited[i] = false;
}
System.out.println("请输入图的邻接矩阵:");
for(int i = 0;i < n;i++){
for(int j = 0;j < n;j++){
matrix[i][j] = sc.nextInt();
}
}
System.out.println("请输入起始顶点[1,"+ n +"]:");
start = sc.nextInt();
graphDFS(start - 1);
//检查是否还存在未被访问过的,因为有递归,不能放在graphDFS里面
for(int i = 0;i < visited.length;i++){
if(visited[i] == false){
graphDFS(i);
}
}
}
public static void graphDFS(int start){
visited[start] = true;
System.out.print(nodeName[start] + " ");
for(int i = 0;i < matrix.length;i++){
if(matrix[start][i] == 1 && visited[i] == false){
visited[i] = true;
graphDFS(i);
}
}
}
}