zoukankan      html  css  js  c++  java
  • 常见算法

    【写在前面】

    • 这个是在巩固常见算法学习过程做的一些笔记
    • 可看《数据结构与算法图解》[美]杰伊·温格罗(人民邮电出版社),讲解简单清晰
    • 有道云普通链接
    • 有道云md地址


    前言

    大O记法( 步数)=时间复杂度、速度、性能,大O技法关注点是长期增长率,所以有以下几个注意点

    大O记法:

    • 忽略常数,不包括一般数字,除非是指数,例如O(N²/2)=O(N²)

    • 只关注最高阶,因为随着数据量的增大,最主要的影响因素是最高阶的数据,所以O(N²+N)=O(N²)

    1. 冒泡排序

    • 思路:两两交换,较大的数值放后,第一次排序后最大已经在末尾
    • 算法动图•ᴗ•
    • 特点:需要n-1趟,比如10个数字,需要9次。for嵌套:时间复杂度是O(n²)

    代码实现要点:

    • 两个for循环,外层控制排序趟数,内层控制比较次数,因为每趟排序完成都会把最大的推到后面,所以每次趟数过后比较数都要减1
    • 优化:如果一次排序后没有交换位置那么该数组已经有序。
    int[] list=new  int[]{1,4,3,2,9,7,8};
    //事先申明免得每次换的时候都要实例化新的对象占用内存,设置参省防止没有循环导致的错误
    int tem;
    boolean isChange;
    
    for(int i=0;i<list.length;i++)
    {
      isChange=false;
      for(int j=0;j<list.length-1-i;j++)
      {
          if(list[j]>list[j+1])
          {
              tem=list[j];
              list[j]=list[j+1];
              list[j+1]=tem;
              isChange=true;
          }
      }
    
      //如果一趟下来没有排序,则说明已经排好了,不需要再执行后面排序
      if(isChange==false)
      {
          break;
      }
    }
    

    【补充】算法是否稳定判定方法:一个数组里相同的值,例如有两个4,结果经过排序之后,原来的第一个4排到了第二个4后面,那么就是不稳定的,反之则还是稳定的。

    2. 选择排序

    • 思路原理:找出等待排序的数组里最小(最大)的数,与待排序最前(最后)的数字替换,然后逐次将未排序完的循环排序,就能得到正确的数组顺序。
    • 算法动图•ᴗ•
    • 特点:不稳定,for嵌套:时间复杂度是O(n²),但其实是冒泡循环的一半左右
    //选择排序
    int[] list=new  int[]{1,4,3,2,5,10,6,9,7,8};
    //事先申明免得每次换的时候都要实例化新的对象占用内存,设置参省防止没有循环导致的错误
    //存放临时变量和下标
    int temp,pos;
    
    for(int i=0;i<list.length-1;i++)
    {
        pos=i;
        for(int j=i+1;j<list.length;j++)
        {
            if(list[i]>list[j])
            {
                pos=j;
            }
        }
        
        if(pos!=i)
        {
            temp=list[i];
            list[i]=list[pos];
            list[pos]=temp;
        }
        System.out.println("每次输出结果:"+Arrays.toString(list));
    }
    
    System.out.println("最后结果:"+Arrays.toString(list));
    

    【补充】 三大经典排序可参考链接>> 含算法动图 <<

    3. 插入排序

    • 思路原理:将一个数据插入到已经排好序的有序数组,从而得到一个新的、个数加1的有序数组。其实就是将前面的数组慢慢排成有序的数组(第一个默认是有序的,第二个要和第一对比排序,以此类推),每次将还没排序的数插入到前面的有序数组中,最终得到一个有序的数组。
    • 特点:稳定,趟数也是n-1,时间复杂度为O(N²),但其实是O(N²+N),适用于少量数据的排序。
    //插入排序
    int[] list=new  int[]{1,4,3,2,5,10,6,9,7,8};
    //事先申明免得每次换的时候都要实例化新的对象占用内存,设置参省防止没有循环导致的错误
    //存放临时变量和下标
    int temp,pos;
    
    for(int i=1;i<list.length;i++)
    {
        pos=i;
        temp=list[i];
        System.out.println("要替换的元素下标是"+i);
        
        //循环体有自减过程,为了替换时不越界,设置为》=1
        //将待排序元素前面的元素  与待排序元素比较
        //如果是for循环嵌套,那么里面还需要多一个if判断,因此换成while
        while (pos>=1&&list[pos-1]>=temp) {
            System.out.print("i,j="+i+","+pos+"  替换:"+Arrays.toString(list)+"
    ");
            list[pos]=list[pos-1];
            pos--;	
        }
        
        //替换
        list[pos]=temp;
        
        System.out.println("输出结果:"+Arrays.toString(list)+"
    ");
    }
    
    System.out.println("最后结果:"+Arrays.toString(list));
    

    4. 快速排序

    • 思路:选定某个数字为基准数,将比基准数小的数字放到左边,大的数放到右边。

    • 算法动图•ᴗ•

    • 特点:是不稳定的

    实现要点:指定最左和最右为L和R指针,如果选定的是左边第一个数字作为基准数

    • (步骤1)则从右边开始移动指针,如果有比基准数小的数,则将R指针与L指针所指的数交换。
    • (步骤2)第一次排序完成后,再从左边指针开始扫,如果有比基准数大的数,则将指针所指数交换。
    • 重复步骤1、2,直到L和R指针的位置重复,此时说明已经完成排序。
    package cn.lxy;
    public class Test {
       
      public static void main(String[] args) {
        int[] list = new int[] {5, 3, 8, 50, 6, 7, 20, 4, 9};
        for(int j:list)
        {
          System.out.print("-"+j+"-");
        }
        System.out.println();
        System.out.println("开始快速排序");
        getPartition(list,0,list.length-1);
       
        System.out.println("排序结果");
        for(int j:list)
        {
          System.out.print("-"+j+"-");
        }
       
      }
      //找到分割点并递归
      public static  void getPartition(int[] list, int left, int right)
      {
        if(left>=right)
        {
         return;
        }
       
        //存放临时变量
        int l,r,temp;
        l=left;
        r=right;
        //基准数
        int pivot=list[left];
        while (l<r)
        {
            //找到比基数小的数就交换,否则就一直移动下标。
            //这里的left小于right是因为后面的while可能会改变left和right的下标
           while(l<r&&list[r]>pivot)
            {
                r--;
            }
           
           
            //比基准数小的话就继续移动下标
            while (l<r&&list[l]<pivot)
            {
                l++;
            }
           
            if (l<r)
            {
              temp=list[l];
              list[l]=list[r];
              list[r]=temp;       
            } 
           
            System.out.println("(l:"+l+",r:"+r+")");    
        }
       
        list[l]=pivot;
        System.out.println("---基准点:list["+left+"]="+pivot+"---
    排序过程:");
        for (int j:list)
        {
          System.out.print("-"+j+"-");
        }
        System.out.println();
        getPartition(list,left,r-1);
        getPartition(list,r+1,right);
        
      }
     
     
    }
    

    5. 其他排序

    to be done

  • 相关阅读:
    threadlocal 变量 跟synchronized 关键字的关系
    Android媒体扫描详细解析之一(MediaScanner & MediaProvider)
    创建视图全文搜索[完整版]
    海量小文件问题综述
    内存拷贝探究
    case功能菜单选项
    linux case ${variable} in
    attack source code
    ftps加密服务器
    vim编程设置
  • 原文地址:https://www.cnblogs.com/inkqx/p/12317191.html
Copyright © 2011-2022 走看看