【C语言编程进阶精选题】

在这里插入图片描述

一、数据存储

1.1 十进制转二级制

在这里插入图片描述

#include <stdio.h>
int main(){
	int a[32];
	int n,i=0;
	scanf("%d",&n);
	//处理特殊边界
	if(n=0){
		printf("0");
	}
	//取余法转二进制
	while(n>0){
		a[i]=n%2;
		n/=2;
		i++;
	}
	//逆序输出余数
	for(i--;i>=0;i--){
		printf("%d",a[i]);
	}
	return 0;
}

十进制转二进制的步骤如下:
取余法:将十进制数不断除以 2,记录每次的余数(0 或 1)。
例如:17 ÷ 2 = 8 余 1
重复此步骤直到商为 0。
逆序排列余数:将记录的余数按逆序排列,得到最终的二进制数。
例如:17 的余数依次为 1,0,0,0,1 → 逆序后为 10001。
数学原理:
二进制每一位对应 2 的幂次(如 2⁰, 2¹, 2²…)。每次除以 2 相当于逐位确定每一位的权值,余数即为当前位的数值。

1.2 浮点数转二级制

在这里插入图片描述

#include <stdio.h>
void floatToBinary(float f) {
    int i;
    printf("0.");
	for(i=0;i<32;i++){
		f*=2; 
		if(f>=1){  //只看整数部分决定取0还是取1
			printf("1");
			f-=1; //只保留小数部分
		}
		else{
			printf("0");
		}
		if(f==0){   //小数部分为0结束
			break;
		}
	}
}

int main() {
    float f;
    scanf("%f", &f);
    floatToBinary(f);
    floatToBinary(f);
    return 0;
}

十进制小数转换为二进制小数采用 “乘 2 取整,顺序排列” 法,具体步骤如下:
初始运算:用 2 乘以十进制小数,得到一个积。
取出整数部分:将积的整数部分取出,这个整数部分只能是 0 或者 1,它将作为二进制小数的一位数字 。
判断小数部分:检查积的小数部分,如果小数部分为 0,转换结束;如果小数部分不为 0,则将该小数部分作为新的被乘数,返回步骤 1 继续运算。
排列结果:将每次取出的整数部分,按照取出的先后顺序从左到右排列,得到的数字序列就是对应的二进制小数。
需要注意的是,有些十进制小数不一定能完全准确地转换成二进制小数,会出现无限循环或无限不循环的情况。在这种情况下,可以根据精度要求,转换到小数点后指定的位数即可。
案例如下
在这里插入图片描述

1.3 二进制转十进制

在这里插入图片描述

#include <stdio.h>
#include <string.h>

// 二进制转十进制
int binaryToDecimal(char str[]) {
    int sum=0,weight=1;
	int pos=strlen(str)-1;
	//从后往前,从低位到高位		
	for(;pos>=0;pos--){
		sum+=(str[pos]-'0')*weight;
		weight*=2; //不断增加权重
	}
	return sum;
}

int main() {
    char Str[32];
    scanf("%s", &Str);
    printf("%d", binaryToDecimal(Str));
    return 0;
}

将二进制数的每一位按权值展开并求和,实现了二进制到十进制的转换

1.4 大整数加🚀🚀🚀

在这里插入图片描述

#include <stdio.h>
#include <string.h>

int main() {
    //用来接收用户输入的字符串形式的大整数
    char sNum1[201] = {'\0'};
    char sNum2[201] = {'\0'};

    //存放相加后的结果方便从高位到低位输出
    //当作1字节的int型使用节省内存
    char result[201];
    gets(sNum1); gets(sNum2);

    int len1 = strlen(sNum1), len2 = strlen(sNum2);
    int addition = 0, push = addition / 10; //用于进位
    int reslen = 0;
    //注意处理长度不一的情况
    for(int i = len1 - 1, j = len2 - 1 ; i >= 0 || j >= 0; i--, j--){
        //从低位到高位依次相加,当i或j小于0时说明改为0
        char a = ( i < 0 ? '0' : sNum1[i] );
        char b = ( j < 0 ? '0' : sNum2[j] );
        addition = a - '0' + b - '0' + push;
        result[reslen++] = addition % 10;
        push = addition / 10; //下一个高位是否需要进位
    }
    //最高位的进位特殊处理
    if(push == 1){
        result[reslen++] = 1;
    }
    for(int i = reslen - 1; i >= 0; i--)
        printf("%d", result[i]);
    return 0;
}

