「归纳|总结」程序员必知必会的十大排序算法

14 篇文章 6 订阅
订阅专栏

微信搜一搜「bigsai」关注这个有趣的程序员
新人原创公众号,求支持一下!你的点赞三连肯定对我至关重要!
文章已收录在 我的Github bigsai-algorithm 欢迎star

本文目录

    • 绪论
    • 交换类
      • 冒泡排序
      • 快速排序
    • 插入类排序
      • 直接插入排序
      • 希尔排序
    • 选择类排序
      • 简单选择排序
      • 堆排序
    • 归并类排序
      • 归并排序
    • 桶类排序
      • 桶排序
      • 计数排序
      • 基数排序
    • 结语

绪论

身为程序员,十大排序是是所有合格程序员所必备和掌握的,并且热门的算法比如快排、归并排序还可能问的比较细致,对算法性能和复杂度的掌握有要求。bigsai作为一个负责任的Java和数据结构与算法方向的小博主,在这方面肯定不能让读者们有所漏洞。跟着本篇走,带你捋一捋常见的十大排序算法,轻轻松松掌握!

首先对于排序来说大多数人对排序的概念停留在冒泡排序或者JDK中的Arrays.sort(),手写各种排序对很多人来说都是一种奢望,更别说十大排序算法了,不过还好你遇到了本篇文章!

对于排序的分类,主要不同的维度比如复杂度来分、内外部、比较非比较等维度来分类。我们正常讲的十大排序算法是内部排序,我们更多将他们分为两大类:基于比较和非比较这个维度去分排序种类。

  • 非比较类的有桶排序、基数排序、计数排序。也有很多人将排序归纳为8大排序,那就是因为基数排序、计数排序是建立在桶排序之上或者是一种特殊的桶排序,但是基数排序和计数排序有它特有的特征,所以在这里就将他们归纳为10种经典排序算法。而比较类排序也可分为
  • 比较类排序也有更细致的分法,有基于交换的、基于插入的、基于选择的、基于归并的,更细致的可以看下面的脑图。

image-20201120124138560

交换类

冒泡排序

冒泡排序,又称起泡排序,它是一种基于交换的排序典型,也是快排思想的基础,冒泡排序是一种稳定排序算法,时间复杂度为O(n^2).基本思想是:循环遍历多次每次从前往后把大元素往后调,每次确定一个最大(最小)元素,多次后达到排序序列。(或者从后向前把小元素往前调)。

具体思想为(把大元素往后调):

  • 从第一个元素开始往后遍历,每到一个位置判断是否比后面的元素大,如果比后面元素大,那么就交换两者大小,然后继续向后,这样的话进行一轮之后就可以保证最大的那个数被交换交换到最末的位置可以确定
  • 第二次同样从开始起向后判断着前进,如果当前位置比后面一个位置更大的那么就和他后面的那个数交换。但是有点注意的是,这次并不需要判断到最后,只需要判断到倒数第二个位置就行(因为第一次我们已经确定最大的在倒数第一,这次的目的是确定倒数第二)
  • 同理,后面的遍历长度每次减一,直到第一个元素使得整个元素有序。

例如2 5 3 1 4排序过程如下:

image-20201120155114930

实现代码为:

public void  maopaosort(int[] a) {
  // TODO Auto-generated method stub
  for(int i=a.length-1;i>=0;i--)
  {
    for(int j=0;j<i;j++)
    {
      if(a[j]>a[j+1])
      {
        int team=a[j];
        a[j]=a[j+1];
        a[j+1]=team;
      }
    }
  }
}

快速排序

快速排序是对冒泡排序的一种改进,采用递归分治的方法进行求解。而快排相比冒泡是一种不稳定排序,时间复杂度最坏是O(n^2),平均时间复杂度为O(nlogn),最好情况的时间复杂度为O(nlogn)。

对于快排来说,基本思想是这样的

  • 快排需要将序列变成两个部分,就是序列左边全部小于一个数序列右面全部大于一个数,然后利用递归的思想再将左序列当成一个完整的序列再进行排序,同样把序列的右侧也当成一个完整的序列进行排序。
  • 其中这个数在这个序列中是可以随机取的,可以取最左边,可以取最右边,当然也可以取随机数。但是通常不优化情况我们取最左边的那个数。

image-20201120133851275

实现代码为:

