c语言强化篇之"排序算法”

1.冒泡排序
主要思想:相邻元素比较,大的放后面,小的放前面,实质上是交换排序。

void BubbleSort(int *arr,int len)//冒泡排序
{
 for(int i =0;i<len-1;i++)//趟数
 {
  for(int j = 0;j<len-i-1;j++)
  {
   int tmp = 0;
   if(arr[j]>arr[j+1])
   {
       tmp = arr[j+1];
       arr[j+1] = arr[j];
       arr[j] = tmp;
   }
  }
 }
}

时间复杂度:O(n^2)
最好:O(n^2)
最坏:O(n^2)
空间复杂度:O(1)
稳定性:稳定
冒泡排序的优化算法

void BubbleSort(int *arr,int len)//冒泡排序的优化算法  
{
 bool swap = false;
 for(int i =0;i<len-1;i++)//趟数
 {
  for(int j = 0;j<len-i-1;j++)
  {
   int tmp = 0;
   if(arr[j]>arr[j+1])
   {
       tmp = arr[j+1];
       arr[j+1] = arr[j];
       arr[j] = tmp;
   swap = true;
   }
  }
  if(!swap)
  {
   break;
  }
 }

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

2.选择排序
主要思想:每一趟在n-i+1(i = 1,2,…,n-1)个记录中选取关键字最小的记录作为有序序列的第i个记录。

void SelectSort(int *arr,int len)//简单选择排序
{
 for(int i = 0;i<len;i++)
 {
  for(int j = i+1;j<len;j++)
  {
   int tmp = 0;
   if(arr[i]>arr[j])
   {
    tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
   }
  }
 }
}

时间复杂度:O(n^2)
最好:O(n^2)
最坏:O(n^2)
空间复杂度:O(1)
稳定性:不稳定
3.直接插入排序
主要思想:将一个记录插入到已排好序的有序表中,从而得到一个新的,记录数增1的有序表。

void InsertSort(int *arr,int len)//直接插入排序
{
 for(int i = 1;i<len;i++)
 {
  int tmp = arr[i];
  int j = 0;
  for(j = i-1;j>=0;j--)
  {
   if(arr[j] > tmp)
   {
    arr[j+1] = arr[j];
   }
   else
   {
    break;
   }
  }
  arr[j+1] = tmp;
 }
}

时间复杂度:O(n^2)
最好:O(n)
最坏:O(n^2)
空间复杂度:O(1)
稳定性:稳定
4.希尔排序
主要思想:又称缩小增量排序,先将整个待排序序列分割成为若干个子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。

void Shell(int *arr,int len,int gap)
{
 for(int i = gap;i < len;i++)
 {
  int tmp = arr[i];
  int j = 0;
  for(j = i-gap;j >= 0;j = j-gap)
  {
   if(arr[j] > tmp)
   {
    arr[j+gap] = arr[j];
   }
   else
   {
    break;
   }
  }
  arr[j+gap] = tmp;
 }
}
void ShellSort(int *arr,int len)//希尔排序
{
 int drr[] = {5,3,1};
 int lend = sizeof(drr)/sizeof(drr[0]);
 for(int i = 0;i < lend;i++)
 {
  Shell(arr,len,drr[i]);
 }
}

时间复杂度:O(n^1.3~1.5)
最好:O(n^2)
最坏:O(n^2)
空间复杂度:O(1)
稳定性:不稳定
5.堆排序
主要思想:先建立一个“大根堆”,使记录序列按关键字非递减有序排序,则在堆排序的算法这先建一个“大顶堆”,即先选得一个关键字为最大的记录并与序列中最后一个记录交换,然后对系列中前n-1记录进行筛选,重新将它调整为一个“大顶堆”,如此反复排序结束。

void Adjust(int *arr,int start,int end)//一次调整过程
{
 int tmp = arr[start];
 for(int i = 2*start+1;i <= end;i = 2*i+1)
 {
  //是否有右孩子
  if((i<end)&&arr[i]<arr[i+1])
  {
   i++;
  }
  //i肯定是当前孩子最大值的下标
  if(arr[i]>tmp)
  {
   arr[start] = arr[i];
   start = i;
  }
  else
  {
   break;
  }
 }
 arr[start] = tmp;
}
void HeapSort(int *arr,int len)//堆排序
{
 int i = 0;
 for(i = (len-1-1)/2;i>=0;i--)
 {
  Adjust(arr,0,len-1);
  //肯定是大根堆
  //先交换,后调整(只需要调整0号下标这颗树)
 }
 for(i = 0;i<len-1;i++)
 {
  int tmp = arr[0];
  arr[0] = arr[len-i-1];
  arr[len-1-i] = tmp;
  Adjust(arr,0,len-1-i-1);
 }
}

时间复杂度:O(nlog2n)
最好:O(nlog2n)
最坏:O(nlog2n)
空间复杂度:O(1)
稳定性:不稳定
6.归并排序
主要思想:即先使每个子序列有序,再使子序列段间有序 。

void Merge(int *arr,int len,int gap)
{
 int *brr = (int*)malloc(sizeof(int)*len);
 assert(brr!=NULL);
 int i = 0;//brr下标
 int start1 = 0;
 int end1 = start1+gap-1;
 int start2 = end1+1;
 int end2 = start2+gap-1<len-1?start2+gap-1:len-1;
 //当有两个归并段的时候
 while(start2 < len)
 {
  //当两个归并段还没有比较的时候
  while(start1 <= end1&&start2 <= end2)
  {
   if(arr[start1] <= arr[start2])
   {
    brr[i++] = arr[start1++];
   }
   else
   {
    brr[i++] = arr[start2++];
   }
  }
  while(start1 <= end1)
  {
   brr[i++] = arr[start1++];
  }
  while(start2 <= end2)
  {
   brr[i++] = arr[start2++];
  }
  start1 = end2+1;
  end1 = start1+gap-1;
  start2 = end1+1;
  end2 = start2+gap-1<len-1?start2+gap-1:len-1;
 }
 while(start1<len)
 {
  brr[i++] = arr[start1]++;
 }
 for(int i = 0;i < len;i++)
 {
  brr[i] = arr[i];
 }
}
void MergeSort(int *arr,int len)//归并排序
{
 for(int i = 1;i < len;i*=2)
 {
  Merge(arr,len,i);
 }
}

时间复杂度:O(nlog2n)
最好:O(nlog2n)
最坏:O(nlog2n)
空间复杂度:O(n)
稳定性:稳定
7.快速排序
主要思想:通过一趟排序将待排记录分割成独立的两部分,其中一部分的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
(1)固定选取基准法
1*递归形式

int Partion(int *arr,int low,int high)//一趟排序
{
 int tmp = arr[low];
 while(low<high)
 {
  while(low<high&&arr[high]>tmp)
  {
   high--;
  }
  if(low>=high)
  {
   break;
  }
  else
  {
   arr[low] = arr[high];
  }
  while(low<high&&arr[low]<tmp)
  {
   low++;
  }
  if(low>=high)
  {
   break;
  }
  else
  {
   arr[high] = arr[low];
  }
 }
 arr[low] = tmp;
 return low;
}
void Quick(int *arr,int start,int end)//快速排序递归
{
 int par = Partion(arr,start,end);//左边  右边
 if(par>start+1)
 {
  Quick(arr,start,par-1);
 }
 if(par<end-1)
 {
  Quick(arr,par+1,end);
 }
}
void QuickSort(int *arr,int len)
{
 Quick(arr,0,len-1);
}

2*非递归形式(用栈来实现)

void QuickSort1(int *arr,int len)//非递归快速排序
{
 int tmpSize = (int)log((double)len)/long((double)2);
 int *stack = (int*)malloc(sizeof(int)*tmpSize*2);
 int top = 0;//数组的下标
 assert(stack != NULL);
 int low = 0;
 int high = len-1;
 int par = Partion(arr,low,high);//第一次找完基准
 if(par>low+1)
 {
  stack[top++] = low;
  stack[top++] = par-1;
 }
 if(par<high-1)
 {
  stack[top++] = par+1;
  stack[top++] = high;
 }
 while(top>0)//栈不为空
 {
  high = stack[--top];
  low = stack[--top];
  par = Partion(arr,low,high);
  if(par>low+1)
  {
   stack[top++] = low;
   stack[top++] = par-1;
  }
  if(par<high-1)
  {
   stack[top++] = par+1;
   stack[top++] = high;
  }
 }
 free(stack);
}

(2)随机选取基准法
随机选取基准防止序列有序带来的时间上的浪费,提高效率。

int Partion(int *arr,int low,int high)//一趟排序
{
 int tmp = arr[low];
 while(low<high)
 {
  while(low<high&&arr[high]>tmp)
  {
   high--;
  }
  if(low>=high)
  {
   break;
  }
  else
  {
   arr[low] = arr[high];
  }
  while(low<high&&arr[low]<tmp)
  {
   low++;
  }
  if(low>=high)
  {
   break;
  }
  else
  {
   arr[high] = arr[low];
  }
 }
 arr[low] = tmp;
 return low;
}
void Swap(int *arr,int start,int end)
{
 int tmp = arr[start];
 arr[start] = arr[end];
 arr[end] = tmp;
}
void Quick(int *arr,int start,int end)
{
 srand((unsigned int)time(NULL));
 Swap(arr,low,rand() % (high-low)+low);
 int par = Partion(arr,start,end);//左边  右边
 if(par>start+1)
 {
  Quick(arr,start,par-1);
 }
 if(par<end-1)
 {
  Quick(arr,par+1,end);
 }
}
void QuickSort(int *arr,int len)
{
 Quick(arr,0,len-1);
}

(3)三分取中法
减少有序和随机性发生的不确定性造成的不必要的时间上的浪费。

int Partion(int *arr,int low,int high)//一趟排序
{
 int tmp = arr[low];
 while(low<high)
 {
  while(low<high&&arr[high]>tmp)
  {
   high--;
  }
  if(low>=high)
  {
   break;
  }
  else
  {
   arr[low] = arr[high];
  }
  while(low<high&&arr[low]<tmp)
  {
   low++;
  }
  if(low>=high)
  {
   break;
  }
  else
  {
   arr[high] = arr[low];
  }
 }
 arr[low] = tmp;
 return low;
}
void Swap(int *arr,int start,int end)
{
 int tmp = arr[start];
 arr[start] = arr[end];
 arr[end] = tmp;
}
void SelectPivotMedianOfThree(int *arr,int low,int high)//三分取中法
{
 int mid = (high-low)/2+low;//(high+low)>>1;
 //arr[mid]<=arr[low]<=arr[high];
 if(arr[mid]>arr[low])
 {
  Swap(arr,mid,low);
 }
 if(arr[low]>arr[high])
 {
  Swap(arr,low,high);
 }
 if(arr[mid]>arr[high])
 {
  Swap(arr,mid,high);
 }
}
void Quick(int *arr,int start,int end)
{
 SelectPivotMedianOfThree(arr,start,end);
 int par = Partion(arr,start,end);//左边  右边
 if(par>start+1)
 {
  Quick(arr,start,par-1);
 }
 if(par<end-1)
 {
  Quick(arr,par+1,end);
 }
}
void QuickSort(int *arr,int len)
{
 Quick(arr,0,len-1);
}

时间复杂度:O(nlog2n)
最好:O(nlog2n)
最坏:O(n^2)
空间复杂度:O(log2n)
稳定性:不稳定

快速排序优化
(1)当待排序的区间中,待排序的个数小于某一个数量级的时候,使用插入排序(插入排序越有序越快,可以达到O(n)的时间复杂度)

void InsertSort(int *arr,int low,int high)//直接插入排序
{
 for(int i = low+1;i<high;i++)
 {
  int tmp = arr[i];
  int j = 0;
  for(j = i-1;j>=0;j--)
  {
   if(arr[j] > tmp)
   {
    arr[j+1] = arr[j];
   }
   else
   {
    break;
   }
  }
  arr[j+1] = tmp;
 }
}
int Partion(int *arr,int low,int high)//一趟排序
{
 int tmp = arr[low];
 while(low<high)
 {
  while(low<high&&arr[high]>tmp)
  {
   high--;
  }
  if(low>=high)
  {
   break;
  }
  else
  {
   arr[low] = arr[high];
  }
  while(low<high&&arr[low]<tmp)
  {
   low++;
  }
  if(low>=high)
  {
   break;
  }
  else
  {
   arr[high] = arr[low];
  }
 }
 arr[low] = tmp;
 return low;
}
void Swap(int *arr,int start,int end)
{
 int tmp = arr[start];
 arr[start] = arr[end];
 arr[end] = tmp;
}
void Quick(int *arr,int start,int end)
{
 if((end-start+1) < 100)
 {
  InsertSort(arr,start,end);
  return;
 }
 int par = Partion(arr,start,end);//左边  右边
 if(par>start+1)
 {
  Quick(arr,start,par-1);
 }
 if(par<end-1)
 {
  Quick(arr,par+1,end);
 }
}
void QuickSort(int *arr,int len)
{
 Quick(arr,0,len-1);
}

(2)聚集相同元素基准法
当有多个元素相同时,用此法可以大大提高效率。

int Partion(int *arr,int low,int high)//一趟排序
{
 int tmp = arr[low];
 while(low<high)
 {
  while(low<high&&arr[high]>tmp)
  {
   high--;
  }
  if(low>=high)
  {
   break;
  }
  else
  {
   arr[low] = arr[high];
  }
  while(low<high&&arr[low]<tmp)
  {
   low++;
  }
  if(low>=high)
  {
   break;
  }
  else
  {
   arr[high] = arr[low];
  }
 }
 arr[low] = tmp;
 return low;
}
void Swap(int *arr,int start,int end)
{
 int tmp = arr[start];
 arr[start] = arr[end];
 arr[end] = tmp;
}
void FocusNumPar(int *arr,int low,int par,int high,int *left,int *right)
{
 if(low < high);
 {
  int parLeft = par-1;
     int ph = par+1;
     int i = par-1;
  for(int i = par-1;i >= low;i--)
  {
   if(arr[i] == arr[par])
   {
    if(i != parLeft)
    {
     Swap(arr,i,parLeft);
     parLeft--;
    }
       else
       {
        parLeft--;
       }
   }
  }
  int parRight = par+1;
  for(int i = par+1;i <= high;i++)
  {
   if(arr[i] == arr[par])
   {
    if(i != parRight)
    {
     Swap(arr,i,parRight);
     parRight++;;
    }
       else
       {
        parRight++;
       }
   }
  }
 }
}
void Quick(int *arr,int start,int end)
{
 int par = Partion(arr,start,end);//左边  右边
 int left = 0;
 int right = 0;
 FocusNumPar(arr,start,par,end,&left,&right);
 if(left >= start+1)
 {
  Quick(arr,start,left);
 }
 if(right <= end-1)
 {
  Quick(arr,right,end);
 }
}
void QuickSort(int *arr,int len)
{
 Quick(arr,0,len-1);
}

以下是具体的每个排序算法的复杂度
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值