排序的整理

排序的相关概念:

什么是排序,排序的稳定性,内部排序与外部排序 ?

排序:就是使一串记录,照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。(即排序过程前后不改变两个相同元素的相对位置)
内部排序:数据元素全部放在内存中的排序。
外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

插入、希尔、选择、堆排、冒泡、归并、快速、计数排序

插入、希尔、选择、堆排、冒泡、归并、快速是七种基于比较的排序
计数排序是非比较排序

直接插入排序

排序原理
如图,在无序队列中取第一个数按照一定顺序插入到有序队列中,无序队列范围每进行一次循环便会减一,剩余无序队列按照相同方法继续进行下去,是减治算法
1)找到要插入的下标
2)插入值
直接插入图解
代码实现

void insertSort(int array[], int size){
 for (int i = 0; i < size; i++)
 {
  int k = array[i];
  int j;
  for (j = i - 1; j >= 0 && k < array[j]; j--)
  {
   array[j + 1] = array[j];
  }
  array[j + 1] = k;
 }
}

稳定性
稳定
时间空间复杂度
时间复杂度
最优:O(n)
最坏(平均):O(n^2)
空间复杂度:O(1)

希尔排序

排序原理
分组进行插入排序,
前提:在插入排序中,数据中越有序排序的效率越高。
其中间隔gap=gap/3-1或gap=gap/2
在这里插入图片描述
代码实现

void insertSortWithgap(int array[], int size, int gap){
 {
  for (int i = 0; i < size; i++)
  {
   int k = array[i];
   int j;
   for (j = i - gap; j >= 0 && k < array[j]; j-=gap)
   {
    array[j + gap] = array[j];
   }
   array[j + gap] = k;
  }
 }
}
void shellSort(int array[], int size){
 int gap = size;
 while (1){
  gap = gap / 2;
  insertSortWithgap(array, size, gap);
  if (gap == 1)
   break;
 }
}

稳定性
不稳定
时间空间复杂度
平均时间复杂度:O(N1.3—N2)

选择排序

排序原理
在无序范围数据中找到最大值放在最右边(或最左边),是减治算法。
可选最大放后面/选最小放前面/选最大、最小放后面、前面选择排序
代码实现

void selectSort(int array[], int size){
 for (int i = 0; i < size; i++)
 {
  int max = 0;
  for (int j = 0; j < size - i; j++)
  {
   if (array[j]>array[max])
    max = j;
  }
  swap(array + max, array + size - i - 1);//在之前的冒泡排序中定义
 }
}

稳定性
不稳定
时间空间复杂度
时间复杂度:O(n)
空间复杂度:O(1)

堆排序

排序原理
1.建大堆(降序建小堆)
2.堆顶元素(最大)和无需区间最后一个数进行交换
3.对堆进行向下调整
只能选最大放后面
堆排序
代码实现

void heapajust(int arr[], int start, int end) { 
 int dad = start;
 int son = dad * 2 + 1;
 while (son <= end) {  
  if (son + 1 <= end && arr[son] < arr[son + 1]) 
   son++;
  if (arr[dad] > arr[son]) 
   return;
  else {   
   swap(&arr[dad],&arr[son]);
   dad = son;
   son = dad * 2 + 1;
  }
 }
}
void heapSort(int arr[], int len) {
 int i;
 for (i = len / 2 - 1; i >= 0; i--) {
   heapajust(arr, i, len - 1);
   }
   for (i = len - 1; i > 0; --i) {
     	swap(arr+0, arr+i);
  	heapajust(arr, 0, i - 1);
  	}
  }

时间空间复杂度
时间复杂度:O(N*logN)
空间复杂度:O(1)

冒泡排序

排序原理
两数比较判断是否需要交换,每趟交换完成得到无序元素中最大数
代码实现

void swap(int* a, int* b){
 int temp = *a;
 *a = *b;
 *b = temp;
}
//一个函数要修改另外一个函数的数据,必须传指针和解引用
void bubbleSort(int array[], int size){
 for (int i = 0; i < size; i++)
 {
  for (int j = 0; j < size - i - 1; j++)
  {
   if (array[j]>array[j+1])
   swap(array+j, array+j+1);
  }
 }
}

