2021年11月22日到2021年11月28日

位段

        1.位段的成员是int, unsigned int,signed int , char类型

        2.位段的空间是按照需要以4个字节(int)或一个字节(char)的方式来开辟的

        3.位段涉及很多不确定因素,位段是不跨平台的,注意可移植的程序应该避免使用位段。 

        在VS2019中,一个字节中,数据是从右向左存储的,当一个字节中剩余位不够储存一个值的时候,它会被浪费掉,重新开辟一块内存以供使用。

位段的安全性问题

        1.int是有符号类型还是无符号类型不确定。

        2.位段中最大位的数目不确定,(机器是多少位的不确定)。

        3.位段中的成员从左向右分配还是从右向左分配未定义。

        4,当一个结构包含两个位段时,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,舍弃还是利用剩余位,也未定义。

        跟结构相比,位段有同样的效果,而且节省空间。

枚举、

        把可能的取值一一列举

#include<stdio.h>

int main(void) {
	enum Color {
	red = 5,//默认递增1
	green = 8,//这些值都是初值,枚举类型都是常量。之后是不能改的
	blue
};
	enum Color c = blue;
	printf("%d\n", red);
	printf("%d\n", green);
	printf("%d\n", blue);//默认从0开始递增下去

}

枚举的好处:

        1.增加代码的可读性和可维护性

        2.和#define定义的标识符比较,枚举有类型检查,更加严谨。

        3.防止了命名污染(封装)

        4.便于调试

        5.使用方便,一次可以定义多个常量        

        应该要注意,枚举类型的大小就是整型的大小。

联合(共用体)

        共用体包含一系列的成员,特征是这些成员共用同一块空间。

#include<stdio.h>
union Un {
	char c;
	int i;
};
int main(void) {
	union Un u;
	printf("%p\n", &u);
	printf("%p\n", &(u.c));//联合体也叫共用体,一个联合体中会公用一块地方。
	printf("%p\n", &(u.i));
	printf("%zd\n", sizeof(u));
	return 0;
}

        一个联合体的大小,至少是最大成员的大小,但同时联合体也存在内存对齐,它必须是最大对齐数的整数倍,举个栗子:

#include<stdio.h>
union Un {
	char a[5];
	int i;
};
int main(void) {
	union Un u;
	printf("%zd", sizeof(u));
}

采用内存对齐我们可以解释这个结果。       

  在同一时间,联合体中的成员只能使用一个。

        各种排序问题:

1.冒泡排序:

#include<stdio.h>
int main(void) {
	int a[10];
	for (int i = 0; i < 10; i++) {
		scanf_s("%d", &a[i]);
	}
	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 9 - i; j++) {//每次排出一个最大的,所以这里的-i很合适
			if (a[j] > a[j + 1]) {
				int temp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = temp;
			}
		}
	}
	for (int i = 0; i < 10; i++) {
		printf("%d ", a[i]);
	}
}

        这个代码很久之前就写过了,但看了另一些博主的代码,随后引出了此代码的优化问题:如果我们发现排序了一圈之后,并没有发生顺序的变化,那我们可以直接退出循环。

#include<stdio.h>
int main(void) {
	int a[10];
	for (int i = 0; i < 10; i++) {
		scanf_s("%d", &a[i]);
	}
	for (int i = 0; i < 10; i++) {
		int flag = 1;
		for (int j = 0; j < 9 - i; j++) {
			if (a[j] > a[j + 1]) {
				flag = 0;
				int temp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = temp;
			}
		}
		if (flag == 1) {
			break;
		}
	}
	for (int i = 0; i < 10; i++) {
		printf("%d ", a[i]);
	}
}

2.插入排序:

        我对于插入排序的理解就是,以第一个数为基准,从后面开始依次往前面找到第一个比它小的数为止,或者到达数组边界为止。

