目录
插入类排序思想:
对待排序的无序序列中的记录逐个进行处理,每一步将一个待排序的记录与已经排序的有序序列中的记录进行比较,然后插入到有序序列的合适位置,直到所有的待排序全部插入。
记录序列的数据类型
#define MAXSiZE 1000 //待排序的数目 typedef int keytype; typedef struct { keytype key; //关键字项 othertype other_data; //其他数据项 }RecordType; typedef struct { RecordType r[MASIZE+1]; int length; //序列长度 }RecordList; //记录序列类型,顺序表类型 RecordList L; //L为一个记录序列
直接插入排序
将r[0]设置为监视哨,最为一辅助空间,用于元素的位置交换,有备份待查记录和防止越界的作用。
待查记录与已排序的序列中的记录从后往前依次比较,找到比前一个记录大,比后一个记录小的位置直接插入。每一次在插入之后,原位置及之后的记录依次往后存入。
更适合于原始数据基本有序的情况。
void InsertSort(RecordList L) { //外层循环控制排序,第一个记录已经确定,从第2个记录开始判断与之前的记录排序 for(i=2;i<=L.length;i++) { if(L.r[i].key<L.r[i-1].key) { L.r[0]=L.r[i].key; //监视哨备份待查记录 //从待查记录位置开始依次从后往前比较,比较且满足条件的同时,记录往后移 for(j=i-1;L.r[0].key<L.r[j].key;j--) { L.r[j+1]=L.r[j]; //记录后移 } //退出循环条件,L.r[j].key小于 L.r[0].key的值 L.r[j+1]=L.r[0]; //插入正确位置 } } }
折半插入排序
通过折半查找找到待查记录在已排序的有序序列中插入的位置,然后再移动原该位置及之后的记录。
void BiInsertSort(RecordList L) { for(i=2;i<=L.length;i++) { if(L.r[i].key<L.r[i-1].key) { L.r[0]=L.r[i]; //折半查找,找到插入的位置 low=1; heigh=i-1; while(low<=heigh) { mid=(low+heigh)/2; if(L.r[low].key<L.r[mid].key) heigh=mid-1; else low=mid+1; } for(j=i-1;j>=low;j--) //从找到位置之后的元素从后往前后移 { L.r[j+1]=L.r[j]; } L.r[low]=L.r[0]; //插入正确的位置 } } }
希尔排序
希尔排序又称为“缩小增量排序”,算法思想为:先将整个待排元素序列分割成若干子序列(都以某个增量的元素隔开)然后分别进行直接插入排序,然后依次减少增减量,待整个学历中的元素基本有序(增量足够小,最小为1),再对全体元素进行直接插入排序。
其中增减量是以递减的方式进行选择,常用的是每次增量除以2递减的方法。(每次除以3递减也可以),希尔排序的执行时间很大程度上取决于增减量的选取。
void ShellInsert(RecordList L,int dk) { //注意:前dk个记录分别是dk个子序列的第一个记录,应该从每个子序列的第二个记录开始 //插入,所以是dk+1开始。 for(i=dk+1;i<=L.length;i++) { //判断是否满足排序的条件,小于上一个记录 if(L.r[i].key<L.r[i-dk].key) { L.r[0]=L.r[i]; //暂存待查入的记录 //注意:比较的是子序列中前面的所有记录,增量是dk。满足条件,之后的记录以增量后移 for(j=i-dk;j>0&&(L.r[0].key<L.r[j].key);j=j-dk) { L.r[j+dk]=L.r[j]; } //找到待插入的位置的条件是:大于子序列中前面的记录,小于后面的记录 L.r[j+dk]=L.r[0]; } } } //t为增量序列的长度 void ShellSort(RecordList L,int t) { //增量以每次除以2的方式递减 for(dk=L.Length/2;dk>=1;dk=dk/2) { ShellInsert(L,dk); } }
算法实现
算法实例:
#include<stdio.h> #define MAXSIZE 10 #define m 8 //序列中个数 typedef struct { int key; }Recordtype; typedef struct { Recordtype r[MAXSIZE]; int length; }RecordList; //========== 创建原始的序列 ========= RecordList Create_r() { RecordList L = { 0 }; int i; L.length = m; for (i = 0; i < MAXSIZE; i++) L.r[i].key = 0; printf("-----请输入待查序列-----\n"); for (i = 1; i <= L.length; i++) scanf("%d",&L.r[i].key); return L; } void Print(RecordList L); //========= 直接插入排序 ======== void InsertSort(RecordList L) { int i = 0, j = 0; for (i = 2; i <= L.length; i++) { if (L.r[i].key < L.r[i - 1].key) { L.r[0] = L.r[i]; for (j = i - 1;L.r[0].key < L.r[j].key; j--) L.r[j + 1] = L.r[j]; L.r[j + 1] = L.r[0]; } } Print(L); } //============= 折半插入排序 ========= void BiInsertSort(RecordList L) { int i = 0, j = 0,low=0,heigh=0,mid=0; for (i = 2; i <= L.length; i++) { if (L.r[i].key < L.r[i - 1].key) { L.r[0] = L.r[i]; heigh = i - 1; low = 1; while (low <= heigh) { mid = (low + heigh) / 2; if (L.r[0].key < L.r[mid].key) heigh = mid - 1; else low = mid + 1; } for (j = i - 1; j >= low; j--) L.r[j + 1] = L.r[j]; L.r[low] = L.r[0]; } } Print(L); } //=========== 希尔排序 ========= void ShellInsert(RecordList L,int dk) { int i = 0, j = 0; for (i = dk + 1; i <= L.length; i++) { if (L.r[i].key < L.r[i - dk].key) { L.r[0] = L.r[i]; for (j = i - dk; j > 0 && (L.r[0].key < L.r[j].key); j = j - dk) L.r[j + dk] = L.r[j]; L.r[j + dk] = L.r[0]; } } if(dk==1) Print(L); } //------ 计算希尔排序中的增减量 ----- void ShellSort(RecordList L) { int dk = 0; for (dk = L.length / 2; dk >= 1; dk = dk / 2) ShellInsert(L, dk); } //====== 打印排序后的序列 ========= void Print(RecordList L) { for (int i = 1; i <= L.length; i++) printf("%d ", L.r[i].key); printf("\n"); } main() { RecordList L=Create_r(); printf("====================== 直接插入排序 =====\n"); InsertSort(L); printf("====================== 折半插入排序 =====\n"); BiInsertSort(L); printf("====================== 希尔排序 =====\n"); ShellSort(L); }