数据结构-08排序算法
01直接插入排序
算法思想: 每次将一个待排序的记录按照关键字大小插入到前面已排好序的子序列,直到全部记录插入即可。
#include<iostream>
using namespace std;
void InsertSort(int arr[], int len){
int i, j, temp; // 定义临时指针i,j,以及中间变量temp
for(i=1; i<len; i++){ // 默认第一个位置已经确定,从第二个元素开始
if(arr[i]<arr[i-1]){ // 若a[i]关键字小于前驱,则向前移动当前元素位置
temp = arr[i]; // 用temp暂存A[i]
for(j=i-1; arr[j]>temp&&j>=0; j--){ // 检查前面的元素,将大于temp的元素后移
arr[j+1] = arr[j];
}
arr[j+1] = temp; // 将temp复制到插入位置
}
}
}
算法分析:
空间复杂度:O(1)
时间复杂度:
最好:O(n) 所有元素都已经排好序,每个元素仅比较一次(共n-1次)
最坏:O(n2) 所有元素均为逆序,移动元素次数1+2+3+…+n-1
平均:O(n2))
稳定性:稳定。
适用性:顺序存储和链式存储的线性表
02 折半插入排序
算法思想: 对于查找待排序元素(当前元素)的待插入位置的算法从顺序查找变为了折半查找。
算法实现:
#include <stdio.h>
void InsertSort(int arr[], int len){
int i,j,temp,low,high,mid;
for(i=1;i<len;i++){
if(arr[i]<arr[i-1]){ // 若a[i]关键字小于前驱,则向前移动当前元素位置
temp = arr[i]; // 用temp暂存arr[i]
low=0;high=i-1; // 定义折半查找的范围
while(low<=high){ // 按照递增排序, 否则就是high=0,low=i-1
mid=(low+high)/2; // 取中间点
if(arr[mid]>temp)
high = mid-1; // 查找左子表
else
low = mid+1; // 查找右子表
}
for(j=i-1;j>=low;j--){
arr[j+1] = arr[j]; // 统一后移元素,空出插入位置
}
arr[j+1] = temp; // 插入元素
}
}
}
算法分析
空间复杂度:O(1)
时间复杂度:
最好:O(n) 所有元素都已经排好序,每个元素仅比较一次(共n-1次)
最坏:O(n2) 所有元素均为逆序,移动元素次数1+2+3+…+n-1
平均:O(n2))
稳定性:稳定
适用性:顺序存储的线性表。(折半查找要求查找表具有随机访问特性)
03 希尔排序
算法思想: 准备一组增量dk[], 按照增量每次将数据元素分为若干子表,这里的dk逐轮减小
如表1为,arr[0],arr[dk],arr[dk+dk]…,表2为:arr[1],arr[1+dk],arr[1+2*dk]…以此类推
如此,对每个子表进行排序,最后一次的dk值一定为1,此时相当于对查找表进行一次直接插入排序。
算法实现
#include<stdio.h>
void ShellSort(int arr[], int len){
int i,j,temp,dk=len;
while(true){
dk = dk/2;
if(dk==0) break;
for(i=dk;i<len;i++){ // 下标i从dk开始,对应每次子表的第二个元素
if(arr[i]<arr[i-dk]){ // 若当前元素小于前驱,则将前驱元素后移
temp = arr[i];
for(j=i-dk;j>=0&&arr[j]>temp;j-=dk){ // 这里只需将子表中的元素间隔后移即可
arr[j+dk] = arr[j];
}
arr[j+dk] = temp;
}
}
}
}
手动模拟:
算法分析:
空间复杂度:O(1)
时间复杂度:
最好:O(n1.3)
最坏:O(n2)
平均:O(n2))
稳定性:不稳定
适用性:顺序存储的线性表