排序概念:使一个序列满足非递减(或者非递归)关系,即使得一个序列有序,这样的操作就称为排序。
下面我们就来看看各类排序吧。
1.冒泡排序
冒泡排序的基本思想:两两比较相邻记录的关键字,如果反序就交换,直到全部有序结束。
下面是算法的图解和核心代码(图为第一轮移动)
动图演示
for(i=0;i<size-1;i++){
for(j=0;j<size-i-1;j++){
if(arr[j]>arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
2.选择排序算法
选择排序算法的基本思想:每一趟在n-i+1(i=1,2,3…,n-1)个记录中选取关键字最小的记录与第i个记录交换,并作为有序序列中的第i个记录。
下面是算法的图解和核心代码(图为第一轮移动)
动图演示
for(i=0;i<size-1;i++)
{
for(j=i+1;j<size;j++)
{
if(arr[i]>arr[j])
{
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
}
3.插入排序算法
插入排序算法基本思想:讲一个记录插入到已经排好序的有序表中,从而得到一个新的,记录增加1的有序表。(图为第一轮移动)
动图演示
for(i=1; i<size; i++)
{
if(arr[i]<arr[i-1])
{
int temp=arr[i];
for(j=i-1; arr[j]>temp; j--)
{
arr[j+1]=arr[j];
}
arr[j+1]=temp;
}
}
4.希尔排序算法
希尔排序基本思想:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量为1,即所有记录放在同一组中进行直接插入排序为止。
希尔排序实际上就是分组插入排序
动图演示
int shell(int arr[100],int size)
{
int increment=size;
do
{
increment=increment/3+1;//调整每个比较的间隔
int i;
for(i=increment; i<size; i++)
{
if(arr[i]<arr[i-increment])//两个间隔点之间进行比较
{
int temp=arr[i];
int j;
for(j=i-increment; j>=0&&arr[j]>temp; j-=increment)//每次都进行交换
{
arr[j+increment]=arr[j];
}
arr[j+increment]=temp;
}
}
}
while(increment>1);
}
5.归并排序算法
归并排序算法基本思想:该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
动图演示
void merge(int arr[], int low, int mid, int high)
{
int i, k;
int *temp = (int *)malloc((high-low+1)*sizeof(int));
//申请空间,使其大小为两个
int left_low = low;
int left_high = mid;
int right_low = mid + 1;
int right_high = high;
for(k=0; left_low<=left_high && right_low<=right_high; k++) // 比较两个指针所指向的元素
{
if(arr[left_low]<=arr[right_low])
{
temp[k] = arr[left_low++];
}
else
{
temp[k] = arr[right_low++];
}
}
if(left_low <= left_high) //若第一个序列有剩余,直接复制出来粘到合并序列尾
{
for(i=left_low; i<=left_high; i++)
temp[k++] = arr[i];
}
if(right_low <= right_high)
{
//若第二个序列有剩余,直接复制出来粘到合并序列尾
for(i=right_low; i<=right_high; i++)
temp[k++] = arr[i];
}
for(i=0; i<high-low+1; i++)
arr[low+i] = temp[i];
free(temp);
return;
}
void merge_sort(int arr[], unsigned int first, unsigned int last)
{
int mid = 0;
if(first<last)
{
mid = (first+last)/2; /* 注意防止溢出 */
merge_sort(arr, first, mid);
merge_sort(arr, mid+1,last);
merge(arr,first,mid,last);
}
return;
}
6。快速排序
快速排序基本思想:通过一趟排序讲待排序记录分割成独立的两个部分,其中一部分记录的关键字均比另一部分记录的关键字小,则分别对两部分记录继续进行排序,达到整个序列有序的目的。
动图演示
void Swap(int *p, int *q)
{
int buf;
buf = *p;
*p = *q;
*q = buf;
return;
}
void QuickSort(int *a, int low, int high)
{
int i = low;
int j = high;
int key = a[low];
if (low >= high) //如果low >= high说明排序结束了
{
return ;
}
while (low < high) //该while循环结束一次表示比较了一轮
{
while (low < high && key <= a[high])
{
--high; //向前寻找
}
if (key > a[high])
{
Swap(&a[low], &a[high]);
++low;
}
while (low < high && key >= a[low])
{
++low; //向后寻找
}
if (key < a[low])
{
Swap(&a[low], &a[high]);
--high;
}
}
QuickSort(a, i, low-1); //用同样的方式对分出来的左边的部分进行同上的做法
QuickSort(a, low+1, j); //用同样的方式对分出来的右边的部分进行同上的做法
}
上述算法的时间复杂度进行比较:
排序方法 平均情况 最好情况 最坏情况 辅助空间 稳定性 冒泡排序
稳定 选择排序 稳定 插入排序 稳定 希尔排序 ~
不稳定 归并排序 稳定 快速排序 ~
不稳定