1. 基本概念
排序就是将一组对象按照规定的次序重新排列的过程, 排序往往是为检索服务的。
稳定性:相同键值两个记录在排序前后相对位置的变化情况。
相邻的元素进行比较的算法,如直接插入算法,冒泡排序,归并排序。
不相邻的元素进行比较的算法,如选择排序中的直接选择排序和堆排序以及快速排序。
内部排序:待排序的记录全部存放在计算机内存中进行的排序。
外部排序:待排序的记录数量很大,内存不能存储全部记录,需要对外存进行访问的排序过程
时间复杂度:通过 键值比较次数和记录移动次数来分析。
当记录基本有序时,插入排序和交换排序比较有效,直接插入和冒泡排序的时间复杂度都是O(n)
当待排记录数量较大时,选择排序比较有效。
2. 插入排序
直接插入排序: 依次将每个记录插入到一个已排好序的有序表中。不到最后一趟,都不能确定每个键值的最终位置。
时间复杂度:
void StarightInsertSort(List R, int n)
{
for (i=2;i<=n;i++)
{
R[0] = R[i];
j = i-1;
while (R[0].key < R[j].key)
{
R[j+1] = R[j];
j--;
}
R[j+1] = R[0];
} // end of for
}
3. 交换排序
基本思想
比较两个记录键值的大小,如果这两个记录键值的大小出现逆序,则交换这两个记录。
冒泡排序
void BubbleSort(List R,int n)
{ int i,j,temp,endsort;
for (i = 1; i<=n-1 ; i++)
{ endsort = 0;
for (j=1;j<=n-1;j++)
{
if(R[j].key>R[j+1].key)
{ temp = R[j];
R[j] = R[j+1];
R[j+1] = temp;
endsort = 1;
} // end of if
} // end of for
if (endsort == 0) break;
} // end of for
}
快速排序
// 快速排序
int QuickPartition(List R,int low,int high)
{ x = R[low];
while(low < high)
{
while ((low < high) && R[high].key >= x.key)) high--;
R[low] = R[high];
while ((low < high) && R[low].key <= x.key)) low++;
R[high] = R[low];
}
R[low] = x;
return low;
}
// 递归实现
void QuickSort(List R,int low,int high)
{ if (low
4. 选择排序
基本思想
每一次在n-i+1个记录中选取键值最小的记录,并和第i个记录交换。
直接选择
void SelectSort(List R,int n)
{ int min,i,j;
for (i = 1;i <= n-1; i++)
{ min = i;
for (j = i+1;j <= n; j++)
{
if (R[j].key < R[min].key) min = j;
if (min != i) swap(R[min],R[i]);
}
}
}
堆排序
自堆顶向下调整过程称为“筛选”。
时间复杂度 一共有n个结点,每次筛选会最多进行log2(n)次比较,O(n * log2(n))
归并排序
基本思想
要求待排序列是由若干个有序序列组成。
合并的方法是比较各子序列的第一个记录的键值,最小的一个就是排序后序列的第一个记录的键值。取出这个记录,继续比较各个子序列现有的第一个记录的键值,便可以找出排序后面的的第二个记录。
空间复杂度,由于要用到和待排记录等数量的数组b来存放结果,所以实现归并排序需要附加一倍的存储开销。
一共有log2(n)趟,每趟进行(n-区间数)次比较。O(比表达式阶级大或者相等的阶级)= O(n * log2(n))