排序
1、基本概念
1、稳定排序:a == b,a本来在b前面,排序结束a仍然在b前面
2、非稳定排序:a==b,a原本在b前面,排序结束b在a前面
3、原地排序:排序过程中不申请新的空间
4、非原地排序:需要利用额外的数组来辅助排序
5、外部排序:排序的数据很大,不能一次容纳全部的排序记录,在排序过程中还需要访问外部存储器的排序
6、内部排序:待排序数据记录完全存放在内存中所进行的排序过程,适合不太大的元素序列。
2、排序算法
1、选择排序
void Selectsort(int a[],int n)
{
int i;
int j;
int k;
int min;
int temp;
for(i = 0;i < n;i++)
{
min = i;
for(j = i + 1;j < n;j++)
{
if(a[min] > a[j])
{
min = j;
}
}
if(i != min)
{
temp = a[i];
a[i] = a[min];
a[min] = temp;
}
}
}
//时间复杂度:O(n的平方)
//空间复杂度:O(1)
//非稳定排序
//原地排序
2、插入排序
void Insertsort(int a[],int n)
{
int i;
int j;
int temp;
int k;
if(a == NULL || n < 2)
{
return ;
}
for(i = 0;i < n;i++)
{
temp = a[i];
k = i-1;//挨个往前找
//找到插入位置
while(k >= 0 && a[k] > temp)
{
k--;
}
//腾出位置插进去,要插的位置是k+1;
for(j = i;j > k+1; j--)
{
a[j] = a[j-1];
}
a[k+1] = temp;
}
}
//时间复杂度O(n的平方)
//空间复杂度:O(1)
//稳定排序
//原地排序
3、冒泡排序
void Bubblesort(int a[],int n)
{
int i;
int j;
int temp;
for(i = 0;i < n;i++)
{
for(j = 0;j < n-i-1;j++)
{
if(a[j+1] < a[j])
{
temp = a[j+1];
a[j+1] = a[j];
a[j] = temp;
}
}
}
}
//时间复杂度O(n的平方)
//空间复杂度O(1)
//稳定排序
//原地排序
//优化,如果一次循环下来一次交换操作都没有,说明此时数组有序
void highBubblesort(int a[],int n)
{
int i;
int j;
int temp;
int flag = 1;
for(i = 0;i < n;i++)
{
for(j = 0;j < n-i-1;j++)
{
if(a[j+1] < a[j])
{
flag = 0;
temp = a[j+1];
a[j+1] = a[j];
a[j] = temp;
}
}
if(flag)
{
break;
}
}
}
4、希尔排序
希尔排序是插入排序的一种变种,无论是插入排序还是冒泡排序,如果数组的最大值刚好在第一位,需要将他挪到正确的位置就需要n-1次移动,也就是说,原数组的一个元素如果距离它正确的位置很远的话,则需要与相邻元素交换很多次才能到达正确的位置,这样相比比较花时间。
希尔排序就是加快速度简单的改进了插入排序,交换不相邻的元素以对数组的局部进行排序。
希尔排序的思想是采用插入排序的方法,先让数组中任意间隔为h的元素有序,刚开始h的大小可以是h = n/2,接着h = n/2,让h一直缩小,当h = 1时,也就是数组中任意间隔1的元素有序,此时的数组就是有序的了。
//希尔排序(插入排序的变种)
//没有特别理解插入,所以代码写的不好
void sort(int a[],int n)
{
int h;
int i;
int j;
int temp;
//遍历所有的步长
for(h = n/2; h > 0;h /= 2)
{
//遍历所有的元素
for(i = h;i < n;i++)
{
//遍历本组中的所有元素
for(j = i-h; j >= 0;j-=h)//这个地方没太用到插入,可以用插入,但是写的那个插入不太对。
{
//如果当前元素大于加上步长后的元素
if(a[j] > a[j+h])//
{
//有插入部分,非交换部分
void sort1(int a[],int n) { int h; int i; int j; int current; //遍历所有的步长 for(h = n/2; h > 0;h /= 2) { //遍历所有的元素 for(i = h;i < n;i++) { j = i; current = a[i]; while(j - h >= 0 && current < a[j - h]) { a[j] = a[j-h]; j = j-h; } a[j] = current; } } }
5、归并排序
归并排序是建立在归并操作上的一种有效的排序算法,使用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列。即使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并
把长度为n的输入序列分为长度为n/2的子序列;对着两个子序列分别采用归并排序;将两个排序号的子序列合并成一个最终的排序序列。
6、快速排序
基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字比另一部分的关键字小,则可对这两部分记录继续进行排序,以达到整个序列有序
算法描述:快速排序使用分治法来把一个串分成两个串。
从数列中调出一个数,称为基准(prvot)
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准后面(相同的数可以放在任一边),在这份分区退出后,该基准就处于数列的中间位置,这个称为分区操作。
递归的把小于基准值元素的子数列和大于基准值元素的子数列排序。
void swap(int *x,int *y)
{
int t;
t = *x;
*x = *y;
*y = t;
}
void fastsort(int arr[],int start,int end)
{
if(start >= end)
{
return ;
}
int mid = arr[end];
int left = start;
int right = end -1;
while(left < right)
{
while(arr[left] < mid && left < right)
{
left++;
}
while(arr[right] >= mid && left < right)
{
right--;
}
swap(&arr[left],&arr[right]);
}
if(arr[left] >= arr[end])
{
swap(&arr[left],&arr[end]);
}
else
{
left++;
}
if(left)
{
sort(arr,start,left-1);
sort(arr,left+1,end);
}
}
7、堆排序
基本思想:利用堆这种数据结构设计的一种算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质,即子节点的键值或索引总是小于或大于它的父节点
算法描述
1、将待排排序关键字序列(R1,R2……Rn)构成大顶堆,此堆为初始的无序区
2、将堆顶元素R【1】与最后一个元素R【n】交换,此时得到新的无序区(R1,R2……Rn-1)以及新的有序区(Rn),且满足R1,R2Rn-1<=R【n】
3、由于交换后新的堆顶R【1】可能违反堆的性质,因此需要对当前无序区(R1,R2,Rn-1)调整为新堆,然后在将R【1】和无序区最后一个元素交换,得到新的无序区(R1,R2……Rn-2)和新的有序区(Rn-1,Rn),不断重复此过程直到有序区的元素个数为n-1,排序完成。
8、计数排序
基本思想:计数排序不是基于比较的排序算法,核心在于将输入的数据值转化为键存储的额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数
算法描述
1、找出待排序的数组中最大和最小的元素
2、统计数组中每个值为i的元素出现的次数,存入数组c的第i项
3、对所有的计数累加(从c中的第一个元素开始,每一项和前一项相加)
4、反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C【i】减去1
9、桶排序
基本思想:捅排序是计数排序的升级版,利用了函数的映射关系,高效与否在于这个映射函数的确定。桶排序的工作的原理,假如输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶在分别排序(有可能在使用别的排序算法或者以递归方式继续使用桶排序进行排)
算法描述:
1、设置一个定量的数组当做空桶
2、遍历输入数据,并且把数据数据一个一个放到对应的桶里去
3、对每个不是空的桶进行排序
4、从不是空的桶里把排好序的数据拼接起来
10、基数排序
基本思想:基数排序是按照低位先排序,然后收集;在按照高位排序,然后在收集;以此类推,知道最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,在按照高优先级排序。最后的次序就是高优先级的在前,高优先级相同的低优先级高的在前。
算法描述:
1、取得数组的最大数,并取得位数
2、a为原始数组,从最低位组成radix数组
3、对radix进行计数排序(利用计数排序使用与小范围数的特点)

浙公网安备 33010602011771号