public void quicksort(int [] a,int left,int right)
{
  int low=left;
  int high=right;
  //下面两句的顺序一定不能混,否则会产生数组越界!!!very important!!!
  if(low>high)//作为判断是否截止条件
    return;
  int k=a[low];//额外空间k,取最左侧的一个作为衡量,最后要求左侧都比它小,右侧都比它大。
  while(low<high)//这一轮要求把左侧小于a[low],右侧大于a[low]。
  {
    while(low<high&&a[high]>=k)//右侧找到第一个小于k的停止
    {
      high--;
    }
    //这样就找到第一个比它小的了
    a[low]=a[high];//放到low位置
    while(low<high&&a[low]<=k)//在low往右找到第一个大于k的,放到右侧a[high]位置
    {
      low++;
    }
    a[high]=a[low];			
  }
  a[low]=k;//赋值然后左右递归分治求之
  quicksort(a, left, low-1);
  quicksort(a, low+1, right);		
}

插入类排序

直接插入排序

直接插入排序在所有排序算法中的是最简单排序方式之一。和我们上学时候 从前往后、按高矮顺序排序,那么一堆高低无序的人群中,从第一个开始,如果前面有比自己高的,就直接插入到合适的位置。一直到队伍的最后一个完成插入整个队列才能满足有序。

直接插入排序遍历比较时间复杂度是每次O(n),交换的时间复杂度每次也是O(n),那么n次总共的时间复杂度就是O(n2)。有人会问折半(二分)插入能否优化成O(nlogn),答案是不能的。因为二分只能减少查找复杂度每次为O(logn),而插入的时间复杂度每次为O(n)级别,这样总的时间复杂度级别还是O(n2).

插入排序的具体步骤:

  • 选取当前位置(当前位置前面已经有序) 目标就是将当前位置数据插入到前面合适位置。
  • 向前枚举或者二分查找,找到待插入的位置。
  • 移动数组,赋值交换,达到插入效果。

image-20201120160709469

实现代码为:

public void insertsort (int a[])
{
  int team=0;
  for(int i=1;i<a.length;i++)
  {
    System.out.println(Arrays.toString(a));
    team=a[i];
    for(int j=i-1;j>=0;j--)
    {

      if(a[j]>team)
      {
        a[j+1]=a[j];
        a[j]=team;	
      }	
      else {
        break;
      }
    }
  }	
}

希尔排序

直接插入排序因为是O(n^2),在数据量很大或者数据移动位次太多会导致效率太低。很多排序都会想办法拆分序列,然后组合,希尔排序就是以一种特殊的方式进行预处理,考虑到了数据量和有序性两个方面纬度来设计算法。使得序列前后之间小的尽量在前面,大的尽量在后面,进行若干次的分组别计算,最后一组即是一趟完整的直接插入排序。

对于一个长串,希尔首先将序列分割(非线性分割)而是按照某个数模(取余这个类似报数1、2、3、4。1、2、3、4)这样形式上在一组的分割先各组分别进行直接插入排序,这样很小的数在后面可以通过较少的次数移动到相对靠前的位置。然后慢慢合并变长,再稍稍移动。

因为每次这样插入都会使得序列变得更加有序,稍微有序序列执行直接插入排序成本并不高。所以这样能够在合并到最终的时候基本小的在前,大的在后,代价越来越小。这样希尔排序相比插入排序还是能节省不少时间的。

image-20201120164448973

实现代码为:

public void shellsort (int a[])
{
  int d=a.length;
  int team=0;//临时变量
  for(;d>=1;d/=2)//共分成d组
    for(int i=d;i<a.length;i++)//到那个元素就看这个元素在的那个组即可
    {
      team=a[i];
      for(int j=i-d;j>=0;j-=d)
      {				
        if(a[j]>team)
        {
          a[j+d]=a[j];
          a[j]=team;	
        }
        else {
          break;
        }
      }
    }	
}

选择类排序

简单选择排序

简单选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

image-20201120201910761

实现代码为:

public void selectSort(int[] arr) {
  for (int i = 0; i < arr.length - 1; i++) {
    int min = i; // 最小位置
    for (int j = i + 1; j < arr.length; j++) {
      if (arr[j] < arr[min]) {
        min = j; // 更换最小位置
      }
    }
    if (min != i) {
      swap(arr, i, min); // 与第i个位置进行交换
    }
  }
}
private void swap(int[] arr, int i, int j) {
  int temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
}

堆排序

对于堆排序,首先是建立在堆的基础上,堆是一棵完全二叉树,还要先认识下大根堆和小根堆,完全二叉树中所有节点均大于(或小于)它的孩子节点,所以这里就分为两种情况

  • 如果所有节点大于孩子节点值,那么这个堆叫做大根堆,堆的最大值在根节点。
  • 如果所有节点小于孩子节点值,那么这个堆叫做小根堆,堆的最小值在根节点。

在这里插入图片描述

堆排序首先就是建堆,然后再是调整。对于二叉树(数组表示),我们从下往上进行调整,从第一个非叶子节点开始向前调整,对于调整的规则如下:

