位段
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);
}
}
这些就是本周的大致学习内容!