学过数据结构的都知道,排序有内部排序和外部排序之分,本文我们主要关注的是内部排序算法。常见的排序算法如下图所示:
排序算法可以分成以下几种:交换排序、插入排序、选择排序和归并排序。其中,冒泡排序和快速排序属于交换排序,插入排序和希尔排序属于插入排序,简单选择排序和堆排序属于选择排序,二路归并排序和多路归并排序属于归并排序。本文主要介绍这几种方法及其实现。
- 冒泡排序
冒泡排序(Bubble Sort)是一种比较简单的排序算法。算法的过程是这样的:重复地走访过要排序的数组,依次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素已经排序完成。这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
void BubbleSort(int nums[],int n)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n-1-i;j++)
{
if(nums[j]>nums[j+1])
{
int tmp=nums[j];
nums[j]=nums[j+1];
nums[j+1]=tmp;
}
}
}
}
- 快速排序
快速排序(Quick Sort)是对冒泡排序的一种改进。算法的基本思想是通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。该算法的核心是找到一个基准,将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
void QuickSort(int nums[],int low,int high)
{
if(low>high) return;
int key=nums[low];
int left=low,right=high;
while(left<right)
{
while(left<right && nums[right]>=key) right--;
nums[left]=nums[right];
while(left<right && nums[left]<key) left++;
nums[right]=nums[left];
}
nums[left]=key;
QuickSort(nums,low,left-1);
QuickSort(nums,left+1,high);
}
- 插入排序
插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。
void InsertionSort(int nums[],int n)
{
for(int i=1;i<n;i++)
{
int key=nums[i],j;
for(j=i-1;j>=0 && nums[j]>key;j--)
{
nums[j+1]=nums[j];
}
nums[j+1]=key;
}
}
- 希尔排序
希尔排序的基本思想:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量 dt =1( dt< dt-1 …<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
void ShellSort(int nums[],int n)
{
if(n<=1) return;
//div为增量
for(int div=n/2;div>=1;div=div/2)
{
for(int i=0;i<div;i++)
{
for(int j=i;j<n-div;j+=div)
{
for(int k=j;k<n;k+=div)
{
if(nums[j]>nums[k])
swap(nums[j],nums[k]);
}
}
}
}
}
- 简单选择排序
简单选择排序的基本思想是每一趟从待排序的数据元素中选出最小(最大)的元素,顺序放在待排序的数列最前,直到全部待排序的数据元素全部排完。
void SelectSort(int nums[],int n)
{
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
if(nums[i]>nums[j])
swap(nums[i],nums[j]);
}
}
}
- 堆排序
暂时还不会。。 - 二路归并排序
归并排序(Merge Sort)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
void Merge(int nums[],int low,int mid,int high)
{
int tmp[high+1];
int i,j;
for(i=low;i<=high;i++)
tmp[i]=nums[i];
for(i=low,j=mid+1;i<=mid&&j<=high;)
{
//选择两个数组中同一位置较小的元素
if(tmp[i]<=tmp[j])
nums[low++]=tmp[i++];
else
nums[low++]=tmp[j++];
}
//将剩余元素放到数组中
while(i<=mid)
nums[low++]=tmp[i++];
while(j<=high)
nums[low++]=tmp[j++];
}
void MergeSort(int nums[],int low,int high)
{
//至少有两个元素
if(low<high)
{
int mid=(low+high)/2;
MergeSort(nums,low,mid);
MergeSort(nums,mid+1,high);
Merge(nums,low,mid,high);
}
}