《算法》第一章部分程序 part 1

▶ 书中第一章部分程序,加上自己补充的代码,包括若干种二分搜索,寻找图上连通分量数的两种算法

● 代码,二分搜索

 1 package package01;
 2 
 3 import java.util.Arrays;
 4 import edu.princeton.cs.algs4.StdRandom;
 5 
 6 public class class01
 7 {
 8     public int binarySearch(int [] a, int target)   // 非递归实现
 9     {
10         int lp = 0, rp = a.length - 1;
11         for(;lp <= rp;)                             // 含等号的条件,后面修改 lp 和 rp 是使用强的跳跃条件
12         {
13             int mp = lp + (rp - lp) / 2;
14             if (target < a[mp])
15                 rp = mp - 1;                        // 不要使用 mp 作为跳跃条件,会导致死循环
16             else if (target > a[mp])
17                 lp = mp + 1;
18             else
19                 return mp;
20         }
21         return -1;
22     }
23 
24     public int binarySearchRecursion(int [] a, int target)// 递归实现
25     {
26         return binarySearchRecursionKernel(a,target,0,a.length-1);
27     }
28 
29     private int binarySearchRecursionKernel(int [] a, int target, int lp, int rp)
30     {
31         for(;lp<=rp;)
32         {
33             int mp = lp + (rp - lp) / 2;
34             if (target < a[mp])
35                 return binarySearchRecursionKernel(a,target,lp,mp - 1);
36             else if (target > a[mp])
37                 return binarySearchRecursionKernel(a,target,mp + 1, rp);
38             else
39                 return mp;
40         }
41         return -1;
42     }
43 
44     public static void main(String[] args)
45     {
46         int N = 10000;
47         int [] a = new int [N];
48         for(int i=0;i<N;i++)
49             a[i] = i;//(int)(StdRandom.uniform()*10000);    // 注释部分留作随机检验
50         //Arrays.sort(a);
51 
52         int target = 7919;//(int)(StdRandom.uniform()*10000);
53         int output1 = binarySearch(a,target);
54         int output2 = binarySearchRecursion(a,target);
55 
56         System.out.printf("
%d,%d
",output1,output2);
57         return;
58     }
59 }

● 重复元素二分搜索,包括查找第一次出现、最后一次出现,以及出现多少次

 1 package package01;
 2 
 3 import java.util.Arrays;
 4 import edu.princeton.cs.algs4.StdRandom;
 5 
 6 public class class01
 7 {
 8     public int binarySearchFirst(int [] a, int target)                        // 寻找第一个等于键值的目标
 9     {
10         return binarySearchFirstKernel(a, target, 0, a.length-1);
11     }
12 
13     private int binarySearchFirstKernel(int [] a, int target,int lp,int rp)    // 添加起点和终点(两端点都包含),为了能与 Count 函数配合
14     {
15         for(;lp<=rp;)
16         {
17             int mp = lp + (rp - lp) / 2;
18             if (target < a[mp])
19                 rp = mp - 1;
20             else if (target > a[mp])
21                 lp = mp + 1;
22             else if(mp == 0 || target > a[mp-1])    // target == a[mp],找第一个
23                 return mp;                          // a[mp] 就是第一个
24             else                                    // a[mp] 前面还有等值的,不能强跳跃,否则可能跨空
25                 rp = mp;
26         }
27         return -1;
28     }
29 
30     public int binarySearchLast(int [] a, int target)                        // 寻找最后一个等于键值的目标
31     {
32         return binarySearchLastKernel(a,target, 0, a.length-1);
33     }
34 
35     private int binarySearchLastKernel(int [] a, int target,int lp, int rp)    // 添加起点和终点(两端点都包含)
36     {
37         for(;lp<=rp;)
38         {
39             int mp = lp + (rp - lp) / 2;
40             if (target < a[mp])
41                 rp = mp - 1;
42             else if (target > a[mp])
43                 lp = mp + 1;
44             else if(mp == a.length-1 || target < a[mp+1])   // target == a[mp],找最后一个
45                 return mp;                                  // a[mp] 就是第一个
46             else                                            // a[mp] 后面还有等值的,不能强跳跃,否则可能跨空
47                 lp = mp;
48         }
49         return -1;
50     }
51 
52     public int binarySearchCount(int [] a, int target)                        // 寻找等于键值的元素个数
53     {
54         int lp = 0, rp = a.length-1;
55         for(;lp<=rp;)
56         {
57             int mp = lp + (rp - lp) / 2;
58             if (target < a[mp])
59                 rp = mp - 1;
60             else if (target > a[mp])
61                 lp = mp + 1;
62             else                                            // 找到元素后,搜查首个和最后一个进行计数
63                 return binarySearchLastKernel(a,target,lp,rp) - binarySearchFirstKernel(a,target,lp,rp) + 1;
64         }
65         return -1;
66     }
67 
68     public static void main(String[] args)
69     {
70         int N = 10000;
71         int [] a = new int [N];
72         for(int i=0;i<N;i++)
73             a[i] = i/100;//(int)(StdRandom.uniform()*10000);    // 用于随机测试
74         //Arrays.sort(a);
75 
76         int target = 29;//(int)(StdRandom.uniform()*10000);        // 可以检验边界 0,99 等情况
77         int output1 = binarySearchFirst(a,target);
78         int output2 = binarySearchLast(a,target);
79         int output3 = binarySearchCount(a,target);
80 
81         System.out.printf("
%d,%d,%d
",output1,output2,output3);
82         return;
83     }
84 }

 ● 数组随机化

 1 package package01;
 2 
 3 public class class01
 4 {
 5     public static void shuffle(Object[] a)
 6     {
 7         int n = a.length;
 8         for (int i = 0; i < n; i++)// 每次在 a[0] ~ a[i] 中随机挑一个 a[r],交换 a[i] 与a[r]
 9         {
10             int r = (int)(Math.random() * (i + 1));
11             Object swap = a[r];
12             a[r] = a[i];
13             a[i] = swap;
14         }
15     }
16 
17     public static void shuffle2(Object[] a)
18     {
19         int n = a.length;
20         for (int i = 0; i < n; i++)// 每次在 a[i] 右边随机挑一个 a[r],交换 a[i] 与a[r]
21         {
22             int r = i + (int)(Math.random() * (n - i));
23             Object swap = a[r];
24             a[r] = a[i];
25             a[i] = swap;
26         }
27     }
28 
29     public static void main(String[] args)
30     {
31         String[] a = { "0","1","2","3","4","5","6","7","8","9" };
32         class01.shuffle(a);
33         for (int i = 0; i < a.length; i++)
34             System.out.print(a[i]);
35 
36         System.out.print("
");
37 
38         String[] b = { "0","1","2","3","4","5","6","7","8","9" };
39         class01.shuffle2(b);
40         for (int i = 0; i < a.length; i++)
41             System.out.print(b[i]);
42 
43         return;
44     }
45 }

 ● 计算图连通分量的算法。输入文件第一行是节点数,后面每行是一个连接的两端节点编号,用 java class01 < inputFile.txt 来运行。

  1 package package01;
  2 
  3 import edu.princeton.cs.algs4.StdIn;
  4 import edu.princeton.cs.algs4.StdOut;
  5 
  6 public class class01
  7 {
  8     private int[] parent;   // 节点祖先标记
  9     private int[] rank;     // 树深度,仅根节点有效
 10     private int count;      // 节点数
 11 
 12     public class01(int n)
 13     {
 14         count = n;
 15         parent = new int[n];
 16         rank = new int[n];
 17         for (int i = 0; i < n; i++)
 18         {
 19             parent[i] = i;
 20             rank[i] = 1;    // 源代码用的是 0 
 21         }
 22     }
 23 
 24     public int find(int p)  // 寻找 p 的根标号
 25     {
 26         for (validate(p); p != parent[p]; p = parent[p]);
 27         return p;
 28     }
 29 
 30     public int count()  // 节点数
 31     {
 32         return count;
 33     }
 34 
 35     public boolean connected(int p, int q)  // 判断 p 与 q 是否连通
 36     {
 37         return find(p) == find(q);
 38     }
 39 
 40     public void union(int p, int q)         // 合并 p 和 q
 41     {
 42         int rootP = find(p);
 43         int rootQ = find(q);
 44         if (rootP == rootQ)
 45             return;
 46 
 47         if (rank[rootP] < rank[rootQ])      // 较小树连接到较大树的树根上,树高按最大值计算
 48             parent[rootP] = rootQ;
 49         else if (rank[rootP] > rank[rootQ])
 50             parent[rootQ] = rootP;
 51         else                                // 两树等大,合并后树高增一
 52         {
 53             parent[rootQ] = rootP;
 54             rank[rootP]++;
 55         }
 56         count--;                            // 合并后连接分量减少
 57     }
 58 
 59     public void union2(int p, int q)        // 合并 p 和 q,第二种方法,更快
 60     {
 61         int rootP = find(p);
 62         int rootQ = find(q);
 63         if (rootP == rootQ)
 64             return;
 65 
 66         if (rank[rootP] < rank[rootQ])
 67         {
 68             parent[rootP] = rootQ;
 69             rank[rootQ] += rank[rootP];     // 树高按加和计算
 70         }
 71         else
 72         {
 73             parent[rootQ] = rootP;
 74             rank[rootP] += rank[rootQ];
 75         }
 76         count--;
 77     }
 78 
 79     private void validate(int p)    // 判断输入的 p 是否合法
 80     {
 81         if (p < 0 || p >= parent.length)
 82             throw new IllegalArgumentException("
p = " + p + "is illegal
");
 83     }
 84 
 85     public static void main(String[] args)
 86     {
 87         int n = StdIn.readInt();
 88         class01 uf = new class01(n);
 89         for (; !StdIn.isEmpty();)
 90         {
 91             int p = StdIn.readInt();
 92             int q = StdIn.readInt();
 93             if (uf.connected(p, q))
 94                 continue;
 95             uf.union(p, q);
 96             //StdOut.println(p + " " + q);
 97         }
 98         StdOut.println(uf.count() + " components");
 99     }
100 }
原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9748440.html