假设含n个记录的序列为{ R1, R2, …, Rn }其相应的关键字序列为 { K1,K2, …,Kn }。经过排序确定一种排列{ Rp1≤Rp2≤…≤Rpn},使得它们的关键码满足如下递增或递减的关系 Kp1≤ Kp2 ≤…≤ Kpn 或 Kp1≤ Kp2 ≤…≤ Kpn 。
内部排序:指代排序记录全部存放在内存中进行排序的过程。
外部排序:指待排序的记录数量很大,以至于内存不能容纳全部全部记录,在排序过程中需要对外存进行访问的排序过程。
(1)比较两个关键码的大小
(2)将记录从一个位置移到另一个位置
整个排序过程为n-1趟插入,即先将序列中第1个记录看成是一个有序子序列,然后从第2个记录开始,逐个进行插入,直至整个序列有序。
void insertSort(int data[], int n)
//将data[0] - data[n-1]的n个整数按非递减有有序的方式进行排列
{
int i, j;
int temp;
for (i = 1; i < n; i++) {
if (data[i] < data[i - 1]) {
temp = data[i];
data[i] = data[i - 1];
for (j = i - 2; j >= 0 && data[i] > temp; j--) {
data[j + 1] = data[j];
data[j + 1] = temp;
}
}
}
}
时间复杂度:T(n)=O(n²)
空间复杂度:S(n)=O(1)
若待排序记录按关键字从小到大排列(正序)
关键字比较次数:n-1
记录移动次数:2(n-1)
若待排序记录按关键字从大到小排列(逆序)
关键字比较次数:(n+2)(n-1)/2
记录移动次数:(n+4)(n-1)/2
若待排序记录是随机的,取平均值
关键字比较次数:n2/4
记录移动次数:n2/4
(1)将第一个记录的关键字与第二个记录的关键字进行比较,若为逆序 r[1].key > r[2].key ,则交换;然后比较第二个记录与第三个记录;依次类推,直至第n-1个记录和第n个记录比较为止——第一趟冒泡排序,结果关键字最大的记录被安置在最后一个记录上
(2)对前n-1个记录进行第二趟冒泡排序,结果使关键字次大的记录被安置在第n-1个记录位置
(3)重复上述过程,直到“在一趟排序过程中没有进行过交换记录的操作”为止
void bubbleSort(int data[], int n)
//将data[0] - data[n-1]的n个整数按非递减有有序的方式进行排列
{
int i, j, tag = 1; //用tag表示排序过程中是否交换过元素值
int temp;
for (i = 1; tag&&i < n; i++) { //i用于计算躺输,最多n-1趟
tag = 0;
for (j = 0; j < n - i; j++) {
temp = data[j];
data[j] = data[j + 1];
data[j + 1] = temp;
tag = 1;
}
}
}
时间复杂度:T(n)=O(n²)
空间复杂度:S(n)=O(1)
最好情况(正序)
比较次数:n-1
移动次数:0
最坏情况(逆序)
比较次数:1/2(n2-n)
移动次数:3/2(n2-n)
冒泡排序是一种稳定的排序方法。
(1)首先通过n-1次关键字比较,从n个记录中找出关键字最小的记录,将它与第一个记录交换
(2)再通过n-2次比较,从剩余的n-1个记录中找出关键字次小的记录,将它与第二个记录交换
(3)重复上述操作,共进行n-1趟排序后,排序结束
void selectSort(int data[], int n)
//将data[0] - data[n-1]的n个整数按非递减有有序的方式进行排列
{
int i,j,k;
int temp;
for (i = 0; i < n-1; i++) {
k = i;
for (j = i + 1; j < n; j++) //找出最小元素的下标
if (data[j] < data[k])
k = j;
if (k != j) {
temp = data[i];
data[i] = data[k];
data[k] = temp;
}
}
}
时间复杂度:T(n)=O(n²)
空间复杂度:S(n)=O(1)
记录移动次数
最好情况:0
最坏情况:3(n-1)
比较次数:n(n-1)/2
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
int partition(int data[], int low, int high)
//用data[low]的值作为枢轴元素pivot进行划分
//使得data[low…i-1]均不大于pivot,data[i+1…high]均不小于pivot
{
int i, j;
int pivot;
pivot = data[low];
i = low;
j = high;
while (i < j) { //从数组的两端交替地向中间扫描
while (i < j&&data[j] >= pivot)j--;
data[i] = data[j]; //比枢轴元素小者向前移
while (i < j&&data[i] <= pivot)i++;
data[j] = data[i]; //比枢轴元素大者向后移
}
data[i] = pivot;
return i; //返回枢轴元素的位置
}
void quickSort(int data[], int low,int high)
//用快速排序方法对整型数组进行非递减排序
{
if (low < high) {
int loc = partition(data, low, high); //进行划分
quicksort(data, low, i - 1); //对前半区进行快速排序
quicksort(data, i + 1, high); //对后半区进行快速排序
}
}
时间复杂度
空间复杂度:需栈空间以实现递归
归并——将两个或两个以上的有序表组合成一个新的有序表,叫归并排序。
排序过程:设初始序列含有n个记录,则可看成n个有序的子序列,每个子序列长度为1两两合并,得到 n/2 个长度为2或1的有序子序列再两两合并,……如此重复,直至得到一个长度为n的有序序列为止。
void merge(int data[], int low, int mid, int high)
//将有序子序列data[low…mid-1]和data[mid…high]归并为有序序列data[low…high】
{
int i,p , k;
int *tmp;
tmp =(int*)malloc((high - low + 1) * sizeof(int));
if (!tmp)
exit(0);
k = 0;
for (i = low, p = mid; i < mid &&p <= high;)
if (data[i] < data[p])
tmp[k++] = data[i++];
else
tmp[k++] = data[p++];
while (i < mid)
tmp[k++] = data[i++];
while (p <= high)
tmp[k++] = data[p++];
i = low;
p = 0;
while (p < k)
data[i++] = tmp[p++];
}
void mergeSort(int data[], int s, int t) //对data[s…t]进行归并排序
{
int m;
if (s < t) {
m = (s + t) / 2; //将data[s…t]均分为data[s…m]和data[m+1…t]
mergeSort(data, s, m); //递归地对data[s…m]进行归并排序
mergeSort(data, m + 1, t); //递归地对data[m+1…t]进行归并排序
merge(data, s, m + 1, t); //将data[s…m]和data[m+1…t]归并为data[s…t]
}
}
时间复杂度:O(nlog2n)。
空间复杂度: O(n)。
归并排序是一种稳定的排序方法。