风也温柔

计算机科学知识库

java排课算法 java五大常用算法,早看早知道

  简介:算法一:分治法基本概念1.把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。2.分治策略是对于一个规模为n的 ...

  java排课算法_一致性hash算法java_矩形排样算法源码

  算法一:分治法

  基本概念

  1.把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

  2.分治策略是对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。

  适用情况

  1)该问题的规模缩小到一定的程度就可以容易地解决

  2)该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。

  3)利用该问题分解出的子问题的解可以合并为该问题的解;

  4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。

  分治法的复杂性分析

  一个分治法将规模为n的问题分成k个规模为n/m的子问题去解。设分解阀值n0=1,且adhoc解规模为1的问题耗费1个单位时间。再设将原问题分解为k个子问题以及用merge将k个子问题的解合并为原问题的解需用f(n)个单位时间。用T(n)表示该分治法解规模为|P|=n的问题所需的计算时间,则有:

  T(n)= k T(n/m)+f(n)

  通过迭代法求得方程的解:

  递归方程及其解只给出n等于m的方幂时T(n)的值,但是如果认为T(n)足够平滑,那么由n等于m的方幂时T(n)的值可以估计T(n)的增长速度。通常假定T(n)是单调上升的,从而当 mi≤n

  分治法例题:合并排序和快速排序

   class 分治_合并排序 {

  /**

  * 函数说明:在数组被拆分以后进行合并

  */

   void Merge(int a[], int left, int , int rigth) {

  //定义左端数组大小

  int n1 = - left+1;

  int n2 = rigth - ;

  //初始化数组,分配内存

  int bejin[] = new int[n1];

  int end[] = new int[n2];

  //数组赋值

  for(int i = 0; i < n1; i++)

  bejin[i] = a[left + i];

  for(int i = 0; i < n2; i++)

  end[i] = a[+1+i];

  //用key做原数组索引,没调用一次函数重新给原数组付一次值

  int i = 0, j = 0, key;

  for(key = left; key i&&n2>j&&i < n1 && bejin[i] i&&n2>j&&j < n2 && bejin[i] >= end[j])

  a[key] = end[j++];

  else if(i == n1 && j < n2)

  a[key] = end[j++];

  else if(j == n2 && i < n1)

  a[key] = bejin[i++];

  }

  }

  /**

  * 差分数组区间,不断分支

  */

   void (int a[],int left,int rigth) {

  int =0;

  if(left

   =(rigth+left)/2;

  (a, left, );

  (a, +1, rigth);

  Merge(a, left, , rigth);

  }

  }

   void main([] args) {

  int a[]= {85,3,52,9,7,1,5,4};

  (a, 0,7);

  for(int i=0;i

  .out.print(" "+a[i]);

  }

  }

  }

   class 分治_快速排序 {

  /**

  *交换函数,i,j为数组索引

  */

   void swap(int A[], int i, int j)

  {

  int temp = A[i];

  A[i] = A[j];

  A[j] = temp;

  }

  /**

  * 选取一个关键字(key)作为枢轴,一般取整组记录的第一个数/最后一个,这里采用选取序列最后一个数为枢轴。

  * 设置两个变量left = 0;right = N - 1;

  * 从left一直向后走,直到找到一个大于key的值,right从后至前,直至找到一个小于key的值,然后交换这两个数。

  * 重复第三步,一直往后找,直到left和right相遇,这时将key放置left的位置即可。

  * @

  */

   int (int[] array,int left,int right)

  {

  int key = array[right];//定义基准

  int count=right;//保存rigth值

  while(left < right)//防止数组越界

  {

  while(left < right && array[left] = key)

  {

  --right;

  }

  swap(array,left,right);

  }

  swap(array,right,count);

   right;

  }

  /**

  *分治思想,递归调用

  */

   void (int array[],int left,int right)

  {

  if(left >= right)//表示已经完成一个组

  {

  ;

  }

  int index = (array,left,right);//枢轴的位置

  (array,left,index - 1);

  (array,index + 1,right);

  }

   void main([] args) {

  int a[]= {1,5,-5,54,15,67,16,23};

  (a,0,7);

  for(int i=0;i

  .out.print(" "+a[i]);

  }

  .out.print("\n");

  }

  }

  算法心得

  作为分治法里很典型的一种算法,合并排序和快速排序充分展现了分治法的思想,分而治之,在此次编程使用此方法中,给我的体会是程序简单分为两部分,第一部分,不断“拆”,缩小子问题规模,达到最优子结构。然后合并,在合并过程中,应为子问题足够小,容易计算,再者不断合并子问题答案,最终求出问题解。

  一致性hash算法java_矩形排样算法源码_java排课算法

  算法二:贪心算法

  一、基本概念:

  所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。

  贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。

  所以对所采用的贪心策略一定要仔细分析其是否满足无后效性。

  二、贪心算法的基本思路:

  1.建立数学模型来描述问题。

  2.把求解的问题分成若干个子问题。

  3.对每一子问题求解,得到子问题的局部最优解。

  4.把子问题的解局部最优解合成原来解问题的一个解。

  三、贪心算法适用的问题

  贪心策略适用的前提是:局部最优策略能导致产生全局最优解。

  实际上,贪心算法适用的情况很少。一般,对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,就可做出判断。

  四、贪心算法的实现框架

  从问题的某一初始解出发;

  while (能朝给定总目标前进一步)

  {

  利用可行的决策,求出可行解的一个解元素;

  }

  由所有解元素组合成问题的一个可行解;

  五、贪心策略的选择

  因为用贪心算法只能通过解局部最优解的策略来达到全局最优解,因此,一定要注意判断问题是否适合采用贪心算法策略,找到的解是否一定是问题的最优解。

  贪心策略例题:prim算法

   java.util.*;

   class 贪心算法_prim算法 {

   int MAX = .;

   void main([] args) {

  //定义无向图矩阵

  int[][] map = new int[][] {

  { 0, 1, 6, 2},

  { 1, 0, 3, 2},

  { 6, 3, 0, 1},

  { 2, 2, 1, 0}

  };

  prim(map, map.);

  }

   void prim(int[][] graph, int n){

  //定义节点名字

  char[] c = new char[]{'A','B','C','D'};

  int[] = new int[n]; //到新集合的最小权

  int[] mid= new int[n];//存取前驱结点

  List list=new ();//用来存储加入结点的顺序

  int i, j, min, minid , sum = 0;

  //初始化辅助数组

  for(i=1;i

  {

  [i]=graph0;

  mid[i]=0;

  }

  list.add(c[0]);

  //一共需要加入n-1个点

  for(i=1;i

  {

  min=MAX;

  minid=0;

  //每次找到距离集合最近的点

  for(j=1;j

  {

  if([j]!=0&&[j]

  {

  min=[j];

  minid=j;

  }

  }

  if(minid==0) ;

  list.add(c[minid]);

  [minid]=0;

  sum+=min;

  .out.(c[mid[minid]] + "到" + c[minid] + " 权值:" + min);

  //加入该点后,更新其它点到集合的距离

  for(j=1;j

  {

  if([j]!=0&&[j]>graphminid)

  {

  [j]=graphminid;

  mid[j]=minid;

  }

  }

  .out.print("\n");

  }

  .out.("sum:" + sum);

  }

  }

  算法心得

  Prim算法是贪婪策略的一种很好的体现,在实现prim算法中,认识到java排课算法 java五大常用算法,早看早知道,贪婪策略是在做当先选择的情况下,先行囊括所有的选择储存好,在根据贪婪策略,选出最符合的步骤进行下去。虽然贪婪策略比较迅捷,应为它不需要预算所有情况(类似回溯),但应为每次所求只是局部最优解,所以结果不一定是最优解,算法准确性在与贪婪策略的选取好坏,所以也具有一定的局限性!

  算法三:动态规划算法

  一、基本概念

  动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。

  二、基本思想与策略

  基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解java排课算法,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。

  由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。

  与分治法最大的差别是:适合于用动态规划法求解的问题,经分解后得到的子问题往往不是互相独立的(即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解)。

  java排课算法_一致性hash算法java_矩形排样算法源码

  三、适用的情况

  能采用动态规划求解的问题的一般要具有3个性质:

  (1) 最优化原理:如果问题的最优解所包含的子问题的解也是最优的java排课算法,就称该问题具有最优子结构,即满足最优化原理。

  (2) 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。

  (3)有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势)

  三、算法实例:背包问题

   class 动态规划_背包问题 {

   void main([] args) {

  //物品价值,重量,和背包承重

  int v[]={0,8,10,6,3,7,2};

  int w[]={0,4,6,2,2,5,1};

  int c=12;

  //定义二位数组动态规划背包价值和重量

  int m[][]=new intv.;

  for (int i = 1; i

  for (int j = 1; j =w[i])

  mi=mi-1]+v[i]>mi-1?mi-1]+v[i]:mi-1;

  else

  mi=mi-1;

  }

  }

  int max=0;

  for (int i = 0; i

  for (int j = 0; j max)

  max=mi;

  }

  }

  .out.(max);

  }

  }

  四、算法心得

  在此次编程中,运用动态内存算法解决背包问题,发先所需分配空间量比较大,在做背包容量小,物平少时还好。如果涉及数量打一是内存占用会比较严重,计算量也会大大提高。动态分配内存类似分治法,把问题分成多个子问题,一步步求解,且前面求出的子问题会对后面所求子问题有影响,不像是分治法的子问题都是独立的。并且时刻给与一个状态值,记录最优解,当所有子问题都解决完时,最优解也就会成为了问题的解了。重点主要在于对内存的分配,和子问题的计算。

  一致性hash算法java_矩形排样算法源码_java排课算法

  算法四:回溯法

  1、概念

  回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。

  回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

  许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。

  2、基本思想

  在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。

  若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。

  而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。

  3、用回溯法解题的一般步骤:

  (1)针对所给问题,确定问题的解空间:

  首先应明确定义问题的解空间,问题的解空间应至少包含问题的一个(最优)解。

  (2)确定结点的扩展搜索规则

  (3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。

  4、算法实例:求子集问题

   class 回溯法_求子集问题 {

   int[] s = {2,2,3};

   int n = s.;

   int[] x = new int[n];

  /**

  * 输出集合的子集

  * @param limit 决定选出特定条件的子集

  * 注:all为所有子集,num为限定元素数量的子集,

  * sp为限定元素奇偶性相同,且和小于8。

  */

   void ( limit){

  (limit){

  case "all":(0);break;

  case "num":(0);break;

  case "sp":(0);break;

  }

  }

  /**

  * 回溯法求集合的所有子集,依次递归

  * 注:是否回溯的条件为精髓

  * @param t

  */

   void (int t){

  if(t >= n)

  (x);

  else

  for (int i = 0; i = n)

  (x);

  else

  for (int i = 0; i

  文章来源:https://zhuanlan.zhihu.com/p/126276575