常见算法简介

  • 文章参考于
  1. 面试常问的十个排序算法都在这里了(含JAVA代码实现)
  2. 视频 | 手撕九大经典排序算法,看我就够了!

0. 排序算法说明

  • 排序的定义:按关键字非递减非递增顺序对一组记录进行排列的操作。

  • 术语说明:

    • 稳定:a == b;排序前 a 在 b 前面,排序之后 a 仍在 b 前面
    • 不稳定:a == b;排序之前 a 在 b 之前,排序之后 a 可能 在 b 后面
    • 内排序:所有排序操作都在内存中完成
    • 外排序:大文件的排序,待排序的文件无法一次装入内存,需要在内存和外部存储器之间进行多次数据交换,以达到排序整个文件的目的。
    • 时间复杂度:一个算法执行所耗费的时间。
    • 空间复杂度:运行完一个程序所需内存的大小
  • 排序算法复杂度总结

  • 图片名词解释:

    • n:数据规模
    • k:“桶”的个数
    • In-place:占用常数内存,不占用额外内存
    • Out-place:占用额外内存

在这里插入图片描述

1. 冒泡排序(Bubble Sort)

  • 工作原理:每次比较相邻的元素,按照要求进行交换(比如 升序排列,吧较大的元素放在后面),循环n次(n为总元素个数)。这样小的元素就会不断的“冒泡”到前面来。

  • 动图演示

    在这里插入图片描述

  • java代码

    public static int[] bubbleSort(int[] nums) {
           if (nums == null || nums.length == 0){
      		return nums;
      	}
      	for (int i = 0; i < nums.length - 1; i++) {
      		for(int j = i + 1; j < nums.length; j++ ){
      			int temp = 0;
      			if(nums[i] > nums[j]){
      				temp = nums[i];
      				nums[i] = nums[j];
      				nums[j] = temp;
      			}
      		}
      	}
      	return nums;
      }
    
  • 算法分析

    • 时间复杂度:T(n) = O(n2)