建堆是一个O(n)的时间复杂度过程,建堆完成后就需要进行删除头排序。给定数组建堆(creatHeap)

①从第一个非叶子节点开始判断交换下移(shiftDown),使得当前节点和子孩子能够保持堆的性质

②但是普通节点替换可能没问题,对如果交换打破子孩子堆结构性质,那么就要重新下移(shiftDown)被交换的节点一直到停止。

在这里插入图片描述

堆构造完成,取第一个堆顶元素为最小(最大),剩下左右孩子依然满足堆的性值,但是缺个堆顶元素,如果给孩子调上来,可能会调动太多并且可能破坏堆结构。

①所以索性把最后一个元素放到第一位。这样只需要判断交换下移(shiftDown),不过需要注意此时整个堆的大小已经发生了变化,我们在逻辑上不会使用被抛弃的位置,所以在设计函数的时候需要附带一个堆大小的参数。

②重复以上操作,一直堆中所有元素都被取得停止。

在这里插入图片描述

而堆算法复杂度的分析上,之前建堆时间复杂度是O(n)。而每次删除堆顶然后需要向下交换,每个个数最坏为logn个。这样复杂度就为O(nlogn).总的时间复杂度为O(n)+O(nlogn)=O(nlogn).

实现代码为:

static void swap(int arr[],int m,int n)
{
  int team=arr[m];
  arr[m]=arr[n];
  arr[n]=team;
}
//下移交换 把当前节点有效变换成一个堆(小根)
static void shiftDown(int arr[],int index,int len)//0 号位置不用
{
  int leftchild=index*2+1;//左孩子
  int rightchild=index*2+2;//右孩子
  if(leftchild>=len)
    return;
  else if(rightchild<len&&arr[rightchild]<arr[index]&&arr[rightchild]<arr[leftchild])//右孩子在范围内并且应该交换
  {
    swap(arr, index, rightchild);//交换节点值
    shiftDown(arr, rightchild, len);//可能会对孩子节点的堆有影响,向下重构
  }
  else if(arr[leftchild]<arr[index])//交换左孩子
  {
    swap(arr, index, leftchild);
    shiftDown(arr, leftchild, len);
  }
}
//将数组创建成堆
static void creatHeap(int arr[])
{
  for(int i=arr.length/2;i>=0;i--)
  {
    shiftDown(arr, i,arr.length);
  }
}
static void heapSort(int arr[])
{
  System.out.println("原始数组为         :"+Arrays.toString(arr));
  int val[]=new int[arr.length]; //临时储存结果
  //step1建堆
  creatHeap(arr);
  System.out.println("建堆后的序列为  :"+Arrays.toString(arr));
  //step2 进行n次取值建堆,每次取堆顶元素放到val数组中,最终结果即为一个递增排序的序列
  for(int i=0;i<arr.length;i++)
  {
    val[i]=arr[0];//将堆顶放入结果中
    arr[0]=arr[arr.length-1-i];//删除堆顶元素,将末尾元素放到堆顶
    shiftDown(arr, 0, arr.length-i);//将这个堆调整为合法的小根堆,注意(逻辑上的)长度有变化
  }
  //数值克隆复制
  for(int i=0;i<arr.length;i++)
  {
    arr[i]=val[i];
  }
  System.out.println("堆排序后的序列为:"+Arrays.toString(arr));

}

归并类排序

在归并类排序一般只讲归并排序,但是归并排序也分二路归并、多路归并,这里就讲较多的二路归并排序,且用递归方式实现。

归并排序

归并和快排都是基于分治算法的,分治算法其实应用挺多的,很多分治会用到递归,但事实上分治和递归是两把事。分治就是分而治之,可以采用递归实现,也可以自己遍历实现非递归方式。而归并排序就是先将问题分解成代价较小的子问题,子问题再采取代价较小的合并方式完成一个排序。

至于归并的思想是这样的:

  • 第一次:整串先进行划分成一个一个单独,第一次是将序列中(1 2 3 4 5 6---)两两归并成有序,归并完(xx xx xx xx----)这样局部有序的序列。
  • 第二次就是两两归并成若干四个(1 2 3 4 5 6 7 8 ----)每个小局部是有序的
  • 就这样一直到最后这个串串只剩一个,然而这个耗费的总次数logn。每次操作的时间复杂的又是O(n)。所以总共的时间复杂度为O(nlogn).

image-20201120173153449

合并为一个O(n)的过程:

image-20201120174526108

实现代码为:

private static void mergesort(int[] array, int left, int right) {
  int mid=(left+right)/2;
  if(left<right)
  {
    mergesort(array, left, mid);
    mergesort(array, mid+1, right);
    merge(array, left,mid, right);
  }
}