二、遍历和循环

2.1 数组循环右移

在这里插入图片描述

#include <stdio.h>

int main() {
	int a[100];
	int n,step,i;
	scanf("%d",&n);
	for(i=0;i<n;i++){ //输入数组
		scanf("%d",&a[i]);
	}
	scanf("%d",&step);
	for(i=n-step;i<n;i++){  //先把右移步数大小,后半部分输出
		printf("%d ",a[i]);
	}
	for(i=0;i<n-step;i++){ //在输出剩下的
		printf("%d ",a[i]);
	}
    return 0;
}

方法二:

#include <stdio.h>

// 实现数组元素整体循环右移的函数
void rightRotate(int arr[], int n, int steps) {
    int temp[n];
    for (int i = 0; i < n; i++) // 将数组元素整体右移steps步存储到临时数组中
        temp[(i + steps) % n] = arr[i];
    for (int i = 0; i < n; i++) // 将临时数组中的元素复制回原数组
        arr[i] = temp[i];
}

int main() {
    int n, steps;
    scanf("%d", &n);
    int arr[n];
    for (int i = 0; i < n; i++)
        scanf("%d", &arr[i]);
    scanf("%d", &steps);
    rightRotate(arr, n, steps);
    for (int i = 0; i < n; i++)
        printf("%d ", arr[i]);
    return 0;
}

2.2 左大右小(分治)🚀🚀

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

//把下标为index的元素左移(左移到基准左边)
void moveToLeft(int arr[], int index, int step) {
    int temp = arr[index]; //index移动步数范围整体左移,会把基准给覆盖掉,所以先保存!
    for(int i = index; (index - i) < step && i >= 1; i--){
        arr[i] = arr[i-1];
    }
    arr[index - step] = temp;
}
void Partition(int arr[], int n) {
    int index = 1;
    int pivot = arr[0];
    int rightNum = 0; //记录大于pivot的元素个数
    while(index < n) {
        if(arr[index] <= pivot)
            moveToLeft(arr, index, rightNum + 1);
        else
            rightNum++;  //因为比基准的不移动,在遍历到比基准小的数移动时,要跨过那些没有移动的大数!🎈
        index++;
    }
}

int main() {
    int arr[100];
    int n = 0;
    char ch;
    // 读取一系列正整数数据,直到遇到回车符
    while (scanf("%d%c", &arr[n], &ch) == 2) {
        n++;
        if (ch == '\n')
            break;
    }
    Partition(arr, n);
    for (int i = 0; i < n; i++)
        printf("%d ", arr[i]);
    return 0;
}

这段代码的核心思想是 基于基准值的原地元素调整,具体如下:

  1. 基准值设定
    以数组第一个元素 arr[0] 作为基准值 pivot,后续元素根据与 pivot 的大小关系调整位置。
  2. 遍历与分类处理
    遍历数组(从第二个元素开始),若元素 arr[index] <= pivot,则通过 moveToLeft 函数将其左移,确保这些元素按相对顺序聚集到数组左侧。
    若元素 arr[index] > pivot,则记录其数量(rightNum++),后续通过左移操作,将这些元素 “挤” 到基准值右侧。
  3. 元素左移实现
    moveToLeft 函数负责将指定元素左移。通过覆盖移动的方式,在不开辟额外数组空间的前提下,调整元素位置,保证 “小于等于基准值” 的元素按原始相对顺序排列在左侧。
  4. 最终划分
    遍历结束后,数组实现 “左小右大” 的划分:左侧是小于等于基准值的元素(相对顺序不变),右侧是大于基准值的元素(相对顺序不变),基准值位于左右两部分之间。
    整体属于 自定义的原地划分策略,通过元素移动而非额外空间,实现特定规则下的数组重组,同时保留元素相对次序。

方法二思路:

用两个数组实现,把比基准小的放一个数组,比基准大的放一个数组,然后逐一输出小的数组→基准→大的数组

2.3 判断上三角

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

