算法4——BinarySearch系列

1 白名单过滤

问题描述:

    想象有一家信用卡公司,需要检查用户的交易账号是否有效,为此,他需要:

  1. 将客户的账号保存到一个文件中,我们称它为白名单;
  2. 从标准输入中得到每笔交易的账号;
  3. 使用这个测试用例在标准输出中打印所欲与任何账户无关的账号,公司可能拒绝侧类交易。

将白名单排序后,二分查找

画图与控制台的实现如下(没用之前准备工作的DrawArray,以为那个封装的还不是很好),输入为官网提供的两个文件,eclipse配置如下:data\tinyW.txt data\tinyT.txt

算法4——BinarySearch系列_第1张图片

package com.duoduo.algs4.Fundamentals;

import java.awt.Color;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;

import com.duoduo.algs4.util.RedirectStream;
import com.duoduo.std.DrawArray;

import edu.princeton.cs.introcs.Draw;
import edu.princeton.cs.introcs.In;
import edu.princeton.cs.introcs.StdIn;
import edu.princeton.cs.introcs.StdOut;

public class BinarySearch {

	// precondition: array a[] is sorted
	public static int rank(int key, int[] a) {
		int lo = 0;
		int hi = a.length - 1;
		while (lo <= hi) {
			// Key is in a[lo..hi] or not present.
			int mid = lo + (hi - lo) / 2;
			if (key < a[mid])
				hi = mid - 1;
			else if (key > a[mid])
				lo = mid + 1;
			else
				return mid;
		}
		return -1;
	}

	public static double X_DOWN = 0.5;
	public static double Y_DOWN = 200;

	public static Draw DrawArray(int[] a, int loc, Draw draw) {
		return DrawArray(a, X_DOWN, Y_DOWN, loc, draw);
	}

	public static Draw DrawArray(int[] a, double X_DOWN, double Y_DOWN,
			int loc, Draw draw) {
		int N = a.length;

		double x = 1.0 * loc / N;
		double y = a[loc] / Y_DOWN;
		double rw = X_DOWN / N;
		double rh = a[loc] / Y_DOWN;
		draw.setPenColor(Color.RED);
		draw.filledRectangle(x, y, rw, rh);
		draw.setPenColor();
		return draw;
	}

	public static void testConsole(String whiteListName,String guestListName) throws IOException {
		StdOut.println("console");
		int[] whiteList = In.readInts(whiteListName);
		FileInputStream fis = RedirectStream.redirectFileToStdin(guestListName);
		Arrays.sort(whiteList);
		while (!StdIn.isEmpty()){
			int key = StdIn.readInt();
			if(rank(key, whiteList) == -1)
				StdOut.println(key);
			
		}
		if(fis!=null){
			fis.close();
		}
		
	}
	public static void testDraw(String whiteListName,String guestListName) {
		StdOut.println("testDraw");
		int[] whitelist = In.readInts(whiteListName);
		int[] guestlist = In.readInts(guestListName);

		Arrays.sort(whitelist);
		Draw draw1 = DrawArray.DrawArray(whitelist, X_DOWN, Y_DOWN,"白名单");
		Draw draw2 = DrawArray.DrawArray(guestlist, X_DOWN, Y_DOWN,"黑名单");
		int local;
		int key;
		int N = guestlist.length;
		for (int i = 0; i < N; i++) {
			key = guestlist[i];
			local = rank(key, whitelist);
			// 白名单中匹配了多少条,以及黑名单有多少条没被匹配。
			if (local == -1) {
				StdOut.println(key);
				//guest中下标为i的元素不在白名单中
				DrawArray(guestlist, i, draw2);
			} else {
				DrawArray(whitelist, local, draw1);

			}
		}
	}
	public static void main(String[] args) throws IOException {
		testDraw(args[0],args[1]);
		testConsole(args[0],args[1]);

		

	}
}
运行结果:

控制台输出:

testDraw
50
99
13
console
50
99
13
图形结果

算法4——BinarySearch系列_第2张图片

防止溢出

int mid = lo + (hi - lo) / 2;

2 将rank改为递归(1),打印递归深度,以及lo和hi

    打印深度是加了一个deeps保存深度值:

package com.duoduo.algs4.Fundamentals;

import java.awt.Color;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;

import com.duoduo.algs4.util.RedirectStream;
import com.duoduo.std.DrawArray;

import edu.princeton.cs.introcs.Draw;
import edu.princeton.cs.introcs.In;
import edu.princeton.cs.introcs.StdIn;
import edu.princeton.cs.introcs.StdOut;

public class BinarySearchRecursion {

	public static int rank(int key, int[] a) {
		//打印深度
		return rank(key, a, 0, a.length - 1, 0);
		//不打印深度
		// return rank(key, a, 0, a.length - 1);

	}

	public static int rank(int key, int[] a, int lo, int hi) {
		if (lo > hi) {
			return -1;
		}
		int mid = lo + (hi - lo) / 2;
		if (key == a[mid]) {
			return mid;
		} else if (key < a[mid]) {
			hi = mid - 1;
		} else {
			lo = mid + 1;
		}
		return rank(key, a, lo, hi);
	}

