1 白名单过滤
问题描述:
想象有一家信用卡公司,需要检查用户的交易账号是否有效,为此,他需要:
将白名单排序后,二分查找
画图与控制台的实现如下(没用之前准备工作的DrawArray,以为那个封装的还不是很好),输入为官网提供的两个文件,eclipse配置如下:data\tinyW.txt data\tinyT.txt
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图形结果
防止溢出
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 删除重复元素
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