// 判断是否为上三角矩阵的函数
int isupperTriangularMatrix(int mat[][10], int n) {  //注意行参写法
	int i,j;
    for (i = 1; i < n; i++)
        for (j = 0; j < i; j++)
            if (mat[i][j] != 0)
                return 0; // 不是上三角矩阵
    return 1; // 是上三角矩阵
}

int main() {
    int n,i,j;
    // 输入方阵维度
    scanf("%d", &n);
    int matrix[10][10];
    // 输入矩阵元素
    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            scanf("%d", &matrix[i][j]);
        }
    }
    // 调用判断函数
    if (isupperTriangularMatrix(matrix, n)) {
        printf("YES"); // 输出YES
    } else {
        printf("NO"); // 输出NO
    }

    return 0;
}

2.4判断数根

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

//返回n的各位数字之和
int digitSum(int n){
	int sum=0;
	while(n>0){
		sum+=n%10;
		n/=10;
	}
    return sum;
}

int main(){
    int n;
    scanf("%d", &n);
    while ( n >= 10 ){
        n = digitSum(n);
    }
    printf("%d", n);
    return 0;
}

三、排序思想qsort

3.1田忌赛马qsort函数 🚀🚀🚀

在这里插入图片描述
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

// 降序比较函数
int compare(const void* a, const void* b) {
    return *(int*)b - *(int*)a;
}

int main() {
    int N;
    while (1) {
        scanf("%d", &N);
        if (N == 0) break;

        int my_horses[N], opponent_horses[N];
        // 读取自己的马
        for (int i = 0; i < N; i++) {
            scanf("%d", &my_horses[i]);
        }
        // 读取对手的马
        for (int i = 0; i < N; i++) {
            scanf("%d", &opponent_horses[i]);
        }

        // 降序排序
        qsort(my_horses, N, sizeof(int), compare);
        qsort(opponent_horses, N, sizeof(int), compare);

        int win_count = 0;
        int my_left = 0, my_right = N - 1;
        int opp_left = 0, opp_right = N - 1;

        while (my_left <= my_right) {
            // 自己最快的马能赢对手最快的马,赢一场
            if (my_horses[my_right] > opponent_horses[opp_right]) {
                win_count++;
                my_right--;
                opp_right--;
            } 
            // 自己最快的马赢不了对手最快的马,用最慢的马消耗对手最快的马
            else {
                // 自己最慢的马对比对手最快的马,输一场
                if (my_horses[my_left] < opponent_horses[opp_right]) {
                    my_left++;
                    opp_right--;
                } 
                // 平局情况(按规则算输),直接消耗
                else {
                    my_left++;
                    opp_right--;
                }
            }
        }

        // 判断是否赢超过一半
        if (win_count > N / 2) {
            printf("yes\n");
        } else {
            printf("no\n");
        }
    }
    return 0;
}

代码解析:

  1. 输入与排序:读取马的数量和速度,对双方马的速度降序排序,便于后续贪心比较。
  2. 双指针贪心策略
    • my_left(自己最慢的马)、my_right(自己最快的马)。
    • opp_left(对手最慢的马)、opp_right(对手最快的马)。
    • 优先用自己最快的马赢对手最快的马;若赢不了,用自己最慢的马消耗对手最快的马,尽可能保留强马赢更多局。
  3. 结果判断:统计胜利场数,若超过总场数一半,输出yes,否则输出no

qsort是C语言标准库中的一个排序函数,使用快速排序算法对数组进行排序,位于头文件<stdlib.h> 中。下面介绍它的使用方法:

1. 函数原型

void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void *));

2. 参数说明

  • base:指向要排序的数组的第一个元素的指针,也就是数组的起始地址。
  • nitems:数组中元素的数量,例如数组int arr[10],这里nitems就是10
  • size:每个元素的大小,以字节为单位。可以使用sizeof运算符获取,如sizeof(arr[0])
  • compar:指向比较函数的指针,用于确定元素的顺序。比较函数由用户自定义,应接受两个const void *类型的参数,返回一个整数值,具体规则如下:
    • 如果第一个参数小于第二个参数,则返回小于零的值。
    • 如果两个参数相等,则返回零。
    • 如果第一个参数大于第二个参数,则返回大于零的值。

3. 使用示例

  • 对整数数组进行升序排序
#include <stdio.h>
#include <stdlib.h>