#include<stdio.h>
int main(void) {
	int a[10];
	for (int i = 0; i < 10; i++) {
		scanf_s("%d", &a[i]);
	}
	for (int i = 0; i < 9; i++) {
		int j = 0;
		int temp = a[i + 1];//将后面的值与前面依次比较
		for (j = i; j >= 0 && a[j] > temp; j--) {//直到找到一个比它小的,或者达到数组边界
			a[j + 1] = a[j];
		}
		a[j + 1] = temp;
	}
	for (int i = 0; i < 10; i++) {
		printf("%d ", a[i]);
	}
}

这里还有另一种写法,思路可能会更加清晰:

#include<stdio.h>
int main(void) {
	int a[10];
	for (int i = 0; i < 10; i++) {
		scanf_s("%d", &a[i]);
	}
	for (int i = 0; i < 9; i++) {
		int end = i;
		int temp = a[end + 1];
		while (end >= 0) {
			if (temp < a[end]) {
				a[end + 1] = a[end];
				--end;
			}
			else {
				break;
			}
		}
		a[end + 1] = temp;
	}
	for (int i = 0; i < 10; i++) {
		printf("%d ", a[i]);
	}
}

 希尔排序

        希尔排序与插入排序大体思路相同,但希尔排序大多数情况是要比插入排序更加高效的,希尔排序采用的是交换相隔一定距离的两个元素的方法进行排序,这种方式比插入排序更加高效,但同样,也更加难以理解。

        希尔排序网上有很多版本,但我感觉有一部分是有问题的,最终我选择了如下版本,代码如下:

#include<stdio.h>
void ShellSort(int* arr, int n)
{
	int gap = n;
	while (gap > 1)
	{
		//每次对gap折半操作
		gap = gap / 2;
		//单趟排序
		for (int i = 0; i < n - gap; ++i)
		{
			int end = i;
			int tem = arr[end + gap];
			while (end >= 0)
			{
				if (tem < arr[end])
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = tem;
		}
	}
}
int main(void) {
	int a[10] = { 9,8,7,6,5,4,3,2,1,0 };
	ShellSort(a, 10);
	for (int i = 0; i < 10; i++) {
		printf("%d ", a[i]);
	}
}

         这便是希尔排序的大致代码,希尔排序采用距离逐次减半的方式进行排序,实质上仍然是插入排序。值得深思。

        这里还有一道针对结构体的练习题:

        用户输入n个学生的学号,姓名和成绩,按成绩从低到高的顺序排列它们,代码如下

        

#include<stdio.h>
#define NAME_MAX 20
struct Stu {
	int stuNumber;
	char name[NAME_MAX];
	int score;
} stu;
struct Num {
	struct Stu stu[100];
	int cnt;
}num;
int main(void) {
	num.cnt = 0;
	int total, j, min;
	printf("请输入你要录入信息的学生总数:");
	scanf_s("%d", &total);
	for (int i = 0; i < total; i++) {
		printf("请输入第%d个学生的信息\n", i + 1);
		printf("请输入学号:");
		scanf_s("%d", &num.stu[num.cnt].stuNumber);
		printf("请输入名字:");
		scanf_s("%s", num.stu[num.cnt].name, NAME_MAX);
		printf("请输入成绩:");
		scanf_s("%d", &num.stu[num.cnt].score);
		num.cnt++;
	}
	for (int i = 0; i < num.cnt; i++) {
		int min = i;
		for (int j = i + 1; j < num.cnt; j++) {
			if (num.stu[j].score < num.stu[min].score) {
				min = j;
			}
			}
		struct Stu temp = num.stu[min];
		num.stu[min] = num.stu[i];
		num.stu[i] = temp;
	}

	for (int i = 0; i < total; i++) {
		printf("分数排名第%d的学生信息:", total-i);
		printf("学号:%d\n", num.stu[i].stuNumber);
		printf("姓名:%s\n", num.stu[i].name);
		printf("分数:%d\n", num.stu[i].score);
}
}

这些就是本周的大致学习内容!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值