2. 选择排序(Selection Sort)

  • 工作原理:首先在未排序的序列中找到最小(大)的元素,存放到排序序列的起始位置,然后再从未排序元素中继续寻找最小(大)的元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。(表现最稳定(此稳定非彼稳定)的排序算法之一,因为无论什么数据进去都是O(n^2)的时间复杂度,所以用他的时候,数据规模越小越好)

  • 动图演示

    在这里插入图片描述

  • java代码

    public static int[] selectionSort(int[] array) {
           if (array.length == 0)
               return array;
           for (int i = 0; i < array.length; i++) {
               int minIndex = i;
               for (int j = i; j < array.length; j++) {
                   if (array[j] < array[minIndex]) //找到最小的数
                       minIndex = j; //将最小数的索引保存
               }
               int temp = array[minIndex];
               array[minIndex] = array[i];
               array[i] = temp;
           }
           return array;
    
  • 时间复杂度:T(o) = O(n2)

3. 插入排序(Insertion Sort)

  • 工作原理:每次选择一个元素,跟序列中的所有元素比较,插入到合适的位置。

  • 动图演示

    在这里插入图片描述

  • java代码

    public static int[] insertionSort(int[] array) {
           if (array.length == 0)
               return array;
           int current;
           for (int i = 0; i < array.length - 1; i++) {
               current = array[i + 1];
               int preIndex = i;
               while (preIndex >= 0 && current < array[preIndex]) {
                   array[preIndex + 1] = array[preIndex];
                   preIndex--;
               }
               array[preIndex + 1] = current;
           }
           return array;
       }
    
  • 时间复杂度:T(n) = O(n2)

4. 希尔排序(Shell Sort)

  • 工作原理:实质上是采用分组插入的方法。先将整个待排序记录序列分割成几组,从而减少参与直接排序的数据量,对每组分别进行直接插入排序,然后增加每组的数据量,重新分组。经过几次这样的分组,当序列基本有序时,再对全体数据进行一次直接插入排序。

  • 特点:当待排序序列个数较少 且 待排序序列基本有序时,效率较高。

  • 动图演示
    在这里插入图片描述

  • 过程演示
    在这里插入图片描述

  • java代码

    public static int[] ShellSort(int[] array) {
           int len = array.length;
           int temp, gap = len / 2;
           while (gap > 0) {
               for (int i = gap; i < len; i++) {
                   temp = array[i];
                   int preIndex = i - gap;
                   while (preIndex >= 0 && array[preIndex] > temp) {
                       array[preIndex + gap] = array[preIndex];
                       preIndex -= gap;
                   }
                   array[preIndex + gap] = temp;
               }
               gap /= 2;
           }
           return array;
       }
    
  • 时间复杂度:T(n) = O(nlog2n)

5. 归并排序(Merge Sort)

  • 工作原理:将两个或两个以上的有序表合为一个有序表的过程

    二路归并:将n个元素的序列,两两归并,得到 n/ 2(向上取整)个长度为2或1的有序子序列;再两两归并…如此之重复,直至得到一个长度为n的有序序列为止。

  • 动图演示:

在这里插入图片描述

  • java代码

       /*
        * 归并排序
        */
    public static int[] MergeSort(int[] array) {
           if (array.length < 2) return array;
           int mid = array.length / 2;
           int[] left = Arrays.copyOfRange(array, 0, mid);
           int[] right = Arrays.copyOfRange(array, mid, array.length);
           return merge(MergeSort(left), MergeSort(right));
       }
       /*
        * 归并排序——将两段排序好的数组结合成一个排序数组
        */
       public static int[] merge(int[] left, int[] right) {
           int[] result = new int[left.length + right.length];
           for (int index = 0, i = 0, j = 0; index < result.length; index++) {
               if (i >= left.length)
                   result[index] = right[j++];
               else if (j >= right.length)
                   result[index] = left[i++];
               else if (left[i] > right[j])
                   result[index] = right[j++];
               else
                   result[index] = left[i++];
           }
           return result;
       }
    
  • 时间复杂度:T(n) = O(nlogn)

6. 快速排序(Quick Sort)

  • 工作原理:首先任意选取一个数据(通常选取数组的第一个数)作为关键数据。然后将所有比它小的都放到它前面,把比它大的都放到它后面。

    • 一趟快排的算法:

      1. 设置两个变量i,j。i= 0;j = len - 1.
      2. 以第一个数组元素作为关键数据,赋值给key,即 key - arr[0];
      3. 从j开始搜索(从后向前搜索,j- -),找到第一个小于 key 的值 arr[j],将arr[j]arr[i] 的值交换
      4. 从i开始(从前往后搜索,i++),找到第一个大于keyarr[i],将 arr[i] 和 arr[j] 的值交换;
      5. 重复3 4 步,知道 i== j;
  • 动图演示

    在这里插入图片描述

  • java代码

       /**
        * 快速排序方法
        */
       public static int[] QuickSort(int[] array, int start, int end) {
           if (array.length < 1 || start < 0 || end >= array.length || start > end) return null;
           int smallIndex = partition(array, start, end);
           if (smallIndex > start)
               QuickSort(array, start, smallIndex - 1);
           if (smallIndex < end)
               QuickSort(array, smallIndex + 1, end);
           return array;
       }
       /*
        * 快速排序算法——partition
        */
       public static int partition(int[] array, int start, int end) {
           int pivot = (int) (start + Math.random() * (end - start + 1));
           int smallIndex = start - 1;
           swap(array, pivot, end);
           for (int i = start; i <= end; i++)
               if (array[i] <= array[end]) {
                   smallIndex++;
                   if (i > smallIndex)
                       swap(array, i, smallIndex);
               }
           return smallIndex;
       }
    
       /**
        * 交换数组内两个元素
        */
       public static void swap(int[] array, int i, int j) {
           int temp = array[i];
           array[i] = array[j];
           array[j] = temp;
       }
    
  • 时间复杂度:T(n) = O(nlogn)

7. 堆排序(Heap Sort)

  • 工作原理:在排序过程中,将待排序的序列看成一棵完全二叉树的顺序储存结构,利用完全二叉树中双亲结点和孩子结点之间的关系(子节点的值大于或者小于父节点的值),在当前无序序列中选择关键字最大(最小)的记录。

  • 动图演示

  • 在这里插入图片描述

  • java 代码

    //声明全局变量,用于记录数组array的长度;
    static int len;
       /**
        * 堆排序算法
        *
        * @param array
        * @return
        */
       public static int[] HeapSort(int[] array) {
           len = array.length;
           if (len < 1) return array;
           //1.构建一个最大堆
           buildMaxHeap(array);
           //2.循环将堆首位(最大值)与末位交换,然后在重新调整最大堆
           while (len > 0) {
               swap(array, 0, len - 1);
               len--;
               adjustHeap(array, 0);
           }
           return array;
       }
       /**
        * 建立最大堆
        *
        * @param array
        */
       public static void buildMaxHeap(int[] array) {
           //从最后一个非叶子节点开始向上构造最大堆
           for (int i = (len - 1) / 2; i >= 0; i--) {
               adjustHeap(array, i);
           }
       }
       /**
        * 调整使之成为最大堆
        *
        * @param array
        * @param i
        */
       public static void adjustHeap(int[] array, int i) {
           int maxIndex = i;
           //如果有左子树,且左子树大于父节点,则将最大指针指向左子树
           if (i * 2 < len && array[i * 2] > array[maxIndex])
               maxIndex = i * 2;
           //如果有右子树,且右子树大于父节点,则将最大指针指向右子树
           if (i * 2 + 1 < len && array[i * 2 + 1] > array[maxIndex])
               maxIndex = i * 2 + 1;
           //如果父节点不是最大值,则将父节点与最大值交换,并且递归调整与父节点交换的位置。
           if (maxIndex != i) {
               swap(array, maxIndex, i);
               adjustHeap(array, maxIndex);
           }
       }
    
  • 时间复杂度:T(n) = O(nlogn)

8. 总结

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值