第B练——数组及元素操作
- 数组及元素操作
1.1. 排序三数:Sort3Num.cpp(本题10分) 【题目描述】 输入3个数a, b, c,利用指针方法,按从小到大的顺序输出。
【程序分析】
利用指针方法。
【输入】
输入文件Sort3Num.in有1行,包含3个int整数,即输入的变量a, b, c。
【输出】
输出文件Sort3Num.out有1行,包含3个int整数(空格隔开),即输出的3个整数。
【输入输出样例1】
Sort3Num.in Sort3Num.out
8 5 7 5 7 8
【输入输出样例2】
Sort3Num.in Sort3Num.out
4 5 3 3 4 5
#include <stdio.h>
/*功能: 通过指针交换2个数*/
void swap(int *p1, int *p2){
int p;
//******************************************
p = *p1;
*p1 = *p2;
*p2 = p;
//==========================================
}
int main(){
int a, b, c; //a,b,c-三个整型变量
int *pointer1, *pointer2, *pointer3; //三个整型指针
printf("请输入3个整数(a b c),空格隔开:");
FILE *fp;
if((fp=fopen("Sort3Num.in", "r")) != NULL ){
fclose(fp); //存在的话,要先把之前打开的文件关掉
freopen("Sort3Num.in", "r", stdin);
freopen("Sort3Num.out", "w", stdout);
}
scanf("%d%d%d", &a, &b, &c); //输入三个整数
//*******************************************
pointer1 = &a;
pointer2 = &b;
pointer3 = &c;
if(a>b){
swap(pointer1, pointer2);
}
if(a>c){
swap(pointer1, pointer3);
}
if(b>c){
swap(pointer2, pointer3);
}
//============================================
printf("%d %d %d", a, b, c); //输出交换后(从小到大有序)的3个整数
return 0;
}
1.2. 最大最小数组元素:ArrayNum.cpp(本题15分) 【题目描述】 输入数组元素个数n以及n个整型数组元素,将值最大的元素与第一个元素交换,值最小的元素与最后一个元素交换,并输出最终的数组。
【程序分析】
首先遍历数组,保留最大最小元素的下标。之后进行相应操作。
注意:值最小元素在头、值最大元素在尾时的特殊情况处理!
【输入】
输入文件ArrayNum.in有2行,第1行是一个整数n;第2行有n个整数,整数之间用空格隔开。
【输出】
输出文件ArrayNum.out有1行,包含n个整数,整数之间用1个空格隔开。
【输入输出样例1】
ArrayNum.in ArrayNum.out
10
23 21 5 98 19 12 6 10 8 61 98 21 61 23 19 12 6 10 8 5
【输入输出样例2】
ArrayNum.in ArrayNum.out
12
4 4 4 4 4 5 5 6 6 6 6 6 6 4 4 4 4 5 5 6 6 6 6 4
【数据限制】
1≤n≤1000。
#include <stdio.h>
const int N0=1000;
/*功能:值最大的元素与第一个元素交换,值最小的元素与最后一个元素交换*/
void max_min(int array[10], int n){
int *max, *min, *p, temp; //max-指向最大数组元素的指针; min-指向最小数组元素的指针; p-遍历数组的指针; temp-元素交换的临时变量
//*********************************************
//(1)初始化最大最小元素的指针
max = array;
min = array;
//(2)遍历数组,寻找最大最小元素
for(p=array+1; p<array+n; p++){
if(*p > *max){
max = p;
}
if(*p < *min){
min = p;
}
}
//(3)值最大的元素与第一个元素交换
temp = *max;
*max = array[0];
array[0] = temp;
//(4)值最小的元素与最后一个元素交(注意处理: 值最小元素在头、值最大元素在尾的情况)
if(min == array){
min = max;
}
temp = *min;
*min = array[n-1];
array[n-1] = temp;
//=============================================
}
int main(){
int number[N0], n, i; //a-整型数组; n-数组元素个数; i-循环变量
printf("请输入整数个数n及n个整数), 空格隔开:");
FILE *fp;
if((fp=fopen("ArrayNum.in", "r")) != NULL ){
fclose(fp); //存在的话,要先把之前打开的文件关掉
freopen("ArrayNum.in", "r", stdin);
freopen("ArrayNum.out", "w", stdout);
}
scanf("%d", &n); //输入数组元素个数
for(i=0; i<n; i++){ //输入数组元素
scanf("%d", &number[i]);
}
//*********************************************
max_min(number, n); //调用函数max_min(...)实现最大最小元素与首尾元素的交换
//=============================================
for(i=0; i<n; i++){ //通过指针p遍历数组,并输入数组元素
printf("%d ", number[i]);
}
return 0;
}
1.3. 选择排序:SelectSort.cpp(本题15分) 【题目描述】 输入数组元素个数n以及n个整型数组元素,使用选择排序算法对n个整数进行排序,使之从小到大有序。
【程序分析】
利用选择法,将第i个元素与其后的n-i个元素进行比较,选择最小的元素(可能多个,只选一个)与第i个元素进行交换。依次类推,进行循环,直到所有元素从小到大有序。
【输入】
输入文件SelectSort.in有2行,第1行是一个整数n;第2行有n个整数,整数之间用空格隔开。
【输出】
输出文件SelectSort.out有1行,包含n个从小到大有序的int整数,即有序数组的元素值,整数之间用1个空格隔开。
【输入输出样例1】
SelectSort.in SelectSort.out
10
23 28 5 98 5 12 6 10 28 61 5 5 6 10 12 23 28 28 61 98
【输入输出样例2】
SelectSort.in SelectSort.out
20
23 21 5 76 19 12 16 12 8 61 89 69 56 34 96 37 67 87 5 32 5 5 8 12 12 16 19 21 23 32 34 37 56 61 67 69 76 87 89 96
【数据限制】
1≤n≤1000。
#include <stdio.h>
#define N 1000
int main(){
int a[N], n; //a-整型数组; n-数组元素个数
int i, j, min, temp;//i,j-循环变量; min-一趟选择排序过程中找到的最小元素的下标; temp-元素交换临时变量
printf("请输入整数个数n及n个整数), 空格隔开:");
FILE *fp;
if((fp=fopen("SelectSort.in", "r")) != NULL ){
fclose(fp); //存在的话,要先把之前打开的文件关掉
freopen("SelectSort.in", "r", stdin);
freopen("SelectSort.out", "w", stdout);
}
scanf("%d", &n); //输入数组元素个数
for(i=0; i<n; i++){ //输入数组元素
scanf("%d", &a[i]);
}
//****************************************
/*(1)使用选择法排序数组*/
for(i=0; i<n; i++){
//(a)初始化最小元素的下标
min = i;
//(b)遍历数组,获得最小元素的下标
for(j=i+1; j<n; j++){
if(a[min] > a[j]){
min = j;
}
}
//(c)将最小元素与首元素交换
temp=a[i];
a[i]=a[min];
a[min]=temp;
}
/*(2)输出最终的数组数据*/
for(i=0; i<n; i++){
printf("%d ", a[i]);
}
//============================================
return 0;
}
1.4. 数组元素插入:InsertNumber.cpp(本题20分) 【题目描述】 有一个已经从小到大排序好的int型数组。现要求输入一个整数number(int型)并将其插入数组,要求插入number后的数组仍有序。
【程序分析】
首先判断此数number与数组首尾元素的关系,尤其是此数与最后一个元素的大小关系,若此数number大于最后一个数,则直接插入在数组末端,无需移动原来的数组元素;否则,此数number将插入在数组的中间,插入number后此元素之后的元素须依次往后移一个位置。
注意:给定的数组的长度N,已有数组个数N-1。插入数据存放于数组最后一个位置,即数组下标N-1。
【输入】
输入文件InsertNumber.in有1行,包含1个int整数,即输入的变量number。
【输出】
输出文件InsertNumber.out有1行,包含若干个从小到大有序的int整数,即原数组基础上插入number后仍有序的数组,整数之间用1个空格隔开。
【输入输出样例1】
InsertNumber.in InsertNumber.out
-8 -8 1 4 6 9 13 16 19 28 32 43 55
【输入输出样例2】
InsertNumber.in InsertNumber.out
10 1 4 6 9 10 13 16 19 28 32 43 55
#include <stdio.h>
#define N 12
int main(){
int a[N]={1, 4, 6, 9, 13, 16, 19, 28, 32, 43, 55}; //当前共11个数组元素
int number, i; //number-待输入的整数; i-循环控制变量
printf("请输入待插入的整数(number):");
FILE *fp;
if((fp=fopen("InsertNumber.in", "r")) != NULL ){
fclose(fp); //存在的话,要先把之前打开的文件关掉
freopen("InsertNumber.in", "r", stdin);
freopen("InsertNumber.out", "w", stdout);
}
scanf("%d", &number); //输入数组元素个数
//******************************************
if(number > a[N-2]){//若插入元素比最好一个元素大,则直接插入在最后
a[N-1] = number;
}else{//若插入元素number插入在数组‘内部’,则...
//从数组右端开始遍历、并将数组往后移动,直到碰到找到不比number大的元素
for(i=N-2; i>=0; i--){
if(a[i] > number){
a[i+1] = a[i];
}else{
break;
}
}
//待插入元素number插入在(i-1)位置上
a[i+1] = number;
}
//============================================
for(i=0; i<N; i++){//输出数组数据
printf("%d ", a[i]);
}
return 0;
}
1.5. 元素移动:ElementMove.cpp(本题20分) 【题目描述】 输入数组元素的个数n及n个整型(int)数组元素数据,以及移动的步长m,使数组的前面各数顺序向后移m个位置,最后m个数变成最前面的m个数,即数组元素自左向右循环转动m个位置。
【程序分析】
程序实现有两种方式,一是:每次自左向右移动1位,循环m次,达到移动m位的效果;二是:计算好移动m位后个元素的对应位置关系,每个元素只进行一次移动。
注意:由于长度为n的数组元素的移动具有周期性,即移动步长为n的整数倍时 数组保持原样(不变),等价于不移动,因此,移动步长m可以取值为对n求余数的结果,即m%n。
【输入】
输入文件ElementMove.in有3行,第一行包含1个int型整数,表示数组元素的个数n,即变量n。第二行包含n个空格隔开的整数,即数组number各元素的值。第三行包含1个int型整数,表示数组元素的循环移动的步长,即变量m。
【输出】
输出文件ElementMove.out有1行,包含n个空格隔开的整数,即原数组元素自左向右循环移动m次后的数组数据。
【输入输出样例1】
ElementMove.in ElementMove.out
10
23 21 5 98 19 12 6 10 8 61
13 10 8 61 23 21 5 98 19 12 6
【输入输出样例2】
ElementMove.in ElementMove.out
12
11 6 15 8 21 33 8 35 48 39 17 42
241 42 11 6 15 8 21 33 8 35 48 39 17
【数据限制】
n≥1,m≥0。
#include <stdio.h>
#define N 1000
void move(int array[N], int n, int m){
int i, temp; //i-数组循环变量; temp-临时变量
//************************************************
/*方法(一):递归调用*/
/*(1)若移动步长m>0, 则所有元素自左向右移动1位*/
if(m > 0){
//(1.1)保留数组元素的最后一个元素
temp = array[n-1]; //保存最后一个元素
//(1.2)将最后一个元素之前的所有n-1个元素向右移动一个位置
for(i=n-1; i>0; i--){
array[i] = array[i-1];
}
array[i] = temp; //array[0] = temp;//数组首元素=原数组最后一个元素
//(1.3)更改移动步长,递归,进行下一轮调用
move(array, n, --m);
}
/*方法(二):循环移动*/
/*
if(m > 0){
for(int k=0; k<m; k++){//m次循环移动
//(1.1)保留数组元素的最后一个元素
temp = array[n-1]; //保存最后一个元素
//(1.2)将最后一个元素之前的所有n-1个元素向右移动一个位置
for(i=n-1; i>0; i--){
array[i] = array[i-1];
}
array[i] = temp; //array[0] = temp;//数组首元素=原数组最后一个元素
}
}
*/
//================================================
}
int main() {
int number[N], n, m, i; //n-数据个数; i-循环变量
printf("请输入数据个数n和n个数据,以及移动的距离m:");
FILE *fp;
if((fp=fopen("ElementMove.in", "r")) != NULL ){
fclose(fp); //存在的话,要先把之前打开的文件关掉
freopen("ElementMove.in", "r", stdin);
freopen("ElementMove.out", "w", stdout);
}
scanf("%d", &n); //输入数组元素个数
for(i=0; i<n; i++){ //输入数组元素
scanf("%d", &number[i]);
}
scanf("%d", &m); //数据移动位数
//************************************************
/*方法(1): */
//m = m%n; //去除可能无效的周期移动(不管m是否大于n!!)
//move(number, n, m); //调用函数move(...)将长度为n的数组number的
/*方法(2): */
move(number, n, m%n); //调用函数move(...)将长度为n的数组number的
//================================================
for(i=0; i<n; i++){
printf("%d ", number[i]);
}
return 0;
}
1.6. 数字抽出:DropNumber.cpp(本题20分) 【题目描述】 有n(程序输入)个人围成一圈,顺序编号(从1开始编号,直到n)。从第一个人开始报数(从1到3报数),凡是报到3的人退出圈子,问第m(程序输入)个退出的人的编号是多少?若第m次‘退出’之前所有人已经退出,则输出最后一个退出的人的编号。
【程序分析】
本题要求学生熟练掌握循环控制。对于本题的实现:
n个人员的编号存储于整型数组中,并由程序通过循环进行初始化。
人员报数和退出的实现,采用数组元素遍历的方式。
遍历数组元素时,程序可将退出人员的编号置为特殊标识(如“-1”),后续遍历时略过这些特殊元素。
一旦遍历到数组尾元素,则将游标移动到数组首元素,从而形成虚拟的圆圈遍历控制。
程序进行循环,直到找到满足条件的人员、或者所有人员都已经退出。
【输入】
输入文件DropNumber.in有1行,包含2个int类型的整数(空格隔开),即初始时刻的总人数(n)和想要获得的第m个退出的人的序号(m)。
【输出】
输出文件DropNumber.out有1行,包含1个int类型的整数,即第m个退出的人的编号。
【输入输出样例1】
DropNumber.in DropNumber.out
20 6 18
【输入输出样例2】
DropNumber.in DropNumber.out
20 18 2
【输入输出样例3】
DropNumber.in DropNumber.out
20 118 20
【数据限制】
1≤n≤5000,m≥1。
#include <stdio.h>
#define nmax 5000
int main() {
int n, num[nmax], m, id; //n-总人数; num-人编号; m-待获得的退出人员的序号; id-第m次退出人员的编号id
int i, k, count;//i-循环控制变量; k-人员报号数; count-已退出人员计数
printf("请输入总人数n和序号m:");
FILE *fp;
if((fp=fopen("DropNumber.in", "r")) != NULL ){
fclose(fp); //存在的话,要先把之前打开的文件关掉
freopen("DropNumber.in", "r", stdin);
freopen("DropNumber.out", "w", stdout);
}
scanf("%d%d", &n, &m); //输入总人数n 和 退出人员的序号m
//********************************************************************
//(1)初始化人员的编号
for(i=0; i<n; i++){
num[i] = i + 1;
}
//(2)若m大于n, 则求最后一个(第n个)退出的人,...
if( m>n ){
m = n;
}
//(3)模拟数 的过程,循环遍历数组元素,直到找到第m个退出的人
k = 0; //人员的叫号
count = 0; //退出的人员的计数
for(i=0; ;i++){
//(3.1)若此元素有效(还没退出!),则报数
if(num[i%n] != -1){
//A.人员报数+1
k++;
//B.若此人员的报数是3的倍数,则累加退出人员的数目 & 并将元素值置为-1(表示此人退出)
if(k%3 == 0){ //若报数是3的倍数, 则将此元素置为-1
//(B.1)退出人员的数目+1
count++;
//printf("报数=%d, 下标=%d, 编号=%d\n", k, i, num[i]);
//(B.2)若此次(count)退出的人员num[i] ->即为要找的人员(m==count)或所有人员都已经退出(n==count), 则找到&退出循环
if( count >= m ){ //if((count == m) || (count == n)){ //找到第m个退出的人
id = num[i%n];
break;
}
//(B.3)将此退出人员的编号置为-1
num[i%n] = -1;
}
}
}
//(4)输出第m次(当m>n时,输出第n个退出的人)退出的人员的编号
printf("%d", id); // printf("报数=%d, ID=%d \n", k, id);
//======================================================================
return 0;
}
#include <stdio.h>
#define nmax 5000
int main() {
int n, num[nmax], m, id; //n-总人数; num-人编号; m-待获得的退出人员的序号; id-第m次退出人员的编号id
int i, k, count;//i-循环控制变量; k-人员报号数; count-已退出人员计数
printf("请输入总人数n和序号m:");
FILE *fp;
if((fp=fopen("DropNumber.in", "r")) != NULL ){
fclose(fp); //存在的话,要先把之前打开的文件关掉
freopen("DropNumber.in", "r", stdin);
freopen("DropNumber.out", "w", stdout);
}
scanf("%d%d", &n, &m); //输入总人数n 和 退出人员的序号m
//********************************************************************
//(1)初始化人员的编号
for(i=0; i<n; i++){
num[i] = i+1;
}
//(2)循环遍历数组元素,直到:1)所有元素(人)都已经退出,或者 2)已经找到第m个退出的人
i=0; //i-数组的遍历游标
count = 0; //退出的人员的计数
k = 0; //人员的叫号
while(count < n){
//(2.1)若此元素有效(还没退出!)
if(num[i] != -1){
//A.人员报数+1
k++;
//B.若此人员的报数是3的倍数,则累加退出人员的数目 & 并将元素值置为-1(表示此人退出)
if(k%3 == 0){ //若报数是3的倍数, 则将此元素置为-1
//printf("报数=%d, 下标=%d, 编号=%d\n", k, i, num[i]);
//(B.1)退出人员的数目+1
count++;
//(B.2)若此次(count)退出的人员num[i] ->即为要找的人员(m==count)或所有人员都已经退出(n==count), 则找到&退出循环
if((count == m) || (count == n)){
id = num[i];
break;
}
//(B.3)将此退出人员的编号置为-1
num[i] = -1;
}
}
//(2.2)数组的遍历游标i往后移动【若达到数组最后一个,则移动到首个->形成圆圈】
i++; //数组的下一个元素
if(i == n){
i = 0; //将数组的遍历游标移动到首个元素
}
}
//======================================================================
//输出第m次(当m>n时,输出第n个退出的人)退出的人员的编号
printf("%d", id); // printf("报数=%d, ID=%d \n", k, id);
return 0;
}