常用的排序算法

Posted mgd666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了常用的排序算法相关的知识,希望对你有一定的参考价值。

排序算法

这篇博文主要讲解一下主流的几大排序算法

选择排序

  • 思路

选择排序应该是这么多排序算法中最简单的一种排序算法了,主要思路是找到数组中最小的元素,其次,将它和数组的第一个元素交换位置(如果第一个元素就是最小的元素就和自己交换)。再次,在剩下的元素中重复此行为。

  • 时间复杂度:O(n^2)

  • 特点

  1. 选择排序的运行时间和输入无关
  2. 数据移动的次数最少(N次)
  3. 数组的左边始终保持有序
  4. 不稳定
  • 代码
void selectSort(vector<int>& arr) {
  for (int i = 0;i < arr.size() - 1; i++) {
			int t = i;
    	for (int j = i+1;j < arr.size(); j++) {
        //遍历数组,找到最小的一个
      	if (a[t] > a[j]) {
        	t = j;
      	}
    	}
    	if (t != i) {
        int tmp = a[i];
        a[i] = a[t];
        a[t] = tmp;
      }
  	}
	}

插入排序

  • 思路

插入排序类似我们打扑克时整理牌时的操作,我们一个一个元素的来处理,每次将要插入的元素插入到其他已有顺序的数组中(数组的右边)

  • 时间复杂度 O(n^2)
  • 特点
  1. 数组中每个元素距离它的最终距离都不远,一个有序的大数组接一个小数组,数组中只有几个数字的位置不正确,此时用插入排序是很快的
  2. 稳定的
  3. 数组的右边是有序的
  • 代码
void insertSort(vector<int>& arr) {
  	//控制循环次数,假设第一个元素是有序的
  	for (int i = 1;i < arr.size(); i++) {
      	//待排序的第一个元素
      	int t = a[i];
      	//代表已经排序过的元素最后一个索引数
      	int j = i - 1;
      	//从后向前逐个比较已经排序过数组,如果比它小,则把后者用前者代替,数组逐个后移一个,为找到合适的位置时便与插入t
      	while (j >= 0 && t < a[j]) {
          	a[j+1] = a[j];
          	j--;
        }
      	//找到了合适的位置,赋值
      	a[j+1] = t;
    }
}

希尔排序

  • 思路

希尔排序是基于插入排序的快速的排序算法,希尔排序是将待排序的数组元素 按下标的一定增量分组 ,分成多个子序列,然后对各个子序列进行直接插入排序算法排序;然后依次缩减增量再进行排序,直到增量为1时,进行最后一次直接插入排序,排序结束。

希尔排序就是分组?插入排序,分组每次都减半

  • 时间复杂度 O(nlog2n)

  • 特点

  1. 非稳定的排序
  2. 希尔排序的执行时间依赖于增量序列
  • 代码
void shellSort(vector<int>& arr) {
  	int i,j,gap;
  	//以数组的长度的一半来分组,每次分组缩小一半
  	for (gap = arr.size()/2; gap > 0; gap /= 2) {
      	//插入排序
      	for (i = 0;i < gap; i++) {
          	for (j = i + gap;j < arr.size(); j+= gap) {
              	if (a[j] < a[j - gap]) {
                  	int tmp = a[j];
                  	int k = j - gap;
                  	while (k >= 0 && a[k] > tmp) {
											a[k + gap] = a[k];
                      k -= gap;
                    }
                  	a[k+gap] = tmp;
                }
            }
        }
    }
}
  • 改进版代码
void shellsort2(int a[], int n)
{
    int j, gap;

    for (gap = n / 2; gap > 0; gap /= 2)
        for (j = gap; j < n; j++)//从数组第gap个元素开始
            if (a[j] < a[j - gap])//每个元素与自己组内的数据进行直接插入排序
            {
                int temp = a[j];
                int k = j - gap;
                while (k >= 0 && a[k] > temp)
                {
                    a[k + gap] = a[k];
                    k -= gap;
                }
                a[k + gap] = temp;
            }
}

归并排序

  • 思路

归并排序,可以先递归的将数组分割直到最小单位,然后合并成一个大数组,在这个过程中进行排序

以数组中心来划分,mid = (l + r) / 2,分成两半的数组分别从头开始进行比较,利用双指针,哪个数小就把它放进答案数组中,再将该指针移动一位,继续比较。

  • 时间复杂度 O(nlogn)
  • 特点
  1. 归并排序是稳定的
  • 代码
void mergeSort(int q[],int l,int r) {
  if (l >= r) return;
  int mid = l + r >> 1;
  mergeSort(q,l,mid);
  mergeSort(q,mid+1,r);
  int k = 0,i = l,j = mid + 1;
  while (i <= mid && j <= r) {
    if (q[i] < q[j]) tmp[k++] = q[i++];
    else tmp[k++] = q[j++];
  }
  while (i <= mid) tmp[k++] = q[i++];
  while (j <= r) tmp[k++] = q[j++];
  
  for (i = l,j = 0;i <= r;i++,j++) q[i] = tmp[j                                          ];
}

快速排序

  • 思路

快速排序是本人最喜欢的排序算法,它将一个数组分成两个子数组,将两部分独立的排序

首先确定分界点x,个人喜欢中点,不用考虑啥越界问题,然后递归处理左右两段,接着利用左右双指针算法,左边i指针先走,只要这个数小于x,i指针就一直往后走,然后移动j指针,当j指针指向的数字大于x,就一直往前走,如果两个指针没有相遇,就交换

  • 时间复杂度 O(n^2) (不一定)

  • 特点

  1. 快排是不稳定的
  2. 快排一般来说很快,而且都是一个套路
  • 代码
void quickSort(int q[],int l,int r) {
  if (l >= r) return;
  int i = l-1,j = r+1,x = q[l + r >> 1];
  while (i < j) {
    while(q[++i] < x);
    while(q[--j] > x);
    if (i < j) {
      int tmp = a[i];
      a[i] = a[j];
      a[j] = tmp;
    }
  }
  quickSort(q,l,j),quickSort(q,j+1,r);
}
  • 三路快排

思路:处理数组中有大量重复数据 ,此时可以用三路快排,< x,== x, > x 来进行快排

代码

void quickSort(int q[],int l,int r) {
  if (l >= r) return;
  int key = q[l];
  int i = l,j = l+1,k = r;
  while (i <= k) {
    if (a[i] < key) swap(a[i++],a[j++]);
    else if (a[i] > key) swap(a[i],a[k--]);
    else i++;
  }
  quickSort(q,l,j - 1);
  quickSort(q,j,r);
}

冒泡排序

  • 思路

不出意外,冒泡排序是大部分接触编程的人第一个学会的排序算法,因为它很简单。比较相邻的元素。如果第一个比第二个大,就交换他们两个,一直重复到倒数第二个元素。

  • 时间复杂度 O(n^2)
  • 特点
  1. 冒泡排序很简单
  2. 冒泡排序是稳定的
  • 代码
void bubbleSort(int q[],int len) {
  for (int i = 0;i < len-1; i++) {
    for (int j = 0;j < len - 1; j++) {
			if (q[i] > q[j+1]) {
        int tmp = q[i];
        q[i] = q[j+1];
        q[j+1] = tmp;
      }
    }
  }
}

以上是关于常用的排序算法的主要内容,如果未能解决你的问题,请参考以下文章

Java常用的八种排序算法与代码实现

常用排序算法

Java常用的八种排序算法与代码实现

常用排序算法比较

集中常用排序算法代码

常用算法的简洁代码实现之快速排序归并排序