插入排序与归并排序

前言:

  排序算法应该算是算法入门级的东西了,这里重新学习算法,先暂时归纳下个人对两种算法的理解。

插入排序:

  插入排序可以对应到现实生活中的排队去停车场停车的场景。假设某家饭店的饭菜十分好吃(流口水),导致来这里吃饭的人特别多,后面来吃饭准备停车的车排起了长队。每次只允许一辆车过去找位置,找到位置之后才允许下一辆车进入,依此类推,直到所有的车都停好。转换成专业的数学模型就是:现有一个无序数组 A[n],要想对其进行排序。我们先从一个数开始考虑,A0肯定是排好序的。现在假设有A1,那么这时候应该将A1和A0 进行比较排序。这时候假设再来A2,A2需要与前面排好队的A0、A1 再进行比较排序。这里需要注意的是在排序的过程中可能会产生数组的移动。下面是java代码实现的升序排列的整数版本:

 1 public static void main(String[] args) {
 2         int[] arr = {2, 1, 23, 22, 15, 76, 43, 36};
 3         ascInsertionSort(arr);
 4         System.out.println(Arrays.toString(arr));
 5     }
 6
 7     /**
 8      * 升序插入排列
 9      * @param arr 传入的数组
10      */
11     private static void ascInsertionSort(int[] arr) {
12         int key = 0;
13         for (int j=1; j<arr.length; j++) {                // 因为如果只有一个元素根本不需要排序,所以带插入的元素的下边从1开始
14             key = arr[j];                                // 用key表示当前用来插入到已排序数组中的值
15             int i = j-1;
16             for (; i>=0; i--)
17             {
18                 // 如果已排完序的数组的最后一个数比当前待插入的数小,说明不需要移动,直接break,否则需要交换两个比较值的元素的位置
19                 if (arr[i] > arr[i+1])
20                 {
21                     arr[i+1] = arr[i];
22                     arr[i] = key;
23                 }
24                 else
25                 {
26                     break;
27                 }
28             }
29         }
30     }

AscInsertionSort

很容易算出该算法的耗时主要是两层for循环嵌套导致的,第一层for循环循环的次数为n次。第二层for循环每次运行的最坏的结果是需要把前面排序好的数组再全部循环一次,为:

1 + 2 + 3 + ... + (n-1) = (n2-1)/2。 我们知道对于n的多项式,随着n的增长,对多项式结果影响结果最大的其实是最高的次数的那个项。所以不难得到该算法的时间复杂度为:θ(n2)。

选择排序:

  既然讲了插入排序,顺便讲讲选择排序。选择排序简而言之就是每次选最帅的,选到最不帅的终结排序。

  java实现的代码如下:

 1 /**
 2      * 升序选择排序
 3      *
 4      * @param arr
 5      */
 6     private static void ascSelectionSort(int[] arr) {
 7         int min;
 8         int minIndex;
 9         for (int i = 0; i < arr.length - 1; i++) {
10             min = arr[i]; // 假设最小的元素是当前就在该位置的元素
11             minIndex = i;
12             for (int j = i + 1; j < arr.length; j++) {
13                 if (arr[j] < min) // 如果有元素比最小的元素小,则将该元素的值作为最小元素的值,依次查找下去,最终找到最小元素所在的下表
14                 {
15                     min = arr[j];
16                     minIndex = j;
17                 }
18             }
19
20             // 循环完发现最小元素的位置不是当前在该位置的元素,则交换两个元素的位置
21             if (minIndex != i) {
22                 int temp = arr[i];
23                 arr[i] = arr[minIndex];
24                 arr[minIndex] = temp;
25             }
26         }
27     }

ascSelectionSort

  可以发现一个很悲伤的事实,这个算法的时间复杂度也为:θ(n2)。

