所谓排序就是整理文件中的记录,使之按关键字递增(或递减)次序排列起来。
稳定排序与不稳定排序:
假设 Ki = Kj ,且排序前序列中 Ri 领先于 Rj ;
若在排序后的序列中 Ri 仍领先于 Rj ,则称排序方法是稳定的。
若在排序后的序列中 Rj 仍领先于 Ri ,则称排序方法是不稳定的。
例:序列 3 15 8 8 6 9
若排序后得 3 6 8 8 9 15 稳定的#两个8 不同顺序
若排序后得 3 6 8 8 9 15 不稳定的
根据排序过程中待排序记录是否全部放置在内存中,排序分为内排和外排。
内部排序: 指的是待排序记录存放在计算机随机存储器中进行的排序过程。
外部排序: 指的是待排序记录的数量很大,以致内存一次不能容纳全部记录,在排序过程中尚需对外存进行访问的排序过程。
算法的复杂性:体现在运行该算法时的计算机所需资源的多少上,计算机资源最重要的是时间和空间(即寄存器)资源,因此复杂度分为时间和空间复杂度。
辅助空间:辅助空间是评价排序算法的一个重要指标,辅助空间是指除了存放待排序资源之外,执行算法所需要的其他存储空间。
时间复杂度:简单的说就是程序循环执行的总的次数。算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。时间复杂度常用大O符号表述,即O(f(n))。
按照排序过程中所依据的原则的不同可以分类为:
►插入排序
直接插入排序 希尔排序
►交换排序
冒泡排序 快速排序
►选择排序
简单选择排序 堆排序
►归并排序
►基数排序
介绍几种已经掌握的排序方法:
直接插入排序:
对于给定的一组记录,初始时假定第一个记录自成一个有序的序列,其余的记录为无序序列;接着从第二个记录开始,按照记录的大小依次将当前处理的记录插入到其之前的有序序列中,直至最后一个记录插入到有序序列为止。
例:将 29 18 87 56 3 27 按由小到大排序
① (29) (18 87 56 3 27)
② (18 29) (87 56 3 27)
③ (18 29 87) (56 3 27)
④ (18 29 56 87) (3 27)
⑤ ( 3 18 29 56 87) (27)
⑥ (3 18 27 29 56 87)
具体的程序看下:(由于头文件写了不好上传 请用时自行加上 下面也是)
int main()
{
int i,j,temp,length;
int a[5] = {8, 7, 3, 5, 1};
length = sizeof(a)/sizeof(a[0]);
for(i = 1; i < length; i++)
{
temp = a[i];
for(j = i-1 ;j >= 0; j–)
{
if(temp < a[j])
{
a[j+1]= a[j];
}
else
{
break;
}
}
a[j+1] = temp;
}
for(i = 0; i < length; i++)
{
printf("%d",a[i]);
}
printf("\n");
return 0;
}
稳 定 性:稳定
时间复杂度: O(n^2)
(1)初始数据正序,总比较次数:n-1
(2)初始数据逆序,总比较次数:(n2+n-1)/2= O(n2)
(3)初始数据无序,第i趟平均比较次数(i+1)/2,总次数为:(n2+3n)/4=O(n2)
(4)可见,原始数据越趋向正序,比较次数和移动次数越少。
希尔排序:
希尔排序也称为“缩小增量排序”,基本原理是:首先将待排序的元素分为多个子序列,使得每个子序的元素个数相对较少,对各个子序分别进行直接插入排序,待整个待排序序列“基本有序后”,再对所有元素进行一次直接插入排序。
希尔排序的特点:
时间复杂度:希尔排序的时间复杂性在O(nlog2n)和O(n2 )之间,大致为O(n1.3)。
稳 定 性:不稳定
具体程序如下:
int main()
{
int a[] = {2,5,7,25,89,105,34};
int length,i,j,temp,gap;
length = sizeof(a)/ sizeof(a[0]);
for(gap = length/2; gap > 0; gap /= 2)
{
for(i = gap; i < length; i++ )
{
temp = a[i];
for(j = i - gap; j >= 0 && temp < a[j];j=j-gap)
{
a[j+gap] = a[j];
}
a[j+gap]= temp;
}
}
for(i = 0; i < length; i++)
{
printf(“%d “,a[i]);
}
printf(“\n”);
return 0;
}
快速排序:
快速排序是一种非常高效的排序方法,采用“分而治之”的思想,把大的拆分为小的,小的在拆分为更小的。
原理是:对于一组给定的记录,通过一趟排序后,将原序列分为两部分,其中前部分的所有记录均比后部分的所有记录小,然后再依次对前后两部分的记录进行快速排序,递归该过程,直到序列中的所有记录均为有序为止
快速排序特点:
稳 定 性:不稳定
平均时间复杂度: O(nlog2n)
程序如下:
void Sort(int *a,int low,int high)
{
int i,j;
int index;
i = low;
j = high;
index = a[i];
if(low >= high)
{
return;
}
while(i < j)
{
while(i < j && a[j] >= index)
{
j--;
}
if(i < j)
{
a[i++] = a[j];
}
while(i < j && a[i] < index)
{
i++;
}
if(i < j)
{
a[j--] = a[i];
}
}
a[i] = index;
Sort(a,low,i - 1);
Sort(a,i + 1,high);
}
void QuickSort(int a[], int length)
{
Sort(a,0,length - 1);
}
int main()
{
int a[] = {9, 8, 15, 78, 54, 89, 21, 36};
int i;
int length = sizeof(a) /sizeof(a[0]);
QuickSort(a,length);
for(i = 0; i < length; i++)
{
printf(“%d “,a[i]);
}
printf(“\n”);
return 0;
}
归并排序:
利用递归与分治技术将数据序列划分为越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并成为越来越大的有序序列。
原理如下:对于给定的一组记录,首先将两个相邻的长度为1的子序列进行归并,得到n/2个长度为2或者1的有序子序列,在将其两两归并,反复执行此过程,直到得到一个有序的序列为止。
例:将49 38 65 97 76 13 27由小到大排序
初始化关键字:[49] [38] [65] [97] [76] [13] [27]
一趟归并后: [38 49] [65 97] [13 76] [27]
二趟归并后: [38 49 65 97] [13 27 76]
三趟归并后: [13 27 38 49 65 76 97]
归并排序特点:
平均时间复杂度: O(nlog2n)
稳 定 性: 稳定
程序如下:
void merging(int a[],int begin,int mid,int end)
{
int tmp = (int )malloc(sizeof(int)*(end - begin + 1));
int i,j,k;
i = begin;
j = mid + 1;
k = 0;
while(i <= mid && j <=end)
{
if(a[i] < a[j])
tmp[k++] = a[i++];
else
tmp[k++] = a[j++];
}
while(i <= mid)
tmp[k++] = a[i++];
while(j <= end)
tmp[k++] = a[j++];
for(i = 0;i < k;i++)
{
a[begin + i] = tmp[i];
}
free(tmp);
}
void merge_sort(int a[],int begin,int end)
{
int mid;
if(a == NULL || begin >= end)
return;
mid = (begin + end) / 2;
merge_sort(a,begin,mid);
merge_sort(a,mid + 1,end);
merging(a,begin,mid,end);
}
int main()
{
int i,length;
int a[10] = {0};
printf(“enter 10 num…\n”);
for(i = 0;i < 10;i++)
{
scanf(“%d”,&a[i]);
}
length = sizeof(a)/sizeof(int);
merge_sort(a,0,length - 1);
for(i = 0;i < length;i++)
{
printf("%d ",a[i]);
}
return 0;
}