【数据结构】有关排序算法的整理

排序的概念

排序:就是一串数按照递增或递减的顺序排列
稳定性:排序后两个数字的相对次序保持不变,则这种排序是稳定的,否则不稳定
举个例子:
在这里插入图片描述
内部排序和外部排序
内部排序:数据元素全部放在内存中的排序
外部排序:数据元素太多不能同时放在内存中,且排序过程不能在内外存之间移动的顺序

排序算法实现、复杂度及稳定性分析

在这里插入图片描述
考点:
1.选择题
2.面试期间:

1.插入排序

假设我按从小到大排序,后面元素,与前一个元素比较,后面元素小,则向后移,再与前元素比较,依次循环,直到找到合适的位置(比前面元素大,比后面元素小),插入就可以了
时间复杂度: O(1)
空间复杂度 : O(N)
稳定性:稳定
使用场景:接近有序,数据量较小在这里插入图片描述

void Insertsort(int *array, int n)
{
 for (int i = 1; i < n; i++)
 {
  int key = array[i];//key是与前面元素比较的元素
  int end = i - 1;//有序中的最后一个元素
  while (key < array[end]&&end >= 0)
  {
   array[end + 1] = array[end];
   end--;
  }
  array[end + 1] = key;
 }
}

2.希尔排序

如果数据量比较大,且不接近有序,依旧按照插入排序的思想排序,就可以采用希尔排序
希尔排序:按照一定间隔划分为组,让数据量变小,在组内进行插入排序
时间复杂度: O(N^1.25 ~ 1.6N^1.25)
空间复杂度:O(1)
稳定性:不稳定

void shellsort(int *a, int n)
{
 int gap = gap/3+1while (gap > 0)
 {
  for (int i = 0; i < n; i++)//分组交替依次插入
  {
   int end = i;
   int key = a[i + gap];
   while (key < a[end] && end>=0&& i+gap < n)
   {
    a[end + gap] = a[end];
    end-=gap;
   }
   a[end+gap] = key;
  }
 } 
}

3.选择排序(直接选择排序)

若要排升序,则在元素中找最大的,与最后一个元素交换,再缩范围(剩余的元素中)继续之前的步骤;也可以找最小的,与第一个元素交换,再缩范围(剩余的元素中)继续之前的步骤。排降序,则与升序是相反的
选择排序很好理解,但效率不是很好,实际很少用
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:不稳定

void Select1(int *a, int size)
{
 for (int i = 0; i < size - 1; i++)//选择躺数
 {
  int max = 0;
  for (int start = 0; start < size-i; start++)//每一次选择的方式
  {
   if (a[start]>a[max])
    max = start;
  }
  if (max != size - 1 - i)
   Swap(&a[max], &a[size - 1- i]);
 }
}

可以直接一起让最小的、最大的元素一起排序

void Select2(int *n, int size)
{
 int start = 0;
 int end = size - 1;
 while (start < end)
 {
  int min = start;
  int max = end;
  for (int i = start + 1; i <= end; i++)
  {
   if (n[i]>n[max]) max = i;
   if (n[i] < n[min]) min = i;
  }
  if (max != end)  Swap(&n[max], &n[end]);
  if (min == end)  min = max;
  if (min != start) Swap(&n[min], &n[start]);
  start++, end--;
 }
}

4.堆排序

步骤:
1.先建堆(升序建大堆,降序建小堆)
从倒数第一个非叶子节点位置开始,一直到根节点的位置,应用向下调整
2.排序(根据堆删除的思想)
将堆顶元素与堆中最后一个元素交换,将堆中有效元素个数减少一个,对堆顶元素向下调整

完全二叉树的高度:log(N+1)~log(N)
时间复杂度: O(nlogn)
空间复杂度: O(1)
稳定性:不稳定
应用场景:元素不是很多、给序列中前n个元素排序、找序列中前n个元素

void AdjustDown(int *a, int size, int parent)//向下调整
{
 parent = 0;
 int child = parent * 2 + 1;
 while (child < size)
 {
  if (a[child] > a[child + 1] && child + 1 < size)
   child = child + 1;
  if (a[parent] > a[child])
  {
   Swap(&a[parent], &a[child]);
   parent = child;
   child = parent * 2 + 1;
  }  
  else return;
 } 
}
void HeapSort(int *a, int size)//
{
 //我建的小堆,你也可以建大堆
 for (int root = (size - 2) >> 1; root >= 0; root--)
  AdjustDown(a, size, root);
 //排序
 int end = size - 1;
 while (end>0)
 {
  Swap(&a[0], &a[end]);
  AdjustDown(a, size, 0);
  end--;//
 }
}

5.冒泡排序

https://blog.csdn.net/weixin_43219708/article/details/103044871
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:稳定
应用场景:如果用户需要稳定的排序算法、越接近有序,效率越高

void BubbleSort(int *a, int size)
{
 for (int i = 0; i < size-1; i++)
 {
  int ischange = 0;//检查进入循环是否排序
  for (int j = 1; j <= size - 1 - i; j++)
  {
   if (a[j - 1]>a[j])
   {
    Swap(&a[j - 1], &a[j]);
    ischange = 1;
   }  
  }
  if (!ischange)  return;//已经有序就不用继续进行后面的冒泡了
 }
}

6.快速排序

面试期间常考的排序
原理
1.从区间中任取一个元素作为基准值(一般情况取的都是区间最左/最右侧元素)
2.按照基准值对区间的元素进行划分为两部分
3.假如我排的是升序(区间左侧比基准值小,右侧比基准值大)
4.递归分别排基准值左侧,右侧(与二叉数排序规则像)
时间复杂度:O(nlogn)
空间复杂度: O(logN)
稳定性:不稳定

  • 左右指针法
//左右指针法(hoare版本)
int div(int *a, int left, int right)
{
int k =right;
 while (left < right)
 {
  while (a[left] <= a[k] && left < right)
   left++;
  while (a[right] >= a[k] && left < right)
   right--;
  if (left<right)
   Swap(&a[left], &a[right]);
 }
 if (left != k)//在同一位置就不用交换了
  Swap(&a[left], &a[k]);
 return left;
}
void QuickSort(int *a, int left, int right)
{
 if (left > right)
  return;
 int ret = div(a, left, right);//与前序遍历类似
 QuickSort(a, left, ret-1);
 QuickSort(a, ret + 1, right);
}
  • 挖坑法
int div1(int *a, int begin, int end)
{
 int k = a[end];
 while (begin < end)
 {
  while (a[begin] <= k&&begin < end)
  {
   begin++;
  }
  a[end] = a[begin];
  while(a[end] >= k&&begin < end)
  {
   end--;
  }
  a[begin] = a[end];
 }
 a[begin] = k;
 return begin;
}
void QuickSort(int *a, int left, int right)
{
 if (left > right)
  return;
 int ret = div1(a, left, right);
 QuickSort(a, left, ret-1);
 QuickSort(a, ret + 1, right);
}
  • 前后指针法
int div2(int *a, int begin, int end)
{
 int k = begin;
 int pre = begin;
 int cur = begin + 1;//找比pre小的
 while (cur<=end)
 {
  if (a[cur] <= a[k]&&++pre != cur)
  {
   Swap(&a[cur], &a[pre]);
  }
  cur++;
 }
 Swap(&a[k], &a[pre]);
 return pre;
}
void QuickSort(int *a, int left, int right)
{
 if (left > right)
  return;
 int ret = div2(a, left, right);
 QuickSort(a, left, ret-1);
 QuickSort(a, ret + 1, right);
}

7.归并排序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值