common.h
#ifndef _COMMON_H_
#define _COMMON_H_
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
//Status Equal(int a, int b);
#endif
SqList.h
#ifndef _SQLIST_H_
#define _SQLIST_H_
#include "common.h"
#include "Sorting.h"
Status PrintElement(ElemType e);
Status InitList_Sq(SqList *L);
Status ListScanf_Sq(SqList *L);
Status Traverse(SqList *L, Status (* Visit)(ElemType e));
#endif
#ifndef _SORTING_H_
#define _SORTING_H_
#define MAXSIZE 10 //顺序表的最大长度
typedef int KeyType;
typedef char Name[20];
typedef int Score;
typedef struct
{
KeyType key; //关键字项
Name name;
Score score;
}RecordType; //记录类型
typedef struct
{
RecordType r[MAXSIZE+1]; //r[0]闲置或用作哨兵单元
int length; //顺序表长度
}SqList; //顺序表类型
#define ElemType RecordType //为了保持与以前写得程序的命名一致性,所以作此宏定义,其实完全也可以直接使用RecordType
//有的时候想要用到别的工程的一段代码,在将别的工程代码移植过来时,常常需要修改一些东西,有没有什么办法可以让少做修改(甚至不修改)而直接应用。
//对两个关键字的比较约定为如下的宏定义
//>>>对数值型关键字
#define EQ(a,b) ((a) == (b))
#define LT(a,b) ((a) < (b))
#define LQ(a,b) ((a) <= (b))
//...
//>>>对字符串型关键字
//#define EQ(a,b) (!strcmp((a),(b)))
//#define LT(a,b) (strcmp((a),(b))<0)
//#define LQ(a,b) (strcmp((a),(b))<=0)
//...
#endif
#include "common.h"
#include "Sorting.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
Status PrintElement(ElemType e)
{
printf("%-3d ",e.key);
printf("%-16s ",e.name); //16个字符长度是我随便定义的,当然可以改变之。
printf("%-3d\n",e.score);
return OK;
}
Status InitList_Sq(SqList *L)
{
L->length = MAXSIZE + 1; //顺序表的最大长度虽然为MAXSIZE+1,但其第一个单元式闲置的,实际只用到了MAXSIZE个单元。
return OK;
}
//说明:若想让程序具有较好的健壮性,则应当还应加入一些判定输入数据是否超出预定范围或者是否非法的判定条件,但这里都还没有。
Status ListScanf_Sq(SqList *L)
{
SqList *p = L;
int i = 1; //让i从1开始是为了让表的0号单元留空。
KeyType num;
Score sco;
Name name;
if(p == NULL)
{
return ERROR;
}
scanf("%d",&num);
if(num<0 || num>32767)
return ERROR;
while(num)
{
scanf("%s",name);
scanf("%d",&sco);
p->r[i].key = num;
strcpy(p->r[i].name, name);
p->r[i].score = sco;
scanf("%d",&num);
if(i++ > p->length)
{
printf("Search Table is full.");
return(OVERFLOW);
}
}
return OK;
}
Status Traverse(SqList *L, Status (* Visit)(ElemType e))
{
int i = 1; //查找表的0号单元被留空
printf("\n>>>>>>>>>>>>>>>>>output start>>>>>>>>>>>>>>>>>\n");
while(L->r[i].key>0 && L->r[i].key<32767 && i<L->length) //32767是int型数的最大值,当然实际应用应根据实际情况采取适当限定措施。
{
Visit(L->r[i]);
i++;
}
printf("\n>>>>>>>>>>>>>>>>>output end>>>>>>>>>>>>>>>>>\n\n");
return OK;
}
Sorting.c
#include "common.h"
#include "Sorting.h"
//直接插入排序
Status StrInsertSort(SqList *L)
{
int i,j;
for(i=2; i<=L->length; ++i)
{
//这个判断是因为:有的时候虽然定义了顺序表的最大长度,但并没有存入那么多的记录进去,这时候如果光靠for循环中i<=L->length条件来判断是不行的。所以这里加入了下面的这个判断条件。
if(L->r[i].key>0 && L->r[i].key<32767)
{
if(LT(L->r[i].key, L->r[i-1].key)) //如果左参数小于右参数
{
L->r[0] = L->r[i]; //复制为哨兵
L->r[i] = L->r[i-1];
for(j=i-2; LT(L->r[0].key, L->r[j].key); --j)
L->r[j+1] = L->r[j];
L->r[j+1] = L->r[0];
}
}
}
return OK;
}
//拆半插入排序
Status BinInsertSort(SqList *L)
{
int i, j, middle, low, high;
for(i=2; i<=L->length; ++i)
{
//加入这个判断的原因同“直接插入排序StrInsertSort()”
if(L->r[i].key>0 && L->r[i].key<32767)
{
L->r[0] = L->r[i]; //将L->r[i]暂存到L->r[0]
low = 1;
high = i - 1;
//在r[low..high]中拆半查找有序插入的位置
while(low <= high)
{
middle = (low + high)/2; //拆半
if(LT(L->r[0].key, L->r[middle].key))
high = middle - 1; //插入点在低半区
else
low = middle + 1; //插入点在高半区
}
//记录后移
for(j=i-1; j>=high+1; --j)
L->r[j+1] = L->r[j];
L->r[high+1] = L->r[0]; //插入
}
}
return OK;
}
main.c
#include "Sorting.h"
#include "SqList.h"
#include "stdio.h"
void main(void)
{
SqList list;
InitList_Sq(&list);
ListScanf_Sq(&list);
Traverse(&list, PrintElement);
//printf("StrInsertSort");
//StrInsertSort(&list);
//Traverse(&list, PrintElement);
printf("BinInsertSort");
BinInsertSort(&list);
Traverse(&list, PrintElement);
}