稳定
时间空间复杂度
时间复杂度:O(n^2)
空间复杂度:O(1)

归并(合并)排序

排序原理
1.把整个待排序区间平均分成两份
2.分别对左右两个小区间按照分治算法处理,知道小区间内个数<=1。
3.合并两个有序区间

void Merge(int *a, int begin1, int end1, int begin2, int end2, int *tmp)
{
 int index = begin1;
  int i = begin1, j = begin2;
 while (i <= end1&&j <= end2){
  if (a[i] <= a[j])
   tmp[index++] = a[i++];
  else
   tmp[index++] = a[j++];
    }
 while (i <= end1)
  tmp[index++] = a[i++];
 while (j <= end2)
  tmp[index++] = a[j++];
 memcpy(a + begin1, tmp + begin1, sizeof(int)*(end2 - begin1 + 1));
}
void MergeSort(int *a, int left, int right, int *tmp)
{
 if (left >= right)
  return;
 assert(a);
int mid = left + ((right - left) >> 1);
 MergeSort(a, left, mid, tmp);
 MergeSort(a, mid + 1, right, tmp);
 Merge(a, left, mid, mid + 1, right, tmp);
}

稳定性
稳定
时间空间复杂度
时间复杂度:O(N*logN)
空间复杂度:O(N)
应用场景
解决磁盘中的外排序问题。

快速排序

排序原理
分治算法
1.在待排区间[left,right]中选择一个基准值(pivot)
1)选边上的值
2)随机选值
3)三数取中间值
2.扫描整个待排区间,比基准值小的放在基准值左边,比基准值大的放在基准值右边。
分组(parition)
1)Hover法
hover
2)挖坑法
相较hover法而言是将right保存而非交换
3)前后下标
3.整个待排区间分为三个部分:
比基准值小的[left,pivotIndex+1]
基准值[pivotIndex]
比基准值大的[pivotIndex+1,right]
照样处理左右两个区间,直到区间内数据个数为1或0。

代码实现

int quickSort(int a[], int p, int q)
{
 int i, j;
 int max, n;
 n = q - p + 1;
 if (p >= q)
 {
  return 0;
 }
  else
 {
  max = a[p];
  j = p;
  for (i = p + 1; i <= q; i++)
  {
   if (max >= a[i])
   {
    n = a[i];
        a[i] = a[j + 1];
    a[j + 1] = n;
    n = a[j];
    a[j] = a[j + 1];
    a[j + 1] = n;
    j = j + 1;
   }
  }
  quickSort(a, p, j - 1);
  quickSort(a, j + 1, q);
 }
 return 0;
}

稳定性
不稳定
时间空间复杂度
时间复杂度:O(N*logN)
空间复杂度:O(logN)

计数排序

排序原理
1.统计每个数出现的次数
2.数据回收
代码实现

void countSort(int *arr, int size)
{
 int i;
 int minValue = arr[0];
 int maxValue = arr[0];
 int range = 0;
 int* tmp = 0;
 int count = 0;
 for (i = 0; i < size; i++)
 {
  if (arr[i] < minValue){
   minValue = arr[i];
  }
    if (arr[i] > maxValue){
   maxValue = arr[i];
  }
 }
 range = maxValue - minValue + 1;
 tmp = (int*)malloc(sizeof(arr[0])*size);
 if (tmp == NULL)
  return;
 memset(tmp, 0, sizeof(int)*range);
 for (i = 0; i < size; i++)
 {
  tmp[arr[i] - minValue]++;
 }
  for (i = 0; i<range; i++)
 {
  while (tmp[i]--)
  {
   arr[count++] = i + minValue;
  }
 }
 free(tmp);
}

稳定性
稳定
时间空间复杂度
时间复杂度:O(MAX(N,范围))
空间复杂度:O(范围)
应用场景
数据密集的集中在某一范围内
排序

发布了39 篇原创文章 · 获赞 4 · 访问量 1157

猜你喜欢

转载自blog.csdn.net/qq_41403559/article/details/96481935