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

● 代码,二分搜索

  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. }

《算法》第一章部分程序 part 1的更多相关文章

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

    ▶ 书中第一章部分程序,加上自己补充的代码,包括简单的计时器,链表背包迭代器,表达式计算相关 ● 简单的计时器,分别记录墙上时间和 CPU 时间. package package01; import ...

  2. C语言编程入门之--第一章初识程序

    第一章 初识程序 导读:计算机程序无时不刻的影响着人类的生活,现代社会已经离不开程序,程序的作用如此巨大,那么程序到底是什么呢?本章主要讨论程序的概念,唤起读者对程序的兴趣,同时对C语言程序与其它语言 ...

  3. windows核心编程-第一章 对程序错误的处理

    第一章-对程序错误的处理 在开始介绍Microsoft Windows 的特性之前,必须首先了解 Wi n d o w s的各个函数是如何进行错误处理的. 当调用一个Wi n d o w s函数时,它 ...

  4. 第一章 Python程序语言简介

    第一节 Python概述 1. 什么是Python Python是一种 解释型.面向对象.动态数据类型 的高级程序设计语言.由Guido van Rossum与1989年发明,第一个公开发行版本发行于 ...

  5. ASP.NET本质论第一章网站应用程序学习笔记3-对象化的Http

    在.NET环境下,万物皆对象,在HttpRuntime收到请求之后,立即将通过HttpWorkerRequest传递的参数进行分析和分解,创建方便用于网站应用程序处理用的对象,其中主要涉及到两个对象类 ...

  6. ASP.NET本质论第一章网站应用程序学习笔记2

    1.初步走进ASP.NET 上篇笔记我们讲述了服务器监听问题,这篇我们就要讲述具体的请求处理了,ASP.NET所涉及的类大多数定义在System.Web程序集中. 在.NET中,程序集管理的最小逻辑单 ...

  7. ASP.NET本质论第一章网站应用程序学习笔记1

    1.统一资源标示符 1) 格式:协议://主机[.端口号][绝对路径[?参数]],在Http://www.kencery.com/hyl/index/login中,http表示协议的名称,www.ke ...

  8. 《程序是怎样跑起来的》读书笔记——第一章 对程序员来说CPU是什么

    1 程序的运行流程 2 CPU的组成 3 寄存器的主要种类和功能 "程序计数器"--决定程序流程的 4 条件分支和循环机制 4.1 顺序执行 4.2 选择分支 5 函数的调用机制 ...

  9. 【学习总结】java数据结构和算法-第一章-内容介绍和授课方式

    总目录链接 [学习总结]尚硅谷2019java数据结构和算法 github:javaDSA 目录 几个经典算法面试题 算法和数据结构的重要性 几个经典算法面试题 字符串匹配 暴力法:慢 kmp算法:更 ...

随机推荐

  1. WPF DataGrid 导出Excel

    #region Excel导出 private void btnExportExcel_Click(object sender, RoutedEventArgs e) { Export(this.dg ...

  2. 跟着未名学Office - 熟练使用WORD

    目录 第一章.Word之编辑篇. 1 第一节 页面布局... 1 第二节 格式编辑... 1 第三节 表.图.域... 5 第四节 审阅.保护... 7 第五节 *插入对像... 9 第二章.Word ...

  3. 为什么.net 4.6.1装了却没看到

    今天在做SignalR网站,需要在发布到的云服务器安装.net4.6.1 从网上下载了安装包,安装完之后,到Windows文件夹的 Microsoft.NET文件夹中却找不到4.6.1的文件夹. 云服 ...

  4. problem:vue之数据变更没有触发视图更新问题

    前言: 数据变更之后,vue如何渲染dom? 实际场景: 更新数据之后,再设置滚动条的位置为什么设置无效? 为什么将隐藏的元素设置为显示状态之后,读取元素状态读取不到? 改变了对象/数组中的值,页面没 ...

  5. 《Java并发编程实战》笔记-取消与关闭

    1,中断是实现取消的最合理方式.2,对中断操作的正确理解是:它并不会真正地中断一个正在运行的线程,而只是发出中断请求,然后由线程在下一个合适的时刻中断自己.3,区分任务和线程对中断的反应是很重要的4, ...

  6. 关于Strategy和State设计模式

    之前,我在描述我所采用的设计模式时,一直在Strategy和State之间犹豫,略微有些拿捏不准,说哪种设计模式好.结果到最后,会根据自己所想,觉得是State就是State,觉得Strategy就是 ...

  7. 网站简介-为什么网站的ICO图标更新后,ie浏览器没有更新过来?

    为什么网站的ICO图标更新后,ie浏览器没有更新过来? 如何更新本地ico图标? 收藏夹里的网址访问后网站ico小图标怎么不会更新,还是没图标的. 如果制作了一个新的favicon.ico图标,并且已 ...

  8. hadoop ha环境下的datanode启动报错java.lang.NumberFormatException: For input string: "10m"

    hadoop ha环境启动start-dfs.sh的时候datanode启动不了,并且报错. [hadoop@datanode2 ~]$ cat /home/hadoop/hadoop-2.7.3/l ...

  9. sas share 备忘录

    options comamid=tcp;libname payable 'E:\shouen';proc server authenticate=optional id=share1 msgnumbe ...

  10. mysql 5.7主从库复制设置

    先要修改配置文件,重启mysql服务 log-bin= mysql-binlog # 打开二进制日志 ,最好放在不同的硬盘上,减小 IO 消耗 expire_logs_day= # 设置二进制日志保存 ...