private static void merge(int[] array, int l, int mid, int r) {
  int lindex=l;int rindex=mid+1;
  int team[]=new int[r-l+1];
  int teamindex=0;
  while (lindex<=mid&&rindex<=r) {//先左右比较合并
    if(array[lindex]<=array[rindex])
    {
      team[teamindex++]=array[lindex++];
    }
    else {				
      team[teamindex++]=array[rindex++];
    }
  }
  while(lindex<=mid)//当一个越界后剩余按序列添加即可
  {
    team[teamindex++]=array[lindex++];

  }
  while(rindex<=r)
  {
    team[teamindex++]=array[rindex++];
  }	
  for(int i=0;i<teamindex;i++)
  {
    array[l+i]=team[i];
  }

}

桶类排序

桶排序

桶排序是一种用空间换取时间的排序,桶排序重要的是它的思想,而不是具体实现,时间复杂度最好可能是线性O(n),桶排序不是基于比较的排序而是一种分配式的。桶排序从字面的意思上看:

  • 桶:若干个桶,说明此类排序将数据放入若干个桶中。
  • 桶:每个桶有容量,桶是有一定容积的容器,所以每个桶中可能有多个元素。
  • 桶:从整体来看,整个排序更希望桶能够更匀称,即既不溢出(太多)又不太少。

桶排序的思想为:将待排序的序列分到若干个桶中,每个桶内的元素再进行个别排序。 当然桶排序选择的方案跟具体的数据有关系,桶排序是一个比较广泛的概念,并且计数排序是一种特殊的桶排序,基数排序也是建立在桶排序的基础上。在数据分布均匀且每个桶元素趋近一个时间复杂度能达到O(n),但是如果数据范围较大且相对集中就不太适合使用桶排序。

image-20201120180500488

实现一个简单桶排序:

import java.util.ArrayList;
import java.util.List;
//微信公众号:bigsai
public class bucketSort {
	public static void main(String[] args) {
		int a[]= {1,8,7,44,42,46,38,34,33,17,15,16,27,28,24};
		List[] buckets=new ArrayList[5];
		for(int i=0;i<buckets.length;i++)//初始化
		{
			buckets[i]=new ArrayList<Integer>();
		}
		for(int i=0;i<a.length;i++)//将待排序序列放入对应桶中
		{
			int index=a[i]/10;//对应的桶号
			buckets[index].add(a[i]);
		}
		for(int i=0;i<buckets.length;i++)//每个桶内进行排序(使用系统自带快排)
		{
			buckets[i].sort(null);
			for(int j=0;j<buckets[i].size();j++)//顺便打印输出
			{
				System.out.print(buckets[i].get(j)+" ");
			}
		}	
	}
}

计数排序

计数排序是一种特殊的桶排序,每个桶的大小为1,每个桶不在用List表示,而通常用一个值用来计数。

设计具体算法的时候,先找到最小值min,再找最大值max。然后创建这个区间大小的数组,从min的位置开始计数,这样就可以最大程度的压缩空间,提高空间的使用效率。

在这里插入图片描述

public static void countSort(int a[])
{
  int min=Integer.MAX_VALUE;int max=Integer.MIN_VALUE;
  for(int i=0;i<a.length;i++)//找到max和min
  {
    if(a[i]<min) 
      min=a[i];
    if(a[i]>max)
      max=a[i];
  }
  int count[]=new int[max-min+1];//对元素进行计数
  for(int i=0;i<a.length;i++)
  {
    count[a[i]-min]++;
  }
  //排序取值
  int index=0;
  for(int i=0;i<count.length;i++)
  {
    while (count[i]-->0) {
      a[index++]=i+min;//有min才是真正值
    }
  }
}

基数排序

基数排序是一种很容易理解但是比较难实现(优化)的算法。基数排序也称为卡片排序,基数排序的原理就是多次利用计数排序(计数排序是一种特殊的桶排序),但是和前面的普通桶排序和计数排序有所区别的是,基数排序并不是将一个整体分配到一个桶中,而是将自身拆分成一个个组成的元素,每个元素分别顺序分配放入桶中、顺序收集,当从前往后或者从后往前每个位置都进行过这样顺序的分配、收集后,就获得了一个有序的数列。

image-20201113154119682

如果是数字类型排序,那么这个桶只需要装0-9大小的数字,但是如果是字符类型,那么就需要注意ASCII的范围。

所以遇到这种情况我们基数排序思想很简单,就拿 934,241,3366,4399这几个数字进行基数排序的一趟过程来看,第一次会根据各位进行分配、收集:

image-20201113161050871

分配和收集都是有序的,第二次会根据十位进行分配、收集,此次是在第一次个位分配、收集基础上进行的,所以所有数字单看个位十位是有序的。

image-20201113161752292

而第三次就是对百位进行分配收集,此次完成之后百位及其以下是有序的。

