经典内部排序算法有交换排序、插入排序、选择排序、归并排序、分配排序。
分类如下:
交换排序:冒泡排序、快速排序。
插入排序:直接插入排序、折半插入排序、希尔排序。
选择排序:直接选择排序、堆排序。
归并排序
分配排序:基数排序、桶排序。
本博文将介绍交换排序。
一、冒泡排序
冒泡排序算法的运作如下:
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
void Bubble_Sort(int *arr,int len)
{
int i,j,exchange;
bool flag = true; //增设标志位,如果已经排好,则不再进行下次冒泡排序
for(i=0; i<len-1 && flag; i++)//i标记循环次数,共进行len-1次循环
{
flag = false;//每次遍历开始时,初始状态为未交换
for(j=0;j<len-i-1;j++)//第i+1次遍历
if(arr[j] > arr[j+1])
{
exchange = arr[j];
arr[j] = arr[j+1];
arr[j+1] = exchange;
flag = true;
}
}
}
思想
快速排序采用的思想是分治思想。
快速排序是找出一个元素(理论上可以随便找一个)作为基准(pivot),然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值 都不小于基准值,如此作为基准的元素调整到排序后的正确位置。递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正 确位置,排序完成。所以快速排序算法的核心算法是分区操作,即如何调整基准的位置以及调整返回基准的最终位置以便分治递归。
举例说明一下吧,这个可能不是太好理解。假设要排序的序列为
2 2 4 9 3 6 7 1 5 首先用2当作基准,使用i j两个指针分别从两边进行扫描,把比2小的元素和比2大的元素分开。首先比较2和5,5比2大,j左移
2 2 4 9 3 6 7 1 5 比较2和1,1小于2,所以把1放在2的位置
2 1 4 9 3 6 7 1 5 比较2和4,4大于2,因此将4移动到后面
2 1 4 9 3 6 7 4 5 比较2和7,2和6,2和3,2和9,全部大于2,满足条件,因此不变
经过第一轮的快速排序,元素变为下面的样子
[1] 2 [9 3 6 7 4 5]
之后,在把2左边的元素进行快排,由于只有一个元素,因此快排结束。右边进行快排,递归进行,最终生成最后的结果。
快速排序函数,通过递归实现
void Quick_Sort(int *a,int low,int high)
{
int pos;
if(low < high)
{
pos = findPoss(a,low,high);
Quick_Sort(a,low,pos-1);
Quick_Sort(a,pos+1,high);
}
return ;
}
/*
该函数返回分割点数值所在的位置,a为待排序数组的首地址,
low刚开始表示排序范围内的第一个元素的位置,逐渐向右移动,
high刚开始表示排序范围内的最后一个位置,逐渐向左移动
*/
int findPoss(int *a,int low,int high)
{
int val = a[low];
while(low < high)
{
while(low<high && a[high]>=val)
high--;
a[low] = a[high];
while(low<high && a[low]<=val)
low++;
a[high] = a[low];
}
//最终low=high
a[low] = val;
return low;
}
算法复杂度:平均O(NlgN),最坏O(N^2)。