结构体
声明结构体变量的四种方式
1.先定义结构体,再声明结构体变量
struct student{
long number;
char name[20];
char sex;
float score;
};//先定义结构体
struct student s1,s2;//声明结构体变量
2.在定义结构体类型的同时声明结构变量
struct student{
long number;
char name[20];
char sex;
float score;
}s1,s2;//在定义结构体的同时定义结构体变量
3.直接声明结构体变量
struct{//省去结构体名
long number;
char name[20];
char sex;
float score;
}s1,s2;//直接给出结构体变量
此方法因为没有给出结构体名,所以不能用来在后面程序中声明此结构体类型的变量,因此在实际编程是这种方法用的较少。
4.typedef引用别名来定义
typedef struct student STUDENT; //给结构体student定义别名
struct student{
long number;
char name[20];
char sex;
float score;
};
STUDENT s1,s2;//使用别名STUDENT定义结构体
头歌作业
1.从键盘输入两个学生的学号,姓名和成绩(整数),分别存入结构体中,输出成绩较高的学生的学号,姓名和成绩。
#include <stdio.h>
typedef struct student STUDENT;
struct student {
long number;
char name[20];
int score;
};
STUDENT s1, s2;
int main() {
scanf("%ld %s %d", &s1.number, s1.name, &s1.score);
scanf("%ld %s %d", &s2.number, s2.name, &s2.score);
if (s1.score > s2.score) {
printf("%ld %s %d", s1.number, s1.name, s1.score);
} else {
printf("%ld %s %d", s2.number, s2.name, s2.score);
}
return 0;
}
2.有 n 个学生的信息(包括学号,姓名,成绩),要求按照成绩的高低顺序输出学生的信息。
#include <stdio.h>
#include<stdlib.h>
// 定义学生结构体
typedef struct {
int student_id;
char name[50];
int score;
} Student;
// 按成绩降序比较函数
int compare(const void *a, const void *b) {
Student *student_a = (Student *)a;
Student *student_b = (Student *)b;
if (student_a->score < student_b->score) {
return 1;
} else if (student_a->score > student_b->score) {
return -1;
} else {
return 0; // 如果a的成绩等于b的成绩,返回0,表示a与b的顺序不变
}
}
int main() {
int n;
scanf("%d", &n);
Student students[n];
for (int i = 0; i < n; i++)
scanf("%d%s%d", &students[i].student_id, students[i].name, &students[i].score);
// C库快速排序函数
qsort(students, n, sizeof(Student), compare);
//指向待排序数组的起始地址。
//n:数组中元素的个数。
//size:数组中每个元素的大小。
//compare:比较函数的指针,用于确定元素之间的顺序关系。
for (int i = 0; i < n; i++)
printf("%d %s %d\n", students[i].student_id, students[i].name, students[i].score);
return 0;
}
用冒泡排序模拟实现qsort函数
冒泡函数基本写法
void BubbleSort(int* arr, int sz)
{
int i = 0;
int j = 0;
//共进行sz-1趟
for (i = 0; i < sz-1; i++)
{
int flag = 1;//每一趟进来都假设有序
// 每一趟
for (j = 0; j < sz - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0;
}
}
//若falg还是1,说明没有交换->已经有序了break退出
if (flag == 1)
{
break;
}
}
}
int main()
{
int arr[10] = { 2,3,6,7,9,0,0,3,2,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
BubbleSort(arr, sz);
return 0;
}
qsort库函数使用的是什么参数,我们设计的函数就使用什么参数!
//交换 --一个字节一个字节的交换,共交换width次
void Swap(char* buf1, char* buf2, size_t width)
{
size_t i = 0;
for (i = 0; i < width; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
void my_BubbleSort(void* base, size_t num,size_t width, int(*cmp)(const void* e1, const void* e2))
{
//冒泡排序
//若要排序n个元素,只需要进行n-1趟
//每一趟可以少比较一个元素,每一趟可以使一个元素在确定的位置上
//num:要排序元素的个数 类型是size_t
//num是无符号数 防止产生警告 所以i和j也定义为size_t
// size_t == unsigned int
size_t i = 0;
size_t j = 0;
//共进行num-1趟
for (i = 0; i < num; i++)
{
//每一趟
for (j = 0; j < num - 1 - i; j++)
{
//比较
//传地址
//相邻两个元素比较 width:宽度,每个元素所占字节
//排成升序
if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
{
//交换两数
Swap( (char*)base + j * width, (char*)base + (j + 1) * width, width );
}
}
}
}
1.为何将base强制类型转化为char*型指针:
原因:char* 指针+1跳过一个字节,+width:跳过width个字节,指向下一个元素。转化为其他类型不合适
2.交换函数:还要把宽度(每个元素所占字节数)传过去
因为交换的时候是传地址,所以要知道元素的宽度,一个字节一个字节的交换 ,这样也证明了使用char*指针的好处!
3.(char)base + j * width, (char)base + (j + 1) * width,
当j = 0时:比较的是第一个元素和第二个元素
j = 1时,比较的是第二个元素和第三个元素
.... 很妙的写法
3.有三个候选人,每个选民只能投一票,写一程序,用结构体存储数据,求出得票结果。三个候选人为 "Li", "Zhang","Sun"。
#include <stdio.h>
#include<string.h>
typedef struct{
char name[20];
}student;
int main() {
int n,a=0,b=0,c=0;
scanf("%d", &n);
student students[n];
for (int i = 0; i < n; i++)
scanf("%s", &students[i].name);
for (int i = 0; i < n; i++){
if(strcmp(students[i].name,"Li")==0)
a++;
if(strcmp(students[i].name,"Zhang")==0)
b++;
if(strcmp(students[i].name,"Sun")==0)
c++;
}
printf("Li:%d\nZhang:%d\nSun:%d",a,b,c);
return 0;
}
4.使用结构体储存学生信息(包括学号,姓名,3 门课程成绩,总分),要求实现对学生信息修改和删除操作,最多50名学生。
#include <stdio.h>
#include <string.h>
int Count;
struct student {
char sno[20], name[20];
int math, english, chinese, sum;
};
void print(struct student stu) {
printf("%s %s %d %d %d %d\n", stu.sno, stu.name, stu.math, stu.english, stu.chinese, stu.sum);
}
void query_stu(struct student s[], char *name) {
for (int i = 0; i < Count; i++) {
if (strcmp(s[i].name, name) == 0) {
print(s[i]);
}
}
}
void delete_stu(struct student s[], char *sno) {
int index = -1;
for (int i = 0; i < Count; i++) {
if (strcmp(s[i].sno, sno) == 0) {
index = i;//mark
break;
}
}
if (index != -1) {
for (int i = index; i < Count - 1; i++) {
s[i] = s[i + 1];
}
Count--;//shan
}
}
void update_stu(struct student s[], char *sno, int math, int english, int chinese) {
int index = -1;
for (int i = 0; i < Count; i++) {
if (strcmp(s[i].sno, sno) == 0) {
index = i;//mark
break;
}
}
if (index != -1) {
s[index].math = math;
s[index].english = english;
s[index].chinese = chinese;
s[index].sum = math + english + chinese;
}
}
int main(void) {
int n, q;
struct student students[50];
scanf("%d%d", &n, &q);
Count = n;
for (int i = 0; i < n; i++) {
scanf("%s%s%d%d%d", students[i].sno, students[i].name, &students[i].math, &students[i].english, &students[i].chinese);
students[i].sum = students[i].math + students[i].english + students[i].chinese;
}
while (q--) {
int op;
scanf("%d", &op);
char sno[20], name[20];
if (op == 1) {
scanf("%s", name);
query_stu(students, name);//sousuo
}
else if (op == 2) {
int a, b, c;
scanf("%s%d%d%d", sno, &a, &b, &c);
update_stu(students, sno, a, b, c);//gengxin
for (int i = 0; i < Count; i++)
print(students[i]);
}
else {
scanf("%s", sno);
delete_stu(students, sno);//shanchu
for (int i = 0; i < Count; i++)
print(students[i]);
}
}
return 0;
}
链表
链表的建立
在链表建立过程中,首先要建立第一个结点,然后不断地在其尾部增加新结点,直到不需再有新结点,即尾指针指向NULL为止。
设有结构指针变量。
struct note p,p1,*head;
head:用来标志链表头;
p:在链表建立过程中,p总是不断先接受系统动态分配的新结点地址。
p1->next:存储新结点的地址。
头歌作业
1.建立单向链表
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int data;
struct node* next;
} Node;
Node* CreateList(int data)
{
Node* phead = (Node*)malloc(sizeof(Node));
phead->data = data;
phead->next = NULL;
return phead;
}
void InsertNode(Node* phead, int data)
{
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->next = NULL;
Node* cur = phead;
while (cur->next != NULL)
{
cur = cur->next;
}
cur->next = newNode;
}
void ShowList(Node* phead)
{
Node* cur = phead;
while (cur != NULL)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
int main(void)
{
int n;
scanf("%d", &n);
int data;
scanf("%d", &data);
Node* phead = CreateList(data);
int i;
for (i = 1; i < n; i++)
{
scanf("%d", &data);
InsertNode(phead, data);
}
ShowList(phead);
return 0;
}
2.统计单链表中的节点数
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int data;
struct node* next;
} Node;
Node* CreateList(int data)
{
Node* phead = (Node*)malloc(sizeof(Node));
phead->data = data;
phead->next = NULL;
return phead;
}
void InsertNode(Node* phead, int data)
{
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->next = NULL;
Node* cur = phead;
while (cur->next != NULL)
{
cur = cur->next;
}
cur->next = newNode;
}
void ShowList(Node* phead)
{
Node* cur = phead;
while (cur != NULL)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
int CountNodes(Node* phead)
{
int count = 0;
Node* cur = phead;
while (cur != NULL)
{
count++;
cur = cur->next;
}
return count;
}
int main(void)
{
int n;
scanf("%d", &n);
int data;
scanf("%d", &data);
Node* phead = CreateList(data);
int i;
for (i = 1; i < n; i++)
{
scanf("%d", &data);
InsertNode(phead, data);
}
ShowList(phead);
int nodeCount = CountNodes(phead);
printf("%d\n", nodeCount);
return 0;
}
单链表的逆置。
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int data;
struct node* next;
} Node;
Node* CreateList(int data)
{
Node* phead = (Node*)malloc(sizeof(Node));
phead->data = data;
phead->next = NULL;
return phead;
}
void InsertNode(Node* phead, int data)
{
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->next = NULL;
Node* cur = phead;
while (cur->next != NULL)
{
cur = cur->next;
}
cur->next = newNode;
}
void ShowList(Node* phead)
{
Node* cur = phead;
while (cur != NULL)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
Node* ReverseList(Node* phead)
{
if (phead == NULL || phead->next == NULL)
{
return phead;
}
Node* prev = NULL;
Node* cur = phead;
Node* next = NULL;
while (cur != NULL)
{
next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
}
return prev;
}
int main(void)
{
int n;
scanf("%d", &n);
int data;
scanf("%d", &data);
Node* phead = CreateList(data);
int i;
for (i = 1; i < n; i++)
{
scanf("%d", &data);
InsertNode(phead, data);
}
printf("链表逆置前的数据:\n");
ShowList(phead);
Node* reversedList = ReverseList(phead);
printf("链表逆置后的数据:\n");
ShowList(reversedList);
return 0;
}