image-20201113162803486

而最后一次的时候进行处理的时候,千位有的数字需要补零,这次完毕后后千位及以后都有序,即整个序列排序完成。

image-20201113170715860

简单实现代码为:

static void radixSort(int[] arr)//int 类型 从右往左
{
  List<Integer>bucket[]=new ArrayList[10];
  for(int i=0;i<10;i++)
  {
    bucket[i]=new ArrayList<Integer>();
  }
  //找到最大值
  int max=0;//假设都是正数
  for(int i=0;i<arr.length;i++)
  {
    if(arr[i]>max)
      max=arr[i];
  }
  int divideNum=1;//1 10 100 100……用来求对应位的数字
  while (max>0) {//max 和num 控制
    for(int num:arr)
    {
      bucket[(num/divideNum)%10].add(num);//分配 将对应位置的数字放到对应bucket中
    }
    divideNum*=10;
    max/=10;
    int idx=0;
    //收集 重新捡起数据
    for(List<Integer>list:bucket)
    {
      for(int num:list)
      {
        arr[idx++]=num;
      }
      list.clear();//收集完需要清空留下次继续使用
    }
  }
}

当然,基数排序还有字符串等长、不等长、一维数组优化等各种实现需要需学习,具体可以参考公众号内其他文章。

结语

本次十大排序就这么潇洒的过了一遍,我想大家都应该有所领悟了吧!对于算法总结,避免不必要的劳动力,我分享这个表格给大家:

排序算法平均时间复杂度最好最坏空间复杂度稳定性
冒泡排序O(n^2)O(n)O(n^2)O(1)稳定
快速排序O(nlogn)O(nlogn)O(n^2)O(logn)不稳定
插入排序O(n^2)O(n)O(n^2)O(1)稳定
希尔排序O(n^1.3)O(n)O(nlog2n)O(1)不稳定
选择排序O(n^2)O(n^2)O(n^2)O(1)不稳定
堆排序O(nlogn)O(nlogn)O(nlogn)O(1)不稳定
归并排序O(nlogn)O(nlogn)O(nlogn)O(n)稳定
桶排序O(n+k)O(n+k)O(n+k)O(n+k)稳定
计数排序O(n+k)O(n+k)O(n+k)O(k)稳定
基数排序O(n*k)O(n*k)O(n*k)O(n+k)稳定

原创不易,bigsai请csdn的朋友们帮两件事帮忙一下:

  1. 点赞、在看、分享支持一下, 您的肯定是我创作的源源动力。

  2. 微信搜索「bigsai」,关注我的公众号,不仅免费送你电子书,我还会第一时间在公众号分享知识技术。加我还可拉你进力扣打卡群一起打卡LeetCode。

咱们下次再见!

image-20201114211553660

