插入排序InsertSort的三种实现方式及循环不变式的使用
2012-03-08 21:48
387 查看
一、循环不变式的概念:
在循环结构设计中,核心设计就是找到循环结构中循环不变式(loop invariant);
方法是找中间的一个普通循环迭代,同时保证满足边界条件(edge case)。
循环不变式满足的三个条件:
1. 初始化: 在初始化状态下,循环不变式保持某种性质。
2.保持性: 循环不变式的性质,在迭代的同时能够保持。
3.终止性: 循环不变式终止时,能够保证某种状态成立。
二、插入排序 (InsertSort)
插入排序:使用一种增量(incremental)求解的方法,在排好序的数组a[0...j-1]中,将元素a[j]插入,形成有序数组a[0...j];
插入排序算法具有循环不变式的性质:
1. 初始化: 仅有一个元素的数组a[0] ,是个排好序的数组。
2. 保持:排好序的数组a[0...j-1], 插入元素a[j],形成新的有序数组a[0...j].
3, 终止: a[0...len] 形成一个有序数组。 目的达到。
下面给出插入排序(insertSort)的三种实现方式, 均采用就地排序(sort in place)的方式:
代码如下:
#include <stdio.h>
#include <stdlib.h>
void printArray(int* a, int len);
int binarySearch(int* a, int low, int high, int key);
int modifiedBinarySearch(int* a, int low, int high, int key);
int selectLocate(int* a, int len, int key);
void insertSort(int * a, int len);
void locateInsertSort(int* a, int len);
void binarySearchInsertSort(int *a, int len);
int main(int argc, char* argv[]) {
int a[9] = {5,4,3,3,3,3,2,1,3};
int len =9;
//insertSort(a, len);
//locateInsertSort(a, len);
binarySearchInsertSort(a, len);
printArray(a, len);
return 0;
}
void printArray(int* a, int len) {
int i;
for(i=0; i<len; i++) {
printf("%d\t", *(a+i));
}
printf("\n");
}
void insertSort(int * a, int len) {
int i;
int j;
int key;
for(i=0; i<len-1; i++) {
key= a[i+1];
for(j=i; j>=0 && key<a[j]; j--) {
a[j+1] = a[j];
}
if(j!=i) {
a[j+1] = key;
}
}
}
void locateInsertSort(int *a, int len) {
int i;
int j;
int k;
int key;
for(i=0; i<len-1; i++) {
key = a[i+1];
k = selectLocate(a, i+1, key);
for(j=i; j>=k; j--) {
a[j+1] = a[j];
}
if(k<=i) a[k] = key;
}
}
void binarySearchInsertSort(int *a, int len) {
int i;
int j;
int k;
int key;
for(i=0; i<len-1; i++) {
key = a[i+1];
k = modifiedBinarySearch(a, 0, i, key);
for(j=i; j>=k; j--) {
a[j+1] = a[j];
}
if(k<=i) a[k] = key;
}
}
int selectLocate(int* a, int len, int key) {
int i;
for(i=len-1; i>=0 && key<a[i]; i--);
return i+1;
}
int binarySearch(int *a, int low, int high, int key) {
int mid;
while(low <= high) {
mid = (low + high) >> 1;
if(key<a[mid]) {
high = mid -1;
}
else if(key>a[mid]) {
low = mid + 1;
}
else {
return mid;
}
}
return -1;
}
int modifiedBinarySearch(int *a, int low, int high, int key) {
int mid;
int top = high;
int bottom = low;
while(low <= high) {
mid = (low + high) >> 1;
if(key<a[mid]) {
high = mid -1;
}
else if(key>a[mid]) {
low = mid + 1;
}
else {
break;
}
}
/*
if(low<=high) {
while(mid<=top && a[mid]==key) mid++;
return mid;
}
*/
if(key>=a[mid]) {
while(mid<=top && key>a[mid]) mid++;
return mid;
}
if(key<a[mid]) {
while(mid>=bottom && key<a[mid]) mid--;
return mid+1;
}
}
三、总结,以上算法的实现参考了《算法导论》中的第二章。并对习题中将折半查找算法整合到insertSort中。
在循环结构设计中,核心设计就是找到循环结构中循环不变式(loop invariant);
方法是找中间的一个普通循环迭代,同时保证满足边界条件(edge case)。
循环不变式满足的三个条件:
1. 初始化: 在初始化状态下,循环不变式保持某种性质。
2.保持性: 循环不变式的性质,在迭代的同时能够保持。
3.终止性: 循环不变式终止时,能够保证某种状态成立。
二、插入排序 (InsertSort)
插入排序:使用一种增量(incremental)求解的方法,在排好序的数组a[0...j-1]中,将元素a[j]插入,形成有序数组a[0...j];
插入排序算法具有循环不变式的性质:
1. 初始化: 仅有一个元素的数组a[0] ,是个排好序的数组。
2. 保持:排好序的数组a[0...j-1], 插入元素a[j],形成新的有序数组a[0...j].
3, 终止: a[0...len] 形成一个有序数组。 目的达到。
下面给出插入排序(insertSort)的三种实现方式, 均采用就地排序(sort in place)的方式:
代码如下:
#include <stdio.h>
#include <stdlib.h>
void printArray(int* a, int len);
int binarySearch(int* a, int low, int high, int key);
int modifiedBinarySearch(int* a, int low, int high, int key);
int selectLocate(int* a, int len, int key);
void insertSort(int * a, int len);
void locateInsertSort(int* a, int len);
void binarySearchInsertSort(int *a, int len);
int main(int argc, char* argv[]) {
int a[9] = {5,4,3,3,3,3,2,1,3};
int len =9;
//insertSort(a, len);
//locateInsertSort(a, len);
binarySearchInsertSort(a, len);
printArray(a, len);
return 0;
}
void printArray(int* a, int len) {
int i;
for(i=0; i<len; i++) {
printf("%d\t", *(a+i));
}
printf("\n");
}
void insertSort(int * a, int len) {
int i;
int j;
int key;
for(i=0; i<len-1; i++) {
key= a[i+1];
for(j=i; j>=0 && key<a[j]; j--) {
a[j+1] = a[j];
}
if(j!=i) {
a[j+1] = key;
}
}
}
void locateInsertSort(int *a, int len) {
int i;
int j;
int k;
int key;
for(i=0; i<len-1; i++) {
key = a[i+1];
k = selectLocate(a, i+1, key);
for(j=i; j>=k; j--) {
a[j+1] = a[j];
}
if(k<=i) a[k] = key;
}
}
void binarySearchInsertSort(int *a, int len) {
int i;
int j;
int k;
int key;
for(i=0; i<len-1; i++) {
key = a[i+1];
k = modifiedBinarySearch(a, 0, i, key);
for(j=i; j>=k; j--) {
a[j+1] = a[j];
}
if(k<=i) a[k] = key;
}
}
int selectLocate(int* a, int len, int key) {
int i;
for(i=len-1; i>=0 && key<a[i]; i--);
return i+1;
}
int binarySearch(int *a, int low, int high, int key) {
int mid;
while(low <= high) {
mid = (low + high) >> 1;
if(key<a[mid]) {
high = mid -1;
}
else if(key>a[mid]) {
low = mid + 1;
}
else {
return mid;
}
}
return -1;
}
int modifiedBinarySearch(int *a, int low, int high, int key) {
int mid;
int top = high;
int bottom = low;
while(low <= high) {
mid = (low + high) >> 1;
if(key<a[mid]) {
high = mid -1;
}
else if(key>a[mid]) {
low = mid + 1;
}
else {
break;
}
}
/*
if(low<=high) {
while(mid<=top && a[mid]==key) mid++;
return mid;
}
*/
if(key>=a[mid]) {
while(mid<=top && key>a[mid]) mid++;
return mid;
}
if(key<a[mid]) {
while(mid>=bottom && key<a[mid]) mid--;
return mid+1;
}
}
三、总结,以上算法的实现参考了《算法导论》中的第二章。并对习题中将折半查找算法整合到insertSort中。
相关文章推荐
- 使用 Python 实现文件递归遍历的三种方式
- JAVA多线程实现的三种方式(继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程)
- iOS项目开发实战——使用三种方式实现页面跳转与参数传递(三)
- SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论 SignalR 简单示例 通过三个DEMO学会SignalR的三种实现方式 SignalR推送框架两个项目永久连接通讯使用 SignalR 集线器简单实例2 用SignalR创建实时永久长连接异步网络应用程序
- iOS项目开发实战——使用三种方式实现页面跳转与参数传递(一)
- Tomcat实现session保持的三种方式、使用msm方式搭建jsp网站
- 使用Vue实现图片上传的三种方式
- 绑定Service的三种实现方式之使用Messenger
- 在 unity 中使用三种简单的方式实现实时时钟动画
- 三种 bottom half的实现方式 softirqs, tasklets, work queue 及之间的比较 ,驱动程序使用tasklet机制
- 冒泡排序C#实现,使用委托,包括三种方式:Fun<>,匿名方法,Lambda表达式
- 绑定Service的三种实现方式之使用AIDL
- mybatis一对一的三种实现方式 数据准备: 使用mysql数据库作为测试。建表语句及测试数据: CREATE TABLE `classes` ( `class_id` int(11) NOT
- 绑定Service的三种实现方式之使用AIDL
- java使用递归,非递归方式实现二叉树的三种常见遍历方式
- delphi使用消息传递字符串有三种方式可以实现
- jQuery自动补全autocomplete插件使用,三种获取数据源方式具体实现(true)
- 使用Lock,wait/notify,Semaphore三种方式实现多线程通信
- iOS项目开发实战——使用三种方式实现页面跳转与参数传递(二)