main.c
#include <stdio.h>
#include <stdlib.h>
#include<time.h>
#include"arrayCalculator.h"
/*
int arrayLength=10;
int numsPerline=5;
char splitChar='\t';
*/
int main()
{
int a[arrayLength];
int ch;
char ch1;
while(1)
{
printMenu();
printf("请选择菜单序号:");
scanf("%d",&ch);
clearCache();
if(ch==0)break;
switch(ch)
{
case 1://配置系统参数
printf("请输入配置数值[数组长度 每行打印个数 元素分隔符]:");
struct configVar cv;
scanf("%d %d %c",&cv.arrayLength,&cv.numsPerline,&cv.splitChar);
void config(struct configVar cv);//配置全局参数
clearCache();
system("cls");
printf("数组长度为%d 每行打印个数为%d 元素分隔符为%c\n",cv.arrayLength,cv.numsPerline,cv.splitChar);
break;
case 2://生成样本数据
system("cls");
while(1)
{
printf("-----请选择菜单子选项-----\n");
printf("0)退出子菜单\n");
printf("1)用指定范围的随机数填充数组\n");
printf("2)键盘输入\n");
printf("3)整个数组同一个值\n");
printf("4)用等差数列填充数组,数组起始值为公差\n");
printf("--------------------------\n");
scanf("%c",&ch1);
if(ch1=='0')break;
switch(ch1)
{
case '1':
fillArray(a,arrayLength,1,0,100);//产生0~100随机数
break;
case '2':
fillArray(a,arrayLength,2,0,0);//键盘输入
break;
case '3':
fillArray(a,arrayLength,3,1,0);//整个数组同一个值
break;
case '4':
fillArray(a,arrayLength,4,1,3);//用等差数列填充数组,数组起始值为公差
break;
default:
break;
}
clearCache();
}
system("cls");
break;
case 3://打印数组
system("cls");
printf("数组元素如下:\n");
printArray(a,arrayLength);
printf("\n");
break;
case 4://删除
system("cls");
while(1)
{
printf("-----请选择菜单子选项-----\n");
printf("0)退出子菜单\n");
printf("1)删除指定下标的元素\n");
printf("2)删除指定值的元素\n");
printf("3)删除指定下标区间的一组元素\n");
printf("--------------------------\n");
scanf("%c",&ch1);
if(ch1=='0')break;
switch(ch1)
{
case '1':
printf("请输入想要删除的下标:");
int idx;
scanf("%d",&idx);
deleteElementById(a,arrayLength,idx);
break;
case '2':
printf("请输入想要删除的值:");
int val;
scanf("%d",&val);
deleteElementByVal(a,arrayLength,val);
break;
case '3':
printf("请依次输入下标的起点和终点:");
int begin,end;
scanf("%d %d",&begin,&end);
deleteRange(a,arrayLength,begin,end);
break;
default:
break;
}
clearCache();
//system("cls");
}
system("cls");
break;
case 5://统计
system("cls");
while(1)
{
printf("-----请选择菜单子选项-----\n");
printf("0)退出子菜单\n");
printf("1)求最大值\n");
printf("2)求最小值\n");
printf("3)求平均值\n");
printf("--------------------------\n");
scanf("%c",&ch1);
if(ch1=='0')break;
switch(ch1)
{
case '1':
printf("最大值是%d\n",maxValue(a,arrayLength));
break;
case '2':
printf("最小值是%d\n",minValue(a,arrayLength));
break;
case '3':
printf("平均值是%f\n",average(a,arrayLength));
break;
default:
break;
}
clearCache();
}
system("cls");
break;
case 6://判断
system("cls");
while(1)
{
printf("-----请选择菜单子选项-----\n");
printf("0)退出子菜单\n");
printf("1)判断是否升序排列\n");
printf("2)判断是否降序排列\n");
printf("3)判断是否全部相等\n");
printf("--------------------------\n");
scanf("%c",&ch1);
if(ch1=='0')break;
switch(ch1)
{
case '1':
if(isAsc(a,arrayLength))printf("升序排列\n");
else printf("不是升序排列\n");
break;
case '2':
if(isDesc(a,arrayLength))printf("降序排列\n");
else printf("不是降序排列\n");
break;
case '3':
if(isEqual(a,arrayLength))printf("数列全部相等\n");
else printf("数列不全部相等\n");
break;
default:
break;
}
clearCache();
}
system("cls");
break;
case 7://排序
system("cls");
while(1)
{
printf("-----请选择菜单子选项-----\n");
printf("0)退出子菜单\n");
printf("1)冒泡排序\n");
printf("2)选择排序\n");
printf("3)交换排序\n");
printf("4)快速排序\n");
printf("5)逆置数组\n");
printf("6)左旋数组\n");
printf("7)右旋数组\n");
printf("--------------------------\n");
scanf("%c",&ch1);
if(ch1=='0')break;
switch(ch1)
{
case '1':
BubbleSort(a,arrayLength);
break;
case '2':
SelectSort(a,arrayLength);
break;
case '3':
SwapSort(a,arrayLength);
break;
case '4':
QuickSort(a,0,arrayLength-1);
break;
case '5':
arrayReverse(a,arrayLength);
break;
case '6':
printf("请输入左移的次数:");
int leftm;
scanf("%d",&leftm);
leftRotate(a,arrayLength,leftm);
break;
case '7':
printf("请输入右移的次数:");
int rightm;
scanf("%d",&rightm);
rightRotate(a,arrayLength,rightm);
break;
default:
break;
}
system("cls");
if(ch1>'0'&&ch1<'8')printf("排序/移动完毕!\n");
clearCache();
}
system("cls");
break;
case 8://查找
system("cls");
while(1)
{
printf("-----请选择菜单子选项-----\n");
printf("0)退出子菜单\n");
printf("1)顺序查找\n");
printf("2)二分查找\n");
printf("--------------------------\n");
scanf("%c",&ch1);
if(ch1=='0')break;
int val;
printf("请输入要查找的值:");
scanf("%d",&val);
switch(ch1)
{
case '1':
if(search(a,arrayLength,val))printf("找到了\n");
else printf("没找到\n");
break;
case '2':
if(biSearch(a,arrayLength,val))printf("找到了\n");
else printf("没找到\n");
break;
default:
break;
}
clearCache();
}
system("cls");
break;
case 9://约瑟夫环
system("cls");
printf("请输入删除的间隔");
int n;
scanf("%d",&n);
yuesefu(a,arrayLength,n);
clearCache();
break;
case 10://素数筛选
system("cls");
isPrime(a,arrayLength);
clearCache();
break;
}
//system("pause");
//system("cls");
}
return 0;
}
arrayCalculator.h
#ifndef ARRAYCALCULATOR_H_INCLUDED
#define ARRAYCALCULATOR_H_INCLUDED
#include"arrayCalculator.c"
//功能:清除缓冲区无用数据
void clearCache(void);
//功能:打印数组运算器功能菜单
void printMenu(void);
/*
功能:打印数组
参数:a:数组地址 n:数组元素个数
*/
void printArray(int a[],int n);
//功能:配置系统参数
void config(struct configVar );
/*
功能:打印数组
参数:a:数组地址 n:数组元素个数
*/
void printArray(int a[],int n);
/*
功能:填充数组
参数:
a 数组地址
n 数组元素个数
fillType 填充的方式 1随机数 2手动输入 3填充相同的数 4等差数列
var1 随机数下限/填充的数/等差数列起始值
var2 随机数上限/等差数列公差
*/
void fillArray(int a[],int n,int fillType,int var1,int var2);
//删除和插入-------------------------------------
/*
功能:删除指定下标的元素
参数:
a 数组地址
n 数组长度
id 想要删除的元素的Index
*/
void deleteElementById(int a[],int n,int id);
/*
功能 删除指定值的元素
参数
a 数组地址
n 数组长度
val 想要删除的value
*/
void deleteElementByVal(int a[],int n,int val);
/*
功能:删除指定区间内的元素
参数:
a 数组地址
n 数组长度
begin 区间起点
end 下标终点
*/
void deleteRange(int a[],int n,int begin,int end);
/*
功能:在指定下标位置插入新元素
参数:
a 数组地址
n 数组长度
id 想要插入的下标
val 待插入的value
*/
void insert(int a[],int n,int id,int val);
//统计---------------------------
/*
功能:求最大 最小值
参数 数组地址a 数组长度n
*/
int maxValue(int a[],int n);
int minValue(int a[],int n);
/*
功能:求平均值
参数:数组地址a 数组长度n
*/
float average(int a[],int n);
//判断--------------------------------
/*
功能:判断是否升序排列
参数 数组地址a 数组长度n
返回值:1代表升序,0代表不升序
*/
int isAsc(int a[],int n);
/*
功能:判断是否降序排列
参数 数组地址a 数组长度n
返回值:1代表降序,0代表不降序
*/
int isDesc(int a[],int n);
/*
功能:判断是否全部相等
参数 数组地址a 数组长度n
返回值:1代表全部相等,0代表不全部相等
*/
int isEqual(int a[],int n);
//排序(从小到大)-----------------------------
/*
功能:交换两个数字
参数:两个整型的指针
*/
void Swap(int *a,int *b);
/*
功能:插入排序
参数:
数组地址a 数组长度n
*/
void InsertSort(int a[],int n);
/*
功能:冒泡排序
参数:数组地址a 数组长度n
*/
void BubbleSort(int a[],int n);
/*
功能:选择排序
参数:数组地址a 数组长度n
*/
void SelectSort(int a[],int n);
/*
功能 交换排序
参数 数组地址a 数组长度n
*/
void SwapSort(int *a,int n);
/*
功能:快速排序
参数:数组地址a 起始下标(一般填0) 结束下标(数组长度-1)
注意下标范围
*/
void QuickSort(int *a,int start,int end);
/*
逆置数组
参数 数组地址a 元素个数n
*/
void arrayReverse(int a[],int n);
/*
左旋数组、右旋数组
参数:数组地址a 数值长度n 左/右移次数m
*/
void leftRotate(int a[],int n,int m);
void rightRotate(int a[],int n,int m);
//查找-----------------------------------
/*
功能:顺序查找
参数:数组地址a 数组长度n 目标值val
返回值:找到返回1 找不到返回0
*/
int search(int a[],int n,int val);
/*
功能 二分查找
参数:数组地址a 数组长度n 目标值val
返回值:找到返回1 找不到返回0
*/
int biSearch(int a[],int n,int val);
/*
功能:约瑟夫环
参数:数组地址a 数组长度n 被删除的下标m
*/
void yuesefu(int a[],int n,int m);
/*
功能:筛选素数
参数:数组地址a 数组长度n
*/
void isPrime(int a[],int n);
extern int arrayLength;
extern int numsPerline;
extern char splitChar;
#endif // ARRAYCALCULATOR_H_INCLUDED
arrayCalculator.c
#include<stdio.h>
#include<math.h>
//#include"arrayCalculator.h"
int isAsc(int a[],int n);
int isDesc(int a[],int n);
int arrayLength=10;
int numsPerline=5;
char splitChar='\t';
//功能:清除缓冲区无用数据
void clearCache(void)
{
while(getchar()!='\n');
}
//功能:打印数组运算器功能菜单
void printMenu(void)
{
printf("--------------------\n");
printf("数组运算器功能菜单\n");
printf("--------------------\n");
printf("0 退出\n");
printf("1 配置系统参数\n");
printf("2 生成样本数据\n");
printf("3 打印数组\n");
printf("4 删除指定元素\n");
printf("5 统计\n");
printf("6 判断\n");
printf("7 排序\n");
printf("8 查找\n");
printf("9 约瑟夫环\n");
printf("10 筛选素数\n");
printf("--------------------\n");
}
//功能:配置系统参数
struct configVar
{
int arrayLength;
int numsPerline;
char splitChar;
};
void config(struct configVar cv)
{
arrayLength=cv.arrayLength;
numsPerline=cv.numsPerline;
splitChar=cv.splitChar;
}
/*
功能:打印数组
参数:a:数组地址 n:数组元素个数
*/
void printArray(int a[],int n)
{
int i;
for(i=0;i<n;i++)
{
if(i!=0&&i%numsPerline==0)printf("\n");
printf("%d%c",a[i],splitChar);
}
}
/*
功能:填充数组
参数:
a 数组地址
n 数组元素个数
fillType 填充的方式 1随机数 2手动输入 3填充相同的数 4等差数列
var1 随机数下限/填充的数/等差数列起始值
var2 随机数上限/等差数列公差
*/
void fillArray(int a[],int n,int fillType,int var1,int var2)
{
int i;
switch(fillType)
{
case 1://随机数
srand(time(NULL));
for(i=0;i<n;i++)
{
a[i]=rand()%(var2-var1+1)+var1;
}
break;
case 2://输入
printf("请输入%d个整数:",n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
break;
case 3://填充相同的数
for(i=0;i<n;i++)
a[i]=var1;
break;
case 4://等差数列
for(i=0;i<n;i++)
a[i]=var1+var2*i;
break;
default:
break;
}
system("cls");
printf("数组样本数据生成完毕!\n");
}
//删除和插入-------------------------------------
/*
功能:删除指定下标的元素
参数:
a 数组地址
n 数组长度
id 想要删除的元素的Index
*/
void deleteElementById(int a[],int n,int id)
{
system("cls");
if(id<n)
{
int i=id;
for(;i<n-1;i++)
{
a[i]=a[i+1];
}
printf("已删除下标为%d的元素!\n",id);
}
else
printf("下标超出数组长度!");
}
/*
功能 删除指定值的元素
参数
a 数组地址
n 数组长度
val 想要删除的value
*/
void deleteElementByVal(int a[],int n,int val)
{
system("cls");
int i,j;
for(i=0;i<n;i++)
{
if(a[i]==val)
{
for(j=i;j<n-1;j++)
{
a[j]=a[j+1];
}
}
}
printf("已删除值为%d的元素!\n",val);
}
/*
功能:删除指定区间内的元素
参数:
a 数组地址
n 数组长度
begin 区间起点
end 下标终点
*/
void deleteRange(int a[],int n,int begin,int end)
{
system("cls");
if(begin>=0&&end<n&&begin>=end)
{
int i;
for(i=begin;i<=end&&i+(end-begin)+1<n;i++)//此处的条件有点复杂
{
a[i]=a[i+end-begin+1];
}
//注:此处将空出来的位置统一赋0值
for(;i<n;i++)
{
a[i]=0;
}
printf("已删除第%d个到第%d个元素!\n",begin,end);
}
else
printf("无效的下标范围!");
}
/*
功能:在指定下标位置插入新元素
参数:
a 数组地址
n 数组长度
id 想要插入的下标
val 待插入的value
*/
void insert(int a[],int n,int id,int val)
{
if(id>0&&id<n)//插入的index不能越界
{
int i;
for(i=n-1;i>id;i--)//如果插入新元素后数组长度不够,则覆盖最后一个元素
{
a[i]=a[i-1];
}
a[id]=val;
}
else
printf("无效的位置!");
}
/*
功能 在有序数组中插入新元素
参数 数组地址a 数组长度n 待插入的值val
*/
void orderInsert(int a[],int n,int val)
{
int i,j;
if(isAsc(a,n))//如果数组升序排列
{
for(i=0;i<n&&val>a[i];i++);//找到元素应该插入的位置
for(j=n-1;j>i;j--)
{
a[j-1]=a[j];//数组局部后移,为新元素腾出位置。如果长度不够则最后一个元素被覆盖
}
a[i]=val;
}
else if(isDesc(a,n))//如果降序排列
{
for(i=0;i<n&&val<a[i];i++);
for(j=n-1;j>i;j--)
{
a[j-1]=a[j];
}
a[i]=val;
}
else printf("原数组无序!\n");
}
//统计---------------------------
/*
功能:求最大 最小值
参数 数组地址a 数组长度n
*/
int maxValue(int a[],int n)
{
system("cls");
int i,max=a[0];
for(i=1;i<n;i++)
{
if(a[i]>max)max=a[i];
}
return max;
}
int minValue(int a[],int n)
{
system("cls");
int i,min=a[0];
for(i=1;i<n;i++)
{
if(a[i]<min)min=a[i];
}
return min;
}
/*
功能:求平均值
参数:数组地址a 数组长度n
*/
float average(int a[],int n)
{
system("cls");
float sum=0;
int i;
for(i=0;i<n;i++)
{
sum+=a[i];
}
sum/=n;
return sum;
}
//判断--------------------------------
/*
功能:判断是否升序排列
参数 数组地址a 数组长度n
返回值:1代表升序,0代表不升序
*/
int isAsc(int a[],int n)
{
system("cls");
int i;
for(i=0;i<n-1;i++)
{
if(a[i]>a[i+1])return 0;
}
return 1;
}
/*
功能:判断是否降序排列
参数 数组地址a 数组长度n
返回值:1代表降序,0代表不降序
*/
int isDesc(int a[],int n)
{
system("cls");
int i;
for(i=0;i<n-1;i++)
{
if(a[i]<a[i+1])return 0;
}
return 1;
}
/*
功能:判断是否全部相等
参数 数组地址a 数组长度n
返回值:1代表全部相等,0代表不全部相等
*/
int isEqual(int a[],int n)
{
system("cls");
int i;
for(i=0;i<n-1;i++)
{
if(a[i]!=a[i+1])return 0;
}
return 1;
}
//排序(从小到大)-----------------------------
/*
功能:交换两个数字
参数:两个整型的指针
*/
void Swap(int *a,int *b)
{
int temp=*a;
*a=*b;
*b=temp;
}
/*
功能:插入排序
参数:
数组地址a 数组长度n
*/
void InsertSort(int a[],int n)
{
int i,j;
for(i=1;i<n;i++)
{
for(j=i;j>0;j--)
{
if(a[j-1]>a[j])Swap(&a[j-1],&a[j]);
else break;
}
}
}
/*
功能:冒泡排序
参数:数组地址a 数组长度n
*/
void BubbleSort(int a[],int n)
{
int i,j,flag;
for(i=n-1;i>0;i--)
{
flag=1;
for(j=0;j<i;j++)
{
if(a[j]>a[j+1])
{
Swap(&a[j],&a[j+1]);
flag=0;
}
}
if(flag)break;//flag==1说明上一轮没有交换数字,数组已经有序,可以结束冒泡排序
}
}
/*
功能:选择排序
参数:数组地址a 数组长度n
*/
void SelectSort(int a[],int n)
{
int i,j,index;
for(i=0;i<n;i++)
{
index=i;
for(j=i+1;j<n;j++)
{
if(a[j]<a[index])index=j;
}
Swap(&a[i],&a[index]);
}
}
/*
功能 交换排序
参数 数组地址a 数组长度n
*/
void SwapSort(int *a,int n)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
if(a[i]>a[j])Swap(&a[j],&a[i]);
}
}
}
/*
功能:快速排序
参数:数组地址a 起始下标(一般填0) 结束下标(数组长度-1)
*/
void QuickSort(int *a,int start,int end)//注意下标范围
{
if(start>end)return;//数组已经排序完成,结束递归
int left=start,right=end;
int temp=a[left];
while(left!=right)//left和right碰头时结束循环
{
//以下两个while循环在a[right]或a[left]==temp时要继续进行,否则会死循环
while(a[right]>=temp&&right>left)right--;
while(temp>=a[left]&&right>left)left++;
if(right>left)
{
Swap(&a[left],&a[right]);
}
}
//将原数组第一个数放入中间特定位置,使数组分为两部分
a[start]=a[left];
a[left]=temp;
//递归 对左右两个小区间进行快速排序
QuickSort(a,start,left-1);
QuickSort(a,left+1,end);
}
/*
逆置数组
参数 数组地址a 元素个数n
*/
void arrayReverse(int a[],int n)
{
int i;
for(i=0;i<=(n-1)/2;i++)
{
Swap(&a[i],&a[n-i-1]);
}
}
/*
左旋数组、右旋数组
参数:数组地址a 数值长度n 左/右移次数m
*/
void leftRotate(int a[],int n,int m)
{
int i,j,temp;
for(i=0;i<m;i++)
{
temp=a[0];
for(j=1;j<n;j++)
{
a[j-1]=a[j];
}
a[j-1]=temp;
}
}
void rightRotate(int a[],int n,int m)
{
int i,j,temp;
for(i=0;i<m;i++)
{
temp=a[n-1];
for(j=n-1;j>0;j--)
{
a[j]=a[j-1];
}
a[0]=temp;
}
}
//查找-----------------------------------
/*
功能:顺序查找
参数:数组地址a 数组长度n 目标值val
返回值:找到返回1 找不到返回0
*/
int search(int a[],int n,int val)
{
system("cls");
int i;
for(i=0;i<n;i++)
{
if(a[i]==val)return 1;
}
return 0;
}
/*
功能 二分查找
参数:数组地址a 数组长度n 目标值val
返回值:找到返回1 找不到返回0
*/
int biSearch(int a[],int n,int val)
{
system("cls");
int left=0,right=n-1,mid;
//先判断数组是否有序
if(isDesc(a,n))//如果降序
{
while(left<=right)//当left==right时,循环内可以检查这个位置是否有目标值
{
mid=(left+right)/2;
if(a[mid]<val)
{
right=mid-1;//缩小区间范围
}
else if(a[mid]>val)
{
left=mid+1;//缩小区间范围
}
else return 1;
}
return 0;
}
else if(isAsc(a,n))//如果升序
{
while(left<=right)
{
mid=(left+right)/2;
if(a[mid]>val)
{
right=mid-1;
}
else if(a[mid]<val)
{
left=mid+1;
}
else return 1;
}
return 0;
}
else//无序数组直接使用顺序查找
{
return search(a,n,val);
}
}
/*
功能:约瑟夫环
参数:数组地址a 数组长度n 被删除的下标m
*/
void yuesefu(int a[],int n,int m)
{
int i=-1,sum=0,t=0;
//i用于遍历原数组 t为已经被杀的人数
do
{
do
{
//if-else将数组变为环
if(i!=n-1)
{
i++;
}
else//若i达到终点,则将其值赋为0从头开始遍历,从而实现把线性数组变为环
{
i=0;
}
} while(a[i]==-1);//发现不等于-1的元素(即还没死的人),停止循环,sum++用于记录间隔了几个(没死的)人
sum++;
if(sum==m)//间隔的没死的人数符合要求时,
{
sum=0;//间隔归零,重新计数
t++;//多了一个被杀的人
a[i]=-1;//将此人杀死(赋值为-1)
}
} while(t<n);
printf("%d",i);
}
/*
功能:筛选素数
参数:数组地址a 数组长度n
*/
void isPrime(int a[],int n)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=2;j<=sqrt(a[i]);j++)//用比平方根小的数字进行验证
{
if(a[i]%j==0)
{
a[i]=0;
break;//发现合数则跳出当前循环
}
}
}
}
分析
模块化编程的思想贯穿这道题目的始终
先把各个积木(函数)做好,再把他们搭建起来
在这种规模大的程序里要写清楚函数的参数(接口)以方便调用
此外,用while和switch搭配打印操作窗口是难度不大但有些繁琐的一步,在程序中运用clearCache()函数清除无用的数据以免干扰程序,用system(“cls”)清屏方便操作者使用
程序中快速排序和约瑟夫环比较麻烦
目前我对约瑟夫环问题有三个解决思路:
a利用for和if的搭配使数组具有环的特性
b递归
c循环链表
快速排序的思路和注意事项已经写在注释里,这里不再重复
测试及运行结果
在写函数时我采用一个个写一个个调试,确保无误后再将其“组装”到整个项目中
写main函数为了方便操作者,频繁采用清屏,带来了不少麻烦,因为要确保在正确的时候清屏并不容易,有一部分system(“cls”)被写到其他函数中
此外在.h使用extern 声明变量,在其他.c文件中定义变量