	// 打印递归深度 P35 1.1.22
	public static int rank(int key, int[] a, int lo, int hi, int deeps) {
		StdOut.println("此次递归的深度为:" + deeps + " lo:" + lo + " hi:" + hi);
		if (lo > hi) {
			return -1;
		}
		int mid = lo + (hi - lo) / 2;
		if (key == a[mid]) {
			return mid;
		} else if (key < a[mid]) {
			hi = mid - 1;
		} else {
			lo = mid + 1;
		}
		return rank(key, a, lo, hi, deeps + 1);
	}

	public static void testConsole(String whiteListName, String guestListName)
			throws IOException {
		int[] whiteList = In.readInts(whiteListName);
		FileInputStream fis = RedirectStream.redirectFileToStdin(guestListName);
		Arrays.sort(whiteList);
		while (!StdIn.isEmpty()) {
			int key = StdIn.readInt();
			if (rank(key, whiteList) == -1)
				StdOut.println(key);

		}
		if (fis != null) {
			fis.close();
		}

	}

	public static void main(String[] args) throws IOException {

		testConsole(args[0], args[1]);

	}
}

运行结果

此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:0 hi:6
此次递归的深度为:2 lo:4 hi:6
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:8 hi:10
此次递归的深度为:3 lo:10 hi:10
此次递归的深度为:4 lo:10 hi:9
50
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:0 hi:6
此次递归的深度为:2 lo:0 hi:2
此次递归的深度为:3 lo:0 hi:0
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:3 lo:14 hi:15
此次递归的深度为:4 lo:15 hi:15
此次递归的深度为:5 lo:16 hi:15
99
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:0 hi:6
此次递归的深度为:2 lo:4 hi:6
此次递归的深度为:3 lo:4 hi:4
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:0 hi:6
此次递归的深度为:2 lo:4 hi:6
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:3 lo:14 hi:15
此次递归的深度为:4 lo:15 hi:15
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:3 lo:14 hi:15
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:0 hi:6
此次递归的深度为:2 lo:0 hi:2
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:0 hi:6
此次递归的深度为:2 lo:0 hi:2
此次递归的深度为:3 lo:0 hi:0
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:8 hi:10
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:0 hi:6
此次递归的深度为:2 lo:0 hi:2
此次递归的深度为:3 lo:2 hi:2
此次递归的深度为:4 lo:3 hi:2
13
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:8 hi:10
此次递归的深度为:3 lo:10 hi:10
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:3 lo:14 hi:15
此次递归的深度为:4 lo:15 hi:15
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:3 lo:12 hi:12

3 删除重复元素

  •  步骤1:排序
  •  步骤2:二分搜索[i+1,...n]
  •  步骤3:如果不存在,加入新数组,如果存在,go next
    (做这玩意儿的时候就感觉python的数组可以切片真是幸福啊)
package com.duoduo.algs4.Fundamentals;

import java.io.IOException;
import java.util.Arrays;

import com.duoduo.algs4.util.ArrayUtil;

import edu.princeton.cs.introcs.In;
import edu.princeton.cs.introcs.StdOut;

public class RemoveDuplicateElement {
	// 删除重复元素

	// 步骤1:排序
	// 步骤2:二分搜索[i+1,...n]
	// 步骤3:如果不存在,加入新数组,如果存在,go next
	public static int[] removeDuplicateElement(int[] a) {
		int M = a.length;
		if (M <= 0) {
			return null;
		}
		int[] b = new int[M];
		int index = 0;

		int hi = M - 1;
		int lo, key;
		for (int i = 0; i < M; i++) {
			lo = i + 1;
			key = a[i];
			if (-1 == BinarySearch.rank(key, a, lo, hi)) {
				b[index++] = key;
			}

		}
		// 剔除掉0
		int[] result = b;
		if (index < M) {
			result = new int[index];
			for (int i = 0; i < index; i++) {
				result[i] = b[i];
			}
			b = null;
		}
		return result;

	}

	public static void testConsole(String whiteListName) {
		StdOut.println("console");
		int[] whiteList = In.readInts(whiteListName);

		Arrays.sort(whiteList);
		int[] afterRemove = removeDuplicateElement(whiteList);
		ArrayUtil.printArray(whiteList);
		ArrayUtil.printArray(afterRemove);
	}

	public static void main(String[] args) {
		testConsole(args[0]);
	}

}
运行结果
console
数组为:
10 10 11 13 18 23 23 48 50 54 68 77 77 77 84 98 98 99 
数组为:
10 11 13 18 23 48 50 54 68 77 84 98 99 

使用data\largeT.txt (6.67M),不知道是不因因为数组太大还是怎么回事儿,输出一闪而过

测试方法

public static void testConsole(String whiteListName) {
		StdOut.println("console");
		int[] whiteList = In.readInts(whiteListName);

		Arrays.sort(whiteList);
		int[] afterRemove = removeDuplicateElement(whiteList);
		StdOut.println("print");
		StdOut.println(whiteList.length);
		StdOut.println(afterRemove.length);
		
		ArrayUtil.printArray(whiteList);
		ArrayUtil.printArray(afterRemove);
	}
public static void printArray(int[] a){
		int M = a.length;
		StdOut.println("数组为:");
		for (int i = 0; i < M; i++) {
			StdOut.print(a[i] + " ");
		}
		StdOut.println();
	}

注释掉ArrayUtil.printArray后输出
console
print
1000000
631959


你可能感兴趣的:(java,算法,二分查找)