// 比较函数,用于升序排序
int compare_ints(const void *a, const void *b) {
    return (*(int*)a - *(int*)b);
}

int main() {
    int arr[] = {5, 2, 3, 1, 4};
    int n = sizeof(arr) / sizeof(arr[0]);

    qsort(arr, n, sizeof(arr[0]), compare_ints);

    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}

在这个示例中,compare_ints函数将两个const void *类型的参数强制转换为int *类型,然后通过减法运算返回比较结果。qsort函数根据这个比较结果对整数数组arr进行排序。

  • 对字符串数组进行排序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 比较函数,用于按字典序升序排序字符串
int compare_strings(const void *a, const void *b) {
    return strcmp(*(const char **)a, *(const char **)b);
}

int main() {
    const char *arr[] = {"welcome", "to", "geeks", "for", "geeks"};
    int n = sizeof(arr) / sizeof(arr[0]);

    qsort(arr, n, sizeof(arr[0]), compare_strings);

    for (int i = 0; i < n; i++) {
        printf("%s ", arr[i]);
    }
    return 0;
}

对于字符串数组,比较函数compare_strings需要将const void *类型的参数强制转换为const char **类型,然后使用strcmp函数进行字符串比较。

  • 对结构体数组进行排序
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int data;
} item;

// 比较函数,用于根据结构体中的数据成员进行升序排序
int compare_items(const void *a, const void *b) {
    return ((item *)a)->data - ((item *)b)->data;
}

int main() {
    item arr[] = {{5}, {2}, {3}, {1}, {4}};
    int n = sizeof(arr) / sizeof(arr[0]);

    qsort(arr, n, sizeof(item), compare_items);

    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i].data);
    }
    return 0;
}

在对结构体数组排序时,compare_items函数将const void *类型的参数强制转换为item *类型,然后根据结构体中的data成员进行比较。

  • qsort比较函数的返回值规则
    • 当比较函数的返回值小于0时,qsort认为第一个参数(a所指向的元素)应该排在第二个参数(b所指向的元素)前面。
    • 当返回值等于0时,两个元素的相对顺序不确定,但都被视为相等。
    • 当返回值大于0时,第一个参数(a所指向的元素)应该排在第二个参数(b所指向的元素)后面。
  • compare_ints函数的运算逻辑:该函数中,abconst void *类型的指针,通过(int*)将它们强制转换为指向整数的指针,再使用*解引用操作符获取指针指向的整数值。然后计算(*(int*)a - *(int*)b), 即第一个整数减去第二个整数:
    • *(int*)a小于*(int*)b,比如*(int*)a3*(int*)b5,那么(*(int*)a - *(int*)b)的结果是-2(小于0) ,按照qsort的规则,此时对应a的元素会被排在对应b的元素前面。
    • *(int*)a等于*(int*)b,例如都为4,则(*(int*)a - *(int*)b)结果是0,这两个元素相对顺序不确定,但被视为相等。
    • *(int*)a大于*(int*)b,比如*(int*)a7*(int*)b2(*(int*)a - *(int*)b)结果是5(大于0), 按照规则,对应a的元素会被排在对应b的元素后面。

qsort排序过程中不断调用这个比较函数,从而使得较小的整数逐渐排在前面,较大的整数逐渐排在后面,最终实现整数数组的升序排序。

3.2 最小乘积

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

// 比较函数,用于qsort排序
int compare(const void *a, const void *b) {
    return *(int *)a - *(int *)b;
}

int main() {
    int n;
    scanf("%d", &n);
    int *arr1 = (int *)malloc(n * sizeof(int));
    int *arr2 = (int *)malloc(n * sizeof(int));
    for (int i = 0; i < n; i++)
        scanf("%d", &arr1[i]);
    for (int i = 0; i < n; i++)
        scanf("%d", &arr2[i]);
    // 对两个数组进行排序
    qsort(arr1, n, sizeof(int), compare);
    qsort(arr2, n, sizeof(int), compare);

    int minProductSum = 0;
    for (int i = 0; i < n; i++)
        minProductSum += arr1[i] * arr2[n - i - 1];
    printf("%d\n", minProductSum);
    free(arr1); 
    free(arr2);
    return 0;
}

贪心的思想 用小数和大数乘

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱康代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值