1.插入排序
对于插入排序,插入排序的工作方式就像排序扑克牌,开始时,我们左手为空且桌子上牌面向下。然后每次我们抓取一张牌并将他插入到正确的位置。为了找到一张牌的正确位置,我们从右到左将它与已在手中的每张牌作比较。拿在手上的牌总是排序好的,原来这些牌是处于桌子上牌堆顶部的牌。
按照上述描述伪代码为:
INSERTION-SORT(A)
for j = 2 to A.length
key = A[j]
//Insert A[j] into the sorted sequence A[1...j - 1]
i = j - 1
while i > 0 and A[i] > key
A[i + 1] = A[i]
i = i - 1
A[i + 1] = key
实现C代码
#include<stdio.h>
int a[10005];
int main(){
int n;
scanf("%d",&n);
int key;
for(int i = 1;i <= n;i++)scanf("%d",&a[i]);
for(int j = 2;j <= n;j++){
key = a[j];
int i = j - 1;
while(i > 0 && a[i] > key){
a[i + 1] = a[i];
i = i - 1;
}
a[i + 1] = key;
}
for(int k = 1;k <= n;k++)printf("%d ",a[k]);
}
最坏情况和平均情况分析
我们往往集中于最坏运行时间,即对规模为n的任何输入,算法的最长运行时间:
- 一个算法的最坏情况的运行时间给出了任何运行输出的一个上界。
- 对于某些算法,最坏情况经常出现。
- 平均情况往往与最坏情况大致一样差。
对于插入排序,当我们忽略低阶项和最重要的项的常系数时,只剩下n^2记作o(n^2)。
2.分治法
分治算法的思想:将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后再合并这些子问题的解来建立原问题的解。
分治每层递归三个步骤:
- 分解原问题。
- 解决子问题,到足够小时直接求解。
- 合并这些子问题的解成原问题的解。
以典型的分治法归并排序直观理解就是:
- 分解:将待排序的n个元素分解成两个n/2的子序列。
- 解决:使用归并排序递归地排序两个子序列。
- 合并:将两个已排序的子序列合并产生已排序的答案。
伪代码:
MERGE(A,p,q,r)
n1 = q - p + 1
n2 = r - q
let L[1...n1 + 1] and R[1...n2 + 1] be new arrays
for i = 1 to n1
L[i] = A[p + i - 1]
for j = 1 to n2
R[j] = A[p + j]
L[n1 + 1] = ∞
R[n2 + 1] = ∞
i = 1
j = 1
for k = p to r
if L[i] <= R[j]
A[k] = L[i]
i = i + 1
else A[k] = R[j]
j = j + 1
具体C代码实现如下:
#include <stdio.h>
int temp[100001];
long long merge(int b[],int left,int right){
int mid= (left + right)/2;
if(left >= right){
return 0;
}
if(left < right){
long long x = merge(b,left,mid);
long long y = merge(b,mid + 1,right);
int i, j, k;
long long count = 0;
for(i = left, j = mid + 1, k = left;i <= mid && j <= right && k <= right; k++){
if(b[i] <= b[j]){
temp[k] = b[i++];
}
else if(b[i] > b[j]){
temp[k] = b[j++];
count = count - i + 1 + mid;
}
}
while(i <= mid){
temp[k++] = b[i++];
}
while(j <= right){
temp[k++] = b[j++];
}
for(i = left;i <= right;i++){
b[i] = temp[i];
}
return count + x + y;
}
}
int main(){
int x;
scanf("%d",&x);
int a[100001];
int len;
for(len = 0;len < x;len++){
scanf("%d",&a[len]);
}
printf("%lld",merge(a,0,x-1));//逆序对个数
for(int k = 0;k < n;k++)printf("%d ",temp[k]);//输出排序
}
测试数据:
5
5 4 3 2 1
归并算法分析:
时间复杂度o(nlgn)