归并排序:

  归并排序的思路应该是源自于递归。也就是大事化小,小事化了。既然是个大的数组,我就先分成两个。两个数组还是有点大吧,那我再每个分成两个。依此下去直到最后没一组中只剩下一个元素,这时候排序应该是很简单的事了。而每两个小组排序完了之后组成大组,由于每个大组都是排序好的,这时候合并大组就简单多了。用伪公式表示为:一个大组排序的时间 = 两个小组分别排序的时间 +  两个小组合并的时间。合并的原理也很简单,就相当于两份扑克牌,正着放的,从上到下是从小到大的顺序。首先从两份扑克中各取出一个牌,将较小的那个牌倒着放到另外个地方。再从较小的扑克牌出现的那份牌里面拿出最上面的,与刚才剩下的牌比大小,同样的道理,小的牌继续倒着放到刚刚选出来的那个牌的上面。依次类推,直到有一份牌被拿完。最后将剩下的那份牌倒过来倒着放到选出的牌堆上面,就完成了排序。

  java实现的代码如下:

 1 /**
 2      * 升序归并排列
 3      *
 4      * @param arr
 5      */
 6     private static void ascMergeSort(int[] arr) {
 7         int startIndex = 0;
 8         int endIndex = arr.length - 1;
 9         divideConquer(arr, startIndex, endIndex);
10
11     }
12
13     private static void divideConquer(int[] arr, int startIndex, int endIndex) {
14         int midIndex = (startIndex + endIndex) / 2;
15         if (midIndex > startIndex) {
16             divideConquer(arr, startIndex, midIndex); // 排序前一部分
17             divideConquer(arr, midIndex + 1, endIndex); // 排序后一部分
18         }
19         mergeSortedArr(arr, startIndex, midIndex, endIndex); // 合并排序后的两个数组
20     }
21
22     private static void mergeSortedArr(int[] arr, int startIndex, int midIndex,
23             int endIndex) {
24         int[] newArr = new int[endIndex + 1];
25         int i = startIndex;
26         int j = midIndex + 1;
27         int k = startIndex;
28         while (i <= midIndex && j <= endIndex) {
29             // 将小的放入当前位置,并且下一个比较大小的从出现小的那一组更新
30             if (arr[i] < arr[j]) {
31                 newArr[k++] = arr[i++];
32             } else {
33                 newArr[k++] = arr[j++];
34             }
35         }
36
37         // 需要将还剩牌的那一组元素加到排序好的数组后面
38         while (i <= midIndex) {
39             newArr[k++] = arr[i++];
40         }
41         while (j <= endIndex) {
42             newArr[k++] = arr[j++];
43         }
44
45         // 将新数组的值复制到老数组
46         for (i = startIndex; i <= endIndex; i++) {
47             arr[i] = newArr[i];
48         }
49     }

ascMergeSort

该算法具体到每一层的时间是n的一定倍数,然后从最顶层到最下面一层可分的层次为logn.所以该算法的时间复杂度为: θ(nlogn).

冒泡排序:

  因为冒泡排序不是今天的主角,所以这里不再将其代码贴出来。只是说说冒泡排序的原理:其实和选择排序有些类似,也是最小的或者最大的冒出来,不同之处在于在冒泡的过程中会发生置换,每次比较只要比较相邻的两个数即可。其时间复杂度其实和选择排序一样,这里直接跳过。

OK!算法入门之简单的排序算法到此完结!

时间: 2024-10-11 05:58:04

插入排序与归并排序的相关文章

疯狂的Java算法——插入排序,归并排序以及并行归并排序

从古至今的难题 在IT届有一道百算不厌其烦的题,俗称排序.不管是你参加BAT等高端笔试,亦或是藏匿于街头小巷的草根笔试,都会经常见到这样一道百年难得一解的问题. 今天LZ有幸与各位分享一下算法届的草根明星,排序届的领衔大神——插入排序以及归并排序.最后,在头脑风暴下,LZ又有幸认识了一位新朋友,名叫并行归并排序.接下来,咱们就一一认识一下,并且在最后来一次“算林大会”吧. 插入排序简介 插入排序,算林称最亲民的排序算法,插入排序采用最简单的插入方式对一个整数数组进行排序.它循环数组中从第二个开始

