排序(详解)中

简介: 排序(详解)

快排(递归)


思路:

任取待排序元素序列中的某个元素作为基准值,按照该基准值,将待排序的元素分为两个子序列,左子序列的元素全部小于基准值,右子序列的元素全部大于基准值;然后左右子序列重复此操作,直到所有将所有元素排序完 右边找小,左边找大


将整个序列按照基准值划分为左右两部分的常见方式有三种:霍尔版本,挖坑法,前后指针法


单趟排序


选择基准值key(一般默认选择第一个数)

单趟排序的结果,小的数在key左边,大的数在key右边


霍尔版本


09745449dbee8ad434bc85b79e82506d_1578c4cac958461f9a5f93a0aebc1833.png


当第一个数为key时,为保证相遇位置的值一定比key小,right先走


R找到比key小的数停下,L撞到R相遇

L找到比key大的数与R找到比key小的数进行交换,然后停下,R撞到L相遇

每次基准值确定之后,就代表这个基准值的位置在整个排序中位置就确定好了,不需要再进行变动;接下来只需要在基准值的两边重复此操作,直到两边都只剩余一个元素,便说明排序完成


911c59269acd4a45b9f6a97363f67abf_a78295e1a6a94e02b08bf4dcd1faf9cc.png


int Partsort1(int* a, int left, int right)
{
    int keyi = left;
  while (right > left)
  {
  while (right>left && a[right] >= a[keyi])
  {
    right--;
  }
  while (right>left && a[left] <= a[keyi])
  {
    left++;
  }
  Swap(&a[right], &a[left]);
  }
  int meet = right;
  Swap(&a[meet], &a[keyi]);
  return meet;
}
void Quicksort(int* a, int left, int right)
{
  if (right <= left)
  {
  return;
  }
  //[left,mid-1] mid [mid+1,right]
  int mid = Partsort1(a, left, right);
  Quicksort(a, left, mid - 1);
  Quicksort(a, mid + 1, right);
}


完成第一趟排序之后,在进行右子序列排序时,发现第一个数(基准值)相较于其他的数还是偏大的,一般情况下基准值都是选择中间值,所以需要对于选基准值进行优化


三数取中


//三数取中
int Getmidindex(int* a, int left, int right)
{
  int mid = left + (right - left) / 2;
  if (a[right] > a[mid])
  {
  if (a[mid] > a[left])
  {
    return mid;
  }
  //   a[mid]<=a[left]
  else if (a[right] > a[left])
  {
    return left;
  }
  //    a[right]<=a[left]
  else
  {
    return right;
  }
  }
  else
  {
  if (a[right] > a[left])
  {
    return right;
  }
  //    a[right]<=a[left]
  else if (a[mid] > a[left])
  {
    return left;
  }
  //    a[mid]<=a[left]
  else
  {
    return mid;
  }
  }
}


优化后的结果


ba0c8b20851efe4443d3158ffc096beb_ac41247b03ee474bb23a34107fa42885.png


挖坑法


将第一个数据令为基准值,并将存放在临时变量中,形成一个坑位


第一次单趟排序


f2aa9ee173fafbf397cdad1d965539e4_0659066d53be463283865d63a8f1f5fa.png


剩余的排序


00dd250a11ca7f6fe759c024032eddeb_f36eb7b82131474cb13cee681806bacc.png


算法实现


int Partsort2(int* a, int left, int right)
{
    //三数取中
  int key = Getmidindex(a, left, right);
  Swap(&a[left], &a[key]);
  int hole = left;
  while (right > left)
  {
  //右边找小   填到左边的坑
  while (right > left && a[right] >= key)
  {
    right--;
  }
  a[hole] = a[right];
  hole = right;
  //左边找大   填到右边的坑
  while (right > left && a[left] <= key)
  {
    left++;
  }
  a[hole] = a[left];
  hole = left;
  }
  a[hole] = key;
  return hole;
}
void Quicksort(int* a, int left, int right)
{
  if (right <= left)
  {
  return;
  }
  int mid = Partsort2(a, left, right);
  Quicksort(a, left, mid - 1);
  Quicksort(a, mid + 1, right);
}


前后指针法


初始化时,prev指针指向序列的开头,cur指针指向prev指针的后一个位置


cur指针找小于key的数;prev指针要么紧跟着cur指针要么停留在比key大的数前面

cur指针遇到比key小的值时,便会停下来,++prev,交换prev和cur位置的值


77987e08c2753e579b77ee526b5a6bfe_60c687ceac6149ffb978f5d4aa5ebf10.png


剩余的排序


43cebc08c0ec67f82a6769a4764818f9_6e679e82dea348628ec4fe9504ec9c82.png


算法实现


int Partsort3(int* a, int left, int right)
{
    int key = Getmidindex(a, left, right);
  Swap(&a[left], &a[key]);
  int prev = left;
  int cur = left + 1;
  while (cur <= right)
  {
  if (a[cur] < a[key] && ++prev != cur)
  {
    Swap(&a[cur], &a[prev]);
  }
  ++cur;
  }
  Swap(&a[prev], &a[key]);
  return prev;
}
void Quicksort(int* a, int left, int right)
{
  if (right <= left)
  {
  return;
  }
  int mid = Partsort3(a, left, right);
  Quicksort(a, left, mid - 1);
  Quicksort(a, mid + 1, right);
}


目录
相关文章
|
算法 搜索推荐 调度
排序的介绍
排序的介绍
|
5月前
|
6月前
|
存储 搜索推荐
排序的总结
排序的总结
|
搜索推荐 算法
排序实现
排序实现
62 0
|
搜索推荐
排序进行曲-v1.0
排序进行曲-v1.0
|
搜索推荐
7-207 排序
7-207 排序
57 0