(一)顺序检索
1.数据个数为10以上,使用同一组数据进行实验。
2.计算程序的时间耗费,对比算法差别。
3.用随机数生产100个数据对两类检索进行实验,在程序中添加起始时间函数及终止时间函数来记录两种算法的时间耗费,对比两类算法差别。
import java.text.SimpleDateFormat;
public class SequentialSearch {
static final int N = 100100;
static int[] a = new int[N];
public static void main(String[] args) {
for (int i = 1; i <= 100000; i++) a[i] = 2 * i;
// 获取当前时间戳
System.out.println("第一种成功");
long st = System.currentTimeMillis();
System.out.println("开始时间:" + formatTimeYMDHMSSSS(st));
search1(199998);
long ed = System.currentTimeMillis();
System.out.println("结束时间:" + formatTimeYMDHMSSSS(ed));
System.out.println();
System.out.println("第二种成功");
st = System.currentTimeMillis();
System.out.println("开始时间:" + formatTimeYMDHMSSSS(st));
search2(199998);
ed = System.currentTimeMillis();
System.out.println("结束时间:" + formatTimeYMDHMSSSS(ed));
System.out.println();
System.out.println("第一种失败");
st = System.currentTimeMillis();
System.out.println("开始时间:" + formatTimeYMDHMSSSS(st));
search1(99999);
ed = System.currentTimeMillis();
System.out.println("结束时间:" + formatTimeYMDHMSSSS(ed));
System.out.println();
System.out.println("第二种失败");
st = System.currentTimeMillis();
System.out.println("开始时间:" + formatTimeYMDHMSSSS(st));
search2(99999);
ed = System.currentTimeMillis();
System.out.println("结束时间:" + formatTimeYMDHMSSSS(ed));
System.out.println();
}
public static void search1(int x) {
int j = 1;
while (j < 100000 && a[j] != x) j++;
if (a[j] == x) System.out.printf("查找成功,查找次数为%d次\n", j);
else System.out.printf("查找失败,查找次数为%d次\n", j);
}
// 初始序列应保持升序排列
public static void search2(int x) {
int j;
for (j = 1; j <= 100000; j++) {
if (a[j] == x) {
System.out.printf("查找成功,查找次数为%d次\n", j);
break;
}
if (a[j] < x && a[j + 1] > x) {
System.out.printf("查找失败,查找次数为%d次\n", j + 1);
break;
}
}
if (j == 100000 && a[j] != x) System.out.printf("查找失败,查找次数为%d次\n", j);
}
// 时间戳转化为日期
public static String formatTimeYMDHMSSSS(long time) {
return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss:SSS").format(time);
}
}
(二)全排列
从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。 当m=n时所有的排列情况叫全排列。 公式:全排列数f(n)=n!(定义0!=1)
此方法使用深度优先遍历
import java.util.Scanner;
public class FullPermutation {
static final int N = 20; //定义全局变量N
static int[] a = new int[N]; //int数组a(用来存储排列后的数组)
static boolean[] st = new boolean[N]; //boolean数组
static int n; //定义数组长度n
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt(); //输入n
dfs(0); //深度优先遍历
}
public static void dfs(int u){
if(u == n){ //如果u和n相等,则从头开始输出
for(int i = 0; i < n; i++)
System.out.printf("%d",a[i]); //注意怎么输出数组
System.out.println(); //换行
return; //退出循环
}
for(int i = 1; i <= n; i++){
if(!st[i]){ //若数组的i位置时false
a[u] = i;//将i填到a[u]中
st[i] = true;//将st改为ture表示里面已经有值了
dfs(u + 1); //递归dfs
st[i] = false;//都输出后再改为false
}
}
}
}
运行结果
(三)二分查找
1. 在一个给定的n个元素的有序序列中查找出与给定关键字x相同的元素的具体位置。即输入一个n个元素的序列,其中n个元素从小到大的顺序排列,查找是否存在给定的值x.(用二分查找法)。
import java.util.Scanner;
public class BinarySearch1 {
static final int N = 1010;
static int[] a = new int[N];
static int n;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
int x = scanner.nextInt();
for (int i = 0; i < n; i++) {
a[i] = scanner.nextInt();
}
int l = 0, r = n - 1;
while (l < r) {
int mid = (l + r) / 2;
if (a[mid] >= x) r = mid;
else l = mid + 1;
}
if (l == r) System.out.println(l);
}
}
2.改写二分搜索算法: 设a[0:n-1]是已排好序的数组,请改写二分搜索算法,使得当搜索元素x不在数组中时,返回小于x的最大元素位置i和大于x的最小元素位置j。当搜索元素在数组中时,i和j相同,均为x在数组中的位置。
import java.util.Scanner;
public class BinarySearch2 {
static final int N = 1010;
static int[] a = new int[N];
static int n;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt(); //输入总数值n
int x = scanner.nextInt(); //输入待检测值x
for(int i = 0; i < n; i++){
a[i] = scanner.nextInt(); //输入数组a
}
int l = 0, r = n - 1;
while(l < r){
int mid = (l + r) / 2;
if(a[mid] >= x)r = mid;
else l = mid + 1;
}
if(a[l] == x)System.out.println(l);
else System.out.printf("%d %d", r-1, r);
}
}
(四)归并排序
归并排序是采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组再合并数组。
以下为消除递归的归并排序:
import java.util.Scanner;
public class mergeSort {
//static final int N = 1010;
//static int[] a = new int[N];
static int n;
public static void main(String[] args) {
//输入
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
int []a=new int[n];//直接新建大小为n的数组
for (int i = 0; i < n; i++) {
a[i] = scanner.nextInt();
}
merge_Sort(a);//例:49 38 65 97
}
//输出
public static void print(int[] a) {
for(int i = 0; i < n; i++)
System.out.printf("%d",a[i]);//输出数组
System.out.println(); //换行
}
//消去递归后的合并排序
public static void merge_Sort(int[] a) {
int[] b = new int[a.length]; //创建一个和a相同长度的数组b
int s = 1; //s表示步长(也表示子数组大小)
while(s < a.length){
mergePass(a, b, s);//合并到数组b
s += s;
mergePass(b, a, s);//合并到数组a
s += s;
}
print(a);
}
//合并排好序的相邻数组段
public static void mergePass(int[] x, int[] y, int s) { //合并函数
int i = 0;
//合并大小为s的相邻2段子数组
while (i <= x.length - 2 * s) {
merge(x, y, i, i + s - 1, i + 2 * s - 1); //i是第一段数组的第一位,i+s-1是最后一位,i+2*s-1是相邻两段子数组最后一位(子数组已排好序)
//例:s=2时 [38 49][65 97] i为38 i+s-1为49 i+2*s-1为97
i = i + 2 * s;//i移动到下一组的第一位,继续循环
}
//剩下的元素个数少于2s
//多于s少于2s
if (i + s >= x.length)
for (int j = i; j < x.length; j++)
y[j] = x[j];//复制到y
else
merge(x, y, i, i + s - 1, x.length - 1);
//小于等于s(只有排序好的一组)
}
//合并c[l:m]和c[m+1:r]到d[l:r]
public static void merge(int[] c, int[] d, int l, int m, int r) {
int i = l, j = m + 1, k = l; //i为第一段数组第一位,j为第二段数组第一位
//i和j都没越界时,第一段最小的i和第二段最小的进行比较
while((i <= m) && (j <= r)) {
if(c[i] <= c[j]) //比较c[i].compareTo(c[j]) <= 0:如果指定的数与参数相等返回 0;如果指定的数小于参数返回 -1;如果指定的数大于参数返回1
d[k++] = c[i++]; //d存比较后的数组(i和j哪个i小存哪个) d[k] = c[i];k++;i++;
else d[k++] = c[j++];
}
//i已经全部遍历完,第一段没有元素了,将第二段剩下的元素写下来
if(i > m)
for(int q = j; q <= r; q++)
d[k++] = c[q];
//j已经全部遍历完,第二段没有元素了,将第一段剩下的元素写下来
else
for(int q = i; q <= m; q++)
d[k++] = c[q];
}
}