插入排序和归并排序的实现代码(C++)

插入排序和归并排序是算法导论先讲到的两中排序方法. 插入排序的思路是对于一个已经排好序的数组,现在新插入一个元素并且保持其有序.那么该如何插入呢,从数组最后一个元素开始进行比较,直到遇到比小于等于自己的元素,然后插入到该元素的后面(所以插入是稳定的).循环不变式:子数组一直保持有序(使用循环不变式来证明算法正确性的方法类似于高中经常用的数学归纳法). 归并排序的思想就是很有名的分治思想(divide and conquer).从较小的多个有序数组得到较大的有序数组即合并,归并排序采用二路归并.多

插入排序与归并排序的C#实现

算法导论在介绍算法时列举了插入排序与并归排序,以此来说明什么事算法,算法效率以及提出了算法设计中重要的思想--分治,也就是将问题划分为规模较小的子问题.这种思想在大规模运算时具有显著的时间开销优势,例如插入排序和并归排序,其时间开销大致分别等于C1N2和C2Nlog2N. 下面介绍具体的代码: 首先是插入排序: 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text;

基本排序算法(冒泡排序 选择排序 插入排序 快速排序 归并排序 基数排序 希尔排序)

冒泡排序 public static void bubbleSort(int[] arr){ int lgn = arr.length; for (int i = 0; i < lgn - 1; i++) { for (int j = 0; j < lgn - 1 - i; j++) { if(arr[j] > arr[j + 1]){ int temp = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = temp; } } } } 选择排序 publ

插入排序和归并排序

//插入排序 //C++ #include <iostream> using namespace std; void main() { int a[6]={5,2,4,6,1,3};//定义一个未排好序的数组 int i,j,key; for(i=0;i<6;i++)//输出排序前的序列 printf("%3d",a[i]); for(j=1;j<6;j++) { key=a[j]; i=j-1; while(i>=0&&a[i]>k

冒泡排序,插入排序,归并排序,快速排序的学习笔记

这几个很基础的排序非常有用,我重新整理了下代码 1 #include<iostream> 2 #include<algorithm> 3 4 using namespace std; 5 6 void Bouble_Sort(int * Arry,int Lenth) //冒泡排序 7 { 8 int i,k; 9 10 int flag = 0; 11 12 for(i = Lenth - 1;i >= 0; i--) 13 { 14 for(k=0;k<i;k++)

算法导论笔记1 - 插入排序 vs 归并排序

import random import time __author__ = 'Administrator' LENGTH = 3000 base = [] for i in range(0, LENGTH): base.append(random.randint(0, LENGTH)) def ins_sort(array): for border in range(1, len(array)): j = border - 1 key = array[border] while j >= 0

算法导论之插入排序和归并排序

一.创建我们的测试工程 因为我们只理解相应算法,没有什么用户图形,也就用不到UI了,在这儿使用Xcode创建一个基于Mac开发的控制台工程即可,整个工程很简单,一个main函数一个排序类,如下所示. 在Sort类中我们写了关于排序的一些类方法,然后在main函数中进行调用. 二.插入排序 插入排序顾名思义,就是把无序的元素插入到有序的元素当中.<算法导论>中举了一个特为形象的例子,插入排序就如同你在打扑克时摸牌一样,手里的牌是有序的,而你刚摸得牌是是随机的,需要你插入到已经排好序的扑克牌中,这

算法导论-排序-插入排序、归并排序

目录: 1.插入排序算法伪码 2.插入排序c++实现 3.归并排序算法伪码 4.归并排序c++实现 5.总测试程序 内容: 1.插入排序算法伪码 Insertion_sort(A[],n) //数组下标从1开始 for j <- 2 to n do key <- A[j] i <- j-1 while i>0 and A[i]>key A[i+1] <- A[i] i <- i-1 A[i+1]=key 2.插入排序c++实现 1 template<type