《算法》第一章部分程序

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

● 代码,二分搜索

 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("\n%d,%d\n",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("\n%d,%d,%d\n",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("\n");
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("\np = " + p + "is illegal\n");
 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

时间: 2024-12-29 10:37:26

《算法》第一章部分程序的相关文章

javascript数据结构和算法 第一章(编程体验)三

变量作用域 变量作用域就是指在一个程序中,变量的值在哪里可以被获取到.javascript函数作用域被定义为函数作用域,这意味着变量的值在定义和声明该变量的函数,包括任何在该函数的嵌套函数里是可见的. 当一个变量定义在函数的外面,在主程序中,该变量将会拥有全局作用域.这就意味着它的值可以被程序的任何地方,包括函数获取. 下面的小程序演示全局变量时如何工作的. function showScope() { return scope; } var scope = "global"; pri

javascript数据结构和算法 第一章(Javascript编程环境和模型) 一

这一章介绍了我们在这本书中使用的描述各种数据结构和算法的Javascript的编程环境和编程架构. Javascript 环境 Javascript 在很长一段时间都是被作为web浏览器内置脚本编程语言来使用. 然而,在过去几年里,javascript编程环境得到了极大的发展,他们可以使javascript在桌面或者服务端运行. 在我们这本书中,我们使用其中的一个javascript环境:javascript shell:是Mozilla公司的javascript环境,被称为SpiderMonk

javascript数据结构和算法 第一章(编程体验)一

声明和初始化变量 Javascript变量默认是全局作用域的.严格来说,使用之前是不需要定义的. 当一个javascript变量在没有被声明之前直接进行初始化,它就是一个全局变量.在这本书中,我们沿用编译语言如c++和java的编程约定.在使用变量之前都进行声明. 这还有一个附带的好处,声明的变量可以作为本地变量. 我们将会在本章节的后面讨论更多关于变量的作用域. 声明javascript变量,使用关键字var 变量名称.可选择的,可以带上赋值表达式. 下面是一些例子 var number; v

第一章 Windows程序内部运行机制(4)WinMain函数

WinMain函数相当于main函数,作为Windows程序的入口函数.当WinMain结束或返回时,Windows程序结束. 一个win32应用程序,该程序创建一个窗口并在窗口中响应键盘与鼠标消息,程序的实现步骤为: 1.WinMain函数的定义:2.创建一个窗口:3.进行消息循环:4.编写窗口过程 WinMain函数的定义: int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, in

解决《C++ Primer》第一章书店程序问题

第一章1.6节有一个书店程序问题,按照书上的代码,编译器就会报错,显示 aa.cpp:13:32: error: no match for call to '(std::__cxx11::string {aka std::__cxx11::basic_string<char>}) ()' if(item1.isbn()==item2.isbn()) ^ aa.cpp:13:46: error: no match for call to '(std::__cxx11::string {aka s

算法第一章小结

第一章主要介绍的内容是算法的时间复杂度还有NP完全问题. 算法的复杂度分析主要包括空间复杂度和时间复杂度,但空间复杂度一般我们不去分析,因为现在的硬件水平确实处于较高的水平,所以我们一般会去分析时间复杂度.时间复杂度用O(n)表示. NP完全问题的概念比较难理解.简单来说,就是如果一个问题A,且A∈NP,并且在多项式时间内可解,那么就叫做NP完全问题. 那么NP问题是什么呢?就是说如果一个问题,它无法通过确定的算法去计算出相应的结果,但是却可以用算法去验证一个猜测的答案. 原文地址:https:

第一章 C 程序的框架结构

计算机系统是由硬件系统和软件系统构成,硬件由IBM.HP.DLL.Acer以及联想这样的工厂制造出来,叫裸机.软件由微软.Oracle以及用友等公司的程序员用计算机语言编写出来的,叫程序.程序和编写该程序的文档一起构成了软件系统.裸机安装上了操作系统就构成了第一层虚拟机,计算机软硬件资源由操作系统来管理.在操作系统之上安装应用软件,就构成第二层虚拟机,用户一般与这层计算机打交道的.应用软件提供一个输入数据的界面,用户通过这个界面将要加工的原始数据(文字.数值 .声音.图片.图形.动画.电影等)输

第一章 Windows程序内部运行机制(3)消息与消息队列

在Windows中,用户程序可以调用系统的API函数,系统也会调用用户程序,这个调用时通过消息来进行的. Windows程序设计是一种事件驱动方式的程序设计模式,主要基于消息. [例]当用户在窗口中画图的时候,按下鼠标左键,操作系统就会感知到这一事件,于是将这个事件包装成一个消息,投递到应用程序的消息队列中,然后应用程序从消息队列中取出消息进行响应.在处理过程中,操作系统会给应用程序“发送消息”.“发送消息”实际上是指操作系统调用程序中一个专门负责处理消息的函数,这个函数称为窗口过程. 1.消息

VC++深入详解 孙鑫 第一章 Windows程序内部运行机制

1.API与SDK API (Application Programming Interface) 应用程序接口 SDK(Software Development Kit) 软件开发包,包括API函数,帮助文档,微软提供的一些辅助开发工具. 2.窗口和句柄 窗口是是屏幕上一块矩形区域,是Windows应用程序与用户进行交互的接口: 在Windows应用程序中,窗口是通过窗口句柄(资源标识)来标识的. 3.消息和消息队列 Windows程序设计是一种基于消息的事件驱动方式的程序设计模式. 每当一个