第一章基本概念
1.1算法:是一组完成特定任务的有穷指令序列。它必须满足输入,输出,确定性,有限性,有效性。
1.1.1选择排序:假定要设计一个程序,把n个整数排序,其中n>=1.下面给出一个简单的解决方案:
从未被排序的整数中找出最小的整数,将其放在已排序整数列表中的下一个位置。
#include<stdio.h>
#include<math.h>
#define MAX_SIZE 101
#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t))
void sort(int [],int);/*定义选择排序*/
void main(void)
{
int i,n;
int list[MAX_SIZE]; //定义表长
printf("Enter the number of numbers to generate: ");
scanf("%d",&n); //输入n
if(n<1||n>MAX_SIZE){
fprintf(stderr,"Improper value of n\n");//打印输出到stderr文件
exit(1); //非正常运行导致退出程序
}//判断n是否超过表长或者小于表长
for(i=0;i<n;i++){/*随机生成数字*/
list[i]=rand()%1000;
printf("%d",list[i]);//输出i的表长
}
sort(list,n); //调用函数
printf("\n Sorted array:\n");
for(i=0;i<n;i++)/*打印出排序的数字*/
printf("%d",list[i]);
printf("\n");
}
void sort(int list[],int n){
int i,j,min,temp;
for(i=0;i<n-1;i++){
min=i;/*已排序*/
for(j=i+1;j<n;j++)
if(list[j]<list[min])
min=j;/*已排序和未排序比较*/
SWAP(list[i],list[min],temp);/*调用宏定义*/
}
}
1.1.2折半查找
(1)查找排序数组
while(有更多整数要检查){
middle=(left+right)/2;//中间位置
if(searchsum<list[middle])
right=middle-1;
else if(searchnum==list[middle])
return middle;
else left=middle+1;
}
(2)比较二个整数
int compare(int x,int y)
{
/*比较x和y,x小于y返回-1,x等于y返回0,x大于y返回1*/
if(x<y) return -1;
else if(x==y) return 0;
else return 1;
}
(3)查找已排序数组
int binsearch(int list[],int searchnum,int left,int right)
{
/*search list[0]<=list[1]<=...<=list[n-1] for searchnum.如果发现返回它的位置。其他的返回-1*/
int middle;
while(left<=right){
middle=(left+right)/2;//之间值
switch(COMPARE(list[middle],searchnum)){//跟之间值比较
case -1:left=middle+1;
break;
case 0:return middle;
case 1:right=middle-1;
}
}
return -1;
}
1.1.3递归算法
(1).折半查找的递归实现
int binsearch(int list[],int searchnum,int left,int right)
{
/*search list[0]<=list[1]<=...<=list[n-1] for searchnum.如果找到返回它的位置,否则返回-1*/
int middle;
if(left<=right){
middle=(left+right)/2;
switch(COMPARE(list[middle],searchnum)){
case -1:return binsearch(list,searchnum,middle+1,right);
case 0:return middle;
case 1:return binsearch(list,searchnum,left,middle-1);
}
}
return -1;
}
(2).递归的全排列产生算法
void perm(char *list,int i,int n)
/*生成list[i]到list[n]的置换*/
{
int j,temp;
if(i==n){
for(j=0;j<=n;j++)
printf("%c",list[j]);
printf(" ");
}
else{
/*list[i]到list[n]有多种置换,生成这些递归*/
for(j=i;j<=n;j++){
SWAP(list[i],list[j],temp);
perm(list,i+1;n);
SWAP(list[i],list[j],temp);
}
}
}
用三个元素的集合{a,b,c}来拷贝。可以知道,每次递归调用perm都将产生参数list,i和n的一个新的本地拷贝,且i的值随调用值而不断变化,而n值是不变的。参数list是一个指向数据的指针,其值也不变。
1.2数据抽象
数据类型:是一个对象集合和一组在这些对象上的操作的总称。
抽象数据型:是一个数据类型,其数据对象和对象上操作的规格说明独立于对象的存储表示和对象上操作的实现。
1.3算法的性能分析
(1)程序的空间复杂度是程序从开始执行到完成所需的存储空间的数量,空间复杂度有固定的空间需求和可变的空间需求。
(2)程序的时间复杂度是程序从开始执行到完成所需的计算时间。
(3)一个程序步是一个在语法或语义上有意义的程序片断,该程序段的执行时间与程序的实例特征无关。
例子1:一个魔方就是一个由1到n*n的整数构成的n*m矩阵,其中每行,每列以及两个主对角线上的数字之和都相等。
思路:把1放入第一行最中间的方格中。向左上方移动,并按照数字的递增顺序,把数字填入空方格。如果移出魔方(即越过了魔方的边界),则进入魔方对边的对应方格。继续填入方格。如果一个方格已被填入数字,则向下继续填入方格。
#include<stdio.h>
#define MAX_SIZE 15 /*maximun size of square*/
void main(void)
/*construct a magic square,iteratively*/
{
static int square[MAX_SIZE][MAX_SIZE];
int i,j,row,column;/*indices*/
int count;/*counter*/
int size;/*Square size*/
printf("Enter the size of the square: ");
scanf("%d",&size);
/*check for input errors*/
if(size<1||size>MAX_SIZE){
fprintf(stderr,"Error! Size is out of range\n");
exit(1);
}
if(!(size%2)){
fprintf(stderr,"Error! Size is even\n");
exit(1);
}
for(i=0;i<size;i++)
for(j=0;j<size;j++)
square[i][j]=0;
square[0][(size-1)/2]=1;/*middle of first row*/
/* i and j are current position*/
i=0;
j=(size-1)/2;
for(count=2;count<=size*size;count++){
row=(i-1<0)?(size-1):(i-1);/*up*/
colum=(j-1<0)?(size-1):(j-1);/*left*/
if(square[row][column]) /*down*/
i=(++i)%size;
else{ /*square is unoccupied*/
i=row;
j=(j-1<0)?(size-1):--j;
}
square[i][j]=count;
}
/*output the magic square*/
printf("Magic Square of size %d: \n\n",size);
for(i=0;i<size;i++){
for(j=0;j<size;j++)
printf("%5d",square[i][j]);
printf("\n");
}
printf("\n\n");
}
它的渐进复杂性是n*n;