javaAPS高级排产系统
01-09
javaAPS高级排产系统
十种排序算法总结
一面之媛
08-07 395
排序方式 排序算法 稳定性 平均时间复杂度 空间复杂度 插入排序 直接插入排序 稳定 O(n2) O(1) 希尔排序 不稳定 O(nlogn) O(1) 选择排序 直接选择排序 不稳定 O(n2) O(1) 堆排序 不稳定 O(nlogn) O(1) 交换排序 冒泡排序 稳定 O(n2...
Oracle 中 row_number()、rank()、dense_rank() 函数的用法
lpf11214的博客
02-20 1万+
Oracle 中 row_number()、rank()、dense_rank() 函数的用法
数据结构算法———基数排序
热门推荐
05-30 1万+
数据结构算法介绍之基数排序(Radix Sort)
希尔排序时间复杂度_O(N)时间复杂度的排序算法!计数排序!
weixin_39595430的博客
11-27 1220
啥?你以为排序算法的时间复杂度最快也只能O(N*log(N))了?O(N) 时间复杂度的排序算法听说过没有?计数排序!!它是世界上最快最简单的算法!!!计数排序算法操作起来只有三步,看完秒懂!1. 根据待排序集合中最大元素和最小元素的差值范围确定申请的桶个数;2. 遍历待排序集合,将每一个元素统计到对应的桶中;(此步完成后每个桶里面的数字代表了此桶对应元素出现的次数。)3. 从小到大遍历一遍所有桶...
程序员必知的8大排序(值得一看)
09-14
程序员必知的8大排序(值得一看),用java实现 程序员必知的8大排序(值得一看),用java实现
程序员必知十大基础实用算法及其讲解
07-22
你知道程序员十大基础实用算法及其讲解吗?一起来看看
计算机基础知识学习笔记-程序员必知的硬核知识大全.pdf
06-24
计算机基础知识学习笔记-程序员必知的硬核知识大全
程序员面试必备】动画详解十大经典排序算法(内含代码)
04-13
排序算法程序员必备的基础知识,弄明白它们的原理和实现很有必要。本文中将通过非常细节的动画展示出算法的原理,配合代码更容易理解。 由于待排序的元素数量不同,使得排序过程中涉及的存储器不同,可将排序方法...
排序算法的原理解析和优劣对比
weixin_38933749的博客
09-29 810
什么是排序 排序,就是让一组无序数据变成有序的过程。 一般默认这里的有序都是从小到大的排列顺序。如何判断不同的排序算法的优劣呢? 衡量一个排序算法的优劣,我们主要会从以下 3 个角度进行分析: 时间复杂度,具体包括,最好时间复杂度、最坏时间复杂度以及平均时间复杂度。 空间复杂度,如果空间复杂度为 1,也叫作原地排序。 稳定性,排序的稳定性是指相等的数据对象,在排序之后,顺序是否能保证不变。 常见的排序算法及其思想 接下来,我们就开始详细地介绍一些经典的排序算法。 冒泡排序 冒泡排序的原理
C++ CArray类及子类,使用sort()排序
zhouworld16的专栏
02-21 4156
http://www.codeguru.com/forum/archive/index.php/t-215414.html这篇贴子帮了大忙。有一个回贴这样说到:#include ...// Note the *only* change is the template type!CArray MyCArray;//...std::sort( MyCArray.GetData(), MyCArray.GetData() + MyCArray.GetSize());It doesn't matter whethe
冒泡和快速排序的时间复杂度_快速排序过程、时间复杂度分析及改进
weixin_39588265的博客
11-22 611
前言之前介绍的插入排序与冒泡排序算法存在一个很明显的问题,就是基于比较和交换的排序策略,从根本上无法对平均时间复杂度进行优化,没有改进的余地和空间。但是如果我们摒弃插入排序与冒泡排序的思想,另辟蹊径是否能够提升排序效果呢?答案是肯定的。下面将介绍基于分治策略的两种排序算法,分别是快速排序算法和归并排序算法,并对其进行时间复杂度分析和改进。一、分治策略首先,我们先了解一下什么是分治策略。分治策略:如...
常用排序算法的时间复杂度和空间复杂度
weixin_49307896的博客
11-25 2707
常用的排序算法的时间复杂度和空间复杂度 排序法 最差时间分析 平均时间复杂度 稳定度 空间复杂度 冒泡排序 O(n2) O(n2) 稳定 O(1) 快速排序 O(n2) O(nlog2n) 不稳定 O(log2n)~O(n) 选择排序 O(n2)
a*算法的时间复杂度_最大时间复杂度为线性时间的中值查找算法
weixin_39861255的博客
11-23 174
分析的时候真是层出不穷的新算法啊,不过也是增长知识,这个Linear Time Median Finding算法用于寻找随机序列的中间值,其最坏的时间复杂度也只有 ,可以说是非常棒棒了。主要参考了My Favorite Algorithm: Linear Time Median Finding,文章比较了三种中间值查找算法,分别是:Sort Based MedianQuickselect wit...
C/C++ 常见数组排序算法
最新发布
CSDN
11-22 5040
本文介绍了几种常见的排序算法的实现,包括冒泡排序、选择排序、插入排序、希尔排序、归并排序和快速排序。冒泡排序通过多次遍历数组,比较并交换相邻元素,逐步将较小元素“浮”到数组顶端,时间复杂度为O(n^2)。选择排序通过选择未排序部分的最小元素进行交换,逐步完成整个数组排序,同样具有O(n^2)的时间复杂度。插入排序将数组分为已排序和未排序部分,逐个插入未排序元素到已排序部分的合适位置,时间复杂度为O(n^2)。希尔排序是插入排序的改进版本,通过分组插入排序,最终得到有序数组,时间复杂度在O(n log n)到
十种排序算法(附动态图和详细代码)
ProMonkey_C的博客
11-08 912
十种排序算法 一.算法分类 十种常见排序算法可以分为两大类: 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序。 线性时间非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此称为线性时间非比较类排序。 ...
各种排序算法详解集合(时间复杂度、空间复杂度、稳定性分析)
马小超
07-14 2105
动图来源:https://blog.csdn.net/weixin_41190227/article/details/86600821 一、冒泡排序 冒泡排序的名字是根据排序算法的特性得出的,每一个元素,像一个气泡,从最初的起始位置,一步步冒到最终位置。 冒泡每次交换相邻的两个元素,(假设是从小到大排序),每一轮冒泡,起码可以把最大的元素,从最初位置置换到最后位置,一路上还顺带着交换了一...
Python实现常见排序算法速度比较
sunbo_csdn的博客
08-31 7680
1.排序是计算机语言需要实现的基本算法之一,有序的数据结构会带来效率上的极大提升。 下面分类列举下常见排序算法: ①冒泡排序 冒泡排序的原理是对序列进行遍历,遍历过程中如果发现相邻两个元素,左边的元素大于右边,则进行交换,一次遍历之后最大的元素被移动到对尾,然后进行第二次遍历,直到队列有序。 #冒泡排序 def bubble_sort(list): l = len(list) ...
各种排序算法,时间复杂度On及比较#1
qq_73669431的博客
09-13 233
. . . . . (同理)logn即将数组n个元素分为单独数需要的步数,在归并过程中,需要对n个数一次遍历比较排序即n步,相乘即。(PS:优化后的冒泡排序为22403.00 ms,变化不大(doge))以{5,2,4,6,1,3}为例,利用Timer()函数得到数量级为。
程序员必知的硬核知识大全 pdf
07-05
### 回答1: 《程序员必知的硬核知识大全》是一本面向程序员的综合性知识手册,涵盖了各个领域的关键知识点,旨在帮助程序员提升技术水平和解决实际问题。该书以PDF格式出版,便于读者在电脑、手机等设备上随时查阅。 该书内容包括以下几个方面的硬核知识: 1. 编程语言知识:介绍了主流的编程语言,如Java、C++、Python等,包括语法、数据结构算法等方面的内容。 2. 操作系统和计算机原理:详细介绍了操作系统的基本原理和常见问题解决方法,以及计算机组成原理和计算机网络等相关知识。 3. 数据库和存储知识:讲解了数据库设计和管理的基本原理,介绍了关系型数据库如MySQL和非关系型数据库如MongoDB等的使用方法和优化技巧。 4. 网站和网络开发知识:包括Web开发的基本原理、前后端开发技术、网络安全和性能优化等方面的内容。 5. 软件工程和开发方法论:介绍了软件工程的基本概念和常用开发方法,包括敏捷开发、测试驱动开发和持续集成等。 6. 设计模式和架构知识:详细介绍了常用的设计模式和软件架构,帮助程序员设计可维护、可扩展和高效的软件系统。 除了以上几个方面的内容,该书还涵盖了其他与程序员工作密切相关的技术和知识,如版本控制、软件部署、性能调优等。《程序员必知的硬核知识大全》适合本科或者有一定编程经验的程序员阅读,对于提高技术实力和职业发展都有很大帮助。 ### 回答2: "程序员必知的硬核知识大全 pdf"是一份提供程序员必备知识的电子书,PDF格式可以方便地在各种设备上阅读。这本书包含了各个方面的硬核知识,帮助程序员提高技术能力和解决问题的能力。 这本电子书的内容包括了数据结构算法,编程语言,操作系统,网络通信,数据库管理等各方面的知识。对于程序员而言,这些都是非常重要的基础知识,能够帮助他们理解和设计高效的程序。 在数据结构算法部分,程序员将学习到各种基础的数据结构,如数组、链表、栈和队列,以及常见的算法,如排序和搜索算法。这些知识对于程序的效率和性能优化至关重要。 编程语言部分将介绍多种编程语言,如C、C++、Java和Python等。这些语言在不同的领域有各自的优点和适用范围,程序员需要了解它们的特点和使用方法,以便在开发项目时选择合适的语言。 操作系统部分将深入讲解操作系统的原理和设计。程序员将了解到进程管理、内存管理、文件系统等重要概念,这些对于编写具有高可靠性和高性能的程序至关重要。 网络通信部分将介绍计算机网络的基本原理和常见的协议,如TCP/IP和HTTP等。程序员需要理解网络通信的基础知识,以便与其他系统进行数据交换和通信。 数据库管理部分将详细介绍关系型数据库和非关系型数据库的原理和使用方法。程序员需要了解数据库的设计和优化,以提高数据的存储和检索效率。 总之,这本电子书涵盖了程序员必备的硬核知识,对于提高他们的技术能力和解决问题的能力非常有帮助。 ### 回答3: 《程序员必知的硬核知识大全》是一本汇集了程序员必备的核心知识的书籍,可以帮助程序员提升自己的技术水平。这本书涵盖了计算机科学的各个领域和重要概念,包括数据结构算法、操作系统、编程语言、网络通信、数据库、Web开发、软件工程等。 在数据结构算法部分,书中介绍了常用的数据结构如链表、栈、队列以及各种排序和搜索算法,帮助程序员理解和应用这些经典的算法。在操作系统方面,书中讲解了进程、线程、内存管理、文件系统等重要概念,帮助程序员深入了解计算机系统的工作原理。 在编程语言方面,书中列举了多种编程语言的特性和应用场景,如C++、Java、Python等,有助于程序员选择适合自己的编程语言并掌握其特性。在网络通信部分,书中介绍了TCP/IP协议、HTTP协议等重要的网络通信协议和技术,帮助程序员理解网络通信的基本原理。 此外,书中还介绍了数据库的相关知识,包括关系数据库、SQL语言、数据备份与恢复等内容,有助于程序员设计和管理数据库。在Web开发方面,书中介绍了前端开发、后端开发、服务器部署等关键技术,帮助程序员构建高效、安全的Web应用程序。 最后,在软件工程方面,书中讲解了软件开发的生命周期、需求分析、设计模式、测试和持续集成等内容,有助于程序员理解和掌握软件开发过程中的重要环节。 总的来说,这本《程序员必知的硬核知识大全》提供了一站式的学习资料,涵盖了程序员必备的核心知识,可以帮助程序员系统地学习和应用这些知识,提升自己的技术能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • 我花了一夜用数据结构给女朋友写个H5走迷宫游戏 463602
  • python3(requests)使用代理ip 121194
  • Uncaught ReferenceError错误详解(js函数参数使用错误) 84605
  • 第二弹!python爬虫批量下载高清大图 58346
  • Thymeleaf一篇就够了 55287

分类专栏

  • 数据结构与算法 付费 52篇
  • 文章精选 付费 5篇
  • 数据结构与算法(旧) 18篇
  • 精选 14篇
  • LeetCode 55篇
  • MongoDB 3篇
  • 剑指offer 8篇
  • 爬虫
  • python 爬虫 13篇
  • Java爬虫 8篇
  • web开发 1篇
  • Springboot 13篇
  • javaWeb 24篇
  • java EE 22篇
  • redis 4篇
  • shiro 2篇
  • ElasticSearch 3篇
  • 个人总结 37篇
  • 设计模式 1篇
  • python学习 7篇
  • java学习 12篇
  • 操作系统 5篇
  • bug 1篇
  • github 1篇
  • java数据结构 13篇
  • java swing GUI小程序 5篇
  • linux 5篇
  • 模板 7篇
  • 算法好题
  • 思维题 9篇
  • dp 14篇
  • bfs 10篇
  • dfs 8篇
  • Codeforces 5篇
  • 贪心 5篇
  • 数论 10篇
  • dijkstra 2篇
  • 并查集 5篇
  • 蓝桥杯 3篇
  • 组合博弈 1篇
  • 分冶 1篇
  • spfa 1篇
  • 二分 2篇
  • 母函数 2篇
  • 尺取法 3篇

最新评论

  • 蓝桥杯国一,非ACMer选手保姆级经验分享

    2401_83159388: 无脑洛谷,蓝桥杯一道题也不用刷,大一随便国一,明天又是国赛

  • 操作系统之多线程编程—读者优先/写者优先详解

    随꧔ꦿɞ缘࿐: 想问一下这个是不是没有用到信号量

  • (建议收藏)一文多图,彻底搞懂Floyd算法(多源最短路径)

    qq_57145752: 算法的本质不就是数学吗,只是换了表示方法

  • 耗时3年写了一本数据结构与算法pdf!开源了

    シ風箏: 内容放到GIT上避免丢失也是个很好的做法,感谢分享啊表情包

  • 蓝桥杯国一,非ACMer选手保姆级经验分享

    时雨h: 很好的建议

您愿意向朋友推荐“博客详情页”吗?

  • 强烈不推荐
  • 不推荐
  • 一般般
  • 推荐
  • 强烈推荐
提交

最新文章

  • 两年前埋得坑,现在直接炸裂
  • 耗时3年写了一本数据结构与算法pdf!开源了
  • 数据结构与算法—搞懂队列
2023年12篇
2022年9篇
2021年77篇
2020年89篇
2019年60篇
2018年112篇
2017年7篇

目录

目录

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员bigsai

喝杯咖啡压压惊!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或 充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

深圳SEO优化公司湘西模板推广哪家好聊城关键词按天扣费哪家好海口网站设计模板铜仁网站推广温州网站推广方案报价东营网站推广工具哪家好南阳外贸网站制作多少钱白山网站优化按天收费推荐重庆网站定制价格伊犁百度seo推荐山南关键词按天计费临夏seo排名报价岳阳营销型网站建设公司双龙seo排名唐山网站关键词优化报价莆田网站优化按天收费公司玉树百度标王多少钱喀什百姓网标王推广价格乌海网站seo优化公司巢湖网站推广推荐榆林设计公司网站价格甘孜seo排名多少钱平顶山SEO按天计费大理建设网站多少钱三明网站优化软件公司台州百姓网标王西安百姓网标王推广报价安顺阿里店铺托管推荐南平推广网站哪家好梅州企业网站改版公司歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化