结构体_字节对齐
结构体变量占据的内存单元的个数应当大于等于其内部所有数据成员占据内存单元数的和。
1、C语言引入了字节对齐机制,一般来说,不同的编译器字节对齐机制有所不同,但还是有以下3条通用准则:
(1)结构体变量的大小能够被其最宽基本类型成员的大小所整除;
(2)结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
(3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
2、说明: 字节对齐第3条准则提及最宽基本类型的概念,所谓基本类型是指像char、short、int、float、double这样的内置数据类型。“数据宽度”就是指其sizeof的大小。诸如结构体、共用体和数组等都不是基本数据类型
1 #define _CRT_SECURE_NO_WARNINGS 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 6 //结构体字节对齐机制 7 // 8 //结构体变量占据的内存单元的个数应当大于等于其内部所有数据成员占据内存单元数的和。 9 // 10 //1、C语言引入了字节对齐机制,一般来说,不同的编译器字节对齐机制有所不同,但还是有以下3条通用准则: 11 // 12 //(1)结构体变量的大小能够被其最宽基本类型成员的大小所整除; 13 // 14 //(2)结构体每个成员相对于结构体首地址的偏移量(offset)都是最宽基本类型成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding); 15 // 16 //(3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。 17 // 18 //2、说明: 字节对齐第3条准则提及最宽基本类型的概念,所谓基本类型是指像char、short、int、float、double这样的内置数据类型。 19 //“数据宽度”就是指其sizeof的大小。诸如结构体、共用体和数组等都不是基本数据类型 20 21 struct info//4 22 { 23 int num;//4 24 }; 25 26 struct info1//8 27 { 28 int num;//4 4 29 char c;//1 4 30 }; 31 32 struct info2//12 33 { 34 char c;//1 4 35 int num;//4 4 36 char c1;//1 4 37 }; 38 39 struct info3//5 40 { 41 char c;//1 42 char ch[4];//4 43 }; 44 45 struct info4//10 46 { 47 char c;//1 48 char ch[9];//9 49 }; 50 51 struct info5//14 52 { 53 char c;//1 2 54 short sh;//2 2 55 char ch[9];//9 10 56 }; 57 58 struct info6//20 59 { 60 char c;//1 4 61 int i;//4 4 62 char ch[9];//9 12 63 }; 64 65 struct info7//11 66 { 67 char c;//1 68 char c1;//1 69 char ch[9];//9 70 }; 71 72 struct info8//32 73 { 74 char c;//1 8 75 double db;//8 8 76 char ch[9];//9 16 77 }; 78 79 struct info9//32 80 { 81 short sh;//2 8 82 double db;//8 8 83 char ch[9];//9 16 84 }; 85 86 struct info10//22 87 { 88 short sh;//2 2 89 char c;//1 char类型一样,不用相加 90 char ch[19];//19 20 91 }; 92 93 struct info11//28 94 { 95 short sh;//2 4 96 int i;//4 4 97 char ch[19];//19 20 98 }; 99 100 main() 101 { 102 printf("sizeof(char)=%d ", sizeof(char));//1 103 printf("sizeof(short)=%d ", sizeof(short));//2 104 printf("sizeof(float)=%d ", sizeof(float));//4 105 printf("sizeof(int)=%d ", sizeof(int));//4 106 printf("sizeof(long)=%d ", sizeof(long));//4 107 printf("sizeof(double)=%d ", sizeof(double));//8 108 printf(" "); 109 110 printf("sizeof(struct info)=%d ", sizeof(struct info));//4 111 112 printf("sizeof(struct info1)=%d ", sizeof(struct info1));//8 113 114 printf("sizeof(struct info2)=%d ", sizeof(struct info2));//12 115 116 printf("sizeof(struct info3)=%d ", sizeof(struct info3));//5 117 118 printf("sizeof(struct info4)=%d ", sizeof(struct info4));//10 119 120 printf("sizeof(struct info5)=%d ", sizeof(struct info5));//14 121 122 printf("sizeof(struct info6)=%d ", sizeof(struct info6));//20 123 124 printf("sizeof(struct info7)=%d ", sizeof(struct info7));//11 125 126 printf("sizeof(struct info8)=%d ", sizeof(struct info8));//32 127 128 printf("sizeof(struct info9)=%d ", sizeof(struct info9));//32 129 130 printf("sizeof(struct info10)=%d ", sizeof(struct info10));//22 131 132 printf("sizeof(struct info11)=%d ", sizeof(struct info11));//28 133 134 system("pause"); 135 }
1 动态结构体
1 #define _CRT_SECURE_NO_WARNINGS 2 3 #include<stdio.h> 4 #include<stdlib.h> 5 6 struct dangdang 7 { 8 char email[30]; 9 char name[30]; 10 char addr[100]; 11 int num; 12 int bignum; 13 char tel[20]; 14 char phone[20]; 15 double rmb; 16 }; 17 18 main() 19 { 20 struct dangdang *p = (struct dangdang *)malloc(sizeof(struct dangdang) * 10); 21 int i; 22 struct dangdang *px; 23 24 for (i = 0;i < 10;i++)//下标循环 25 { 26 sprintf(p[i].email, "123@qq.com"); 27 p[i].num = 100; 28 printf("%s,%d ", p[i].email, p[i].num); 29 } 30 31 for (px = p;px < p + 10;px++)//指针循环px->email 32 { 33 sprintf(px->email, "123@qq.com"); 34 px->num = 100; 35 printf("%s,%d ", px->email, px->num); 36 } 37 38 for (i = 0;i < 10;i++)//指针循环(*(p + i)).email 39 { 40 sprintf((*(p + i)).email, "123@qq.com"); 41 (*(p + i)).num = 100; 42 printf("%s,%d ", (*(p + i)).email, (*(p + i)).num); 43 } 44 45 system("pause"); 46 };
1 设链表中每个结点包括学号、成绩、和指针三个字段, 试编程序打印出链表中第1,3,5,7...结点。
2 设链表中每个结点包括学号、成绩、和指针三个字段, 试编程序将大于平均成绩的各个结点打印出来。
3 设链表中每个结点包括学号、成绩、和指针三个字段, 试编程序将成绩最高的结点作为链表的第一个结点,成绩最低的结点作为尾结点。
4 建立一个链表,每个结点包括:学号、姓名、性别、年龄。输入一个年龄,如果链表中的结点所包含的年龄等于此年龄,则将此结点删去。
5 逆序输出的数列
题目内容:
你的程序会读入一系列的正整数,预先不知道正整数的数量,一旦读到-1,就表示输入结束。然后,按照和输入相反的顺序输出所读到的数字,不包括最后标识结束的-1。
输入格式:
一系列正整数,输入-1表示结束,-1不是输入的数据的一部分。
输出格式:
按照与输入相反的顺序输出所有的整数,每个整数后面跟一个空格以与后面的整数区分,最后的整数后面也有空格。
输入样例:
1 2 3 4 -1
输出样例:
4 3 2 1
时间限制:2000ms内存限制:128000kb
6 插入排序。许多玩牌的人是以这样的方式来对他们手中的牌进行排序的:设手中原有3张牌已排好序,抓1张新牌,若这张新牌的次序在原来的第2张牌之后,第3张牌之前,那么就把这张新牌放在第3张牌的位置上,原来的第3张改为第4张, 然后再抓新牌。按着这个算法,编写一个排序程序。
注:开始一张牌也没有,从第一张牌开始抓起。
7 有两个链表a和b。设结点中包含学号、姓名。从a链表中删除与b链表中有相同学号的那些结点。
8 建立一个链表,每个结点包括的成员为:职工号、工资。用new函数开辟新结点。要求链表包括5个结点,从键盘输入结点中的有效数据。然后把这些结点的数据打印出来。要求用函数creat来建立链表,用list函数来输出数据。这5个职工的职工号是101,103,105,107,109。
在上题的基础上,新增加一个职工数据。这个新结点不放在最后,而是按职工号顺序插入,新职工号为106。写一函数insert来插入结点。
在上两题的基础上,写一函数,用来删除一个结点(按指定职工号删除)。
9 建立两个链表,来表示x幂的两个多项式,链表中的结点有三个字段coef、exp和next,分别表示多项式每项的系数、x的指数及指向下一项的指针。编一程序,按x的降幂输入多项式的系数和指数,建立两个链表,然后编一函数来完成把两个多项式的链表叠加到第三个链表中。例如:
第一个多项式为: -4x8 +5x6 +3x4 -4x的链表为:
-4 8 5 6 3 4 -4 1
第二个多项式为: 5x9 -5x8 -3x4 +7x的链表为:
5 9 -5 8 -3 4 7 1
结果的多项式为: 5x9 -9x8 +5x6 +3x
5 9 -9 8 5 6 3 1
1 设链表中每个结点包括学号、成绩、和指针三个字段, 试编程序打印出链表中第1,3,5,7...结点。
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 struct student 5 { 6 int num;//学号 7 int score;//成绩 8 struct student *next;//下一个结点 9 }; 10 11 typedef struct student STU;//简写 12 13 //涉及5个函数 14 STU *nit();//创建头指针,不存放数据 15 void add(STU *head, int num, int score);//插入数据到尾部 16 void Print(STU *head);//打印,递归 17 void PrintJi(STU *head);//打印奇数结点,非递归 18 void PrintOu(STU *head);//打印偶数结点,非递归 19 20 void main() 21 { 22 STU *head = nit();//创建头指针,不存放数据 23 24 add(head, 1, 10);//插入数据到尾部 25 add(head, 2, 1); 26 add(head, 3, 13); 27 add(head, 4, 15); 28 add(head, 5, 16); 29 add(head, 6, 12); 30 add(head, 7, 17); 31 32 printf("打印,递归 "); 33 Print(head);//打印,递归 34 35 printf("打印奇数结点,非递归 "); 36 PrintJi(head);//打印奇数结点,非递归 37 38 printf("打印偶数结点,非递归 "); 39 PrintOu(head);//打印偶数结点,非递归 40 41 system("pause"); 42 } 43 44 STU *nit()//创建头指针,不存放数据 45 { 46 STU *head = (STU*)malloc(sizeof(STU));//创建头结点 47 if (head == NULL) 48 { 49 printf("分配内存失败 "); 50 return NULL; 51 } 52 else 53 { 54 head->next = NULL;//最后指向NULL 55 return head;//返回头指针 56 } 57 } 58 59 void add(STU *head, int num, int score)//插入数据到尾部 60 { 61 STU *new = (STU*)malloc(sizeof(STU));//第1步,创建指针new,用于存储新数据 62 if (new == NULL) 63 { 64 printf("分配内存失败 "); 65 return; 66 } 67 new->num = num;//学号 68 new->score = score;//成绩 69 new->next = NULL;//最后指向NULL 70 71 STU *p = head;//第2步,创建指针p,用于移动 72 if (p == NULL) 73 { 74 return; 75 } 76 while (p->next != NULL)//遍历 77 { 78 p = p->next; 79 } 80 81 p->next = new;//第3步,指针p指向指针new 82 } 83 84 void Print(STU *head)//打印,递归 85 { 86 if (head->next == NULL) 87 { 88 return; 89 } 90 else 91 { 92 printf("num=%d,score=%d ", head->next->num, head->next->score); 93 Print(head->next);//递归 94 } 95 } 96 97 void PrintJi(STU *head)//打印奇数结点,非递归 98 { 99 STU *p = head;//指向头指针 100 while (p != NULL && p->next != NULL) 101 { 102 printf("num=%d,score=%d ", p->next->num, p->next->score); 103 p = p->next->next;//指向下一个的下一个 104 } 105 } 106 107 void PrintOu(STU *head)//打印偶数结点,非递归 108 { 109 STU *p = head->next;//指向头指针的下一个 110 while (p != NULL && p->next != NULL) 111 { 112 printf("num=%d,score=%d ", p->next->num, p->next->score); 113 p = p->next->next;//指向下一个的下一个 114 } 115 }
2 设链表中每个结点包括学号、成绩、和指针三个字段, 试编程序将大于平均成绩的各个结点打印出来。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #define N 7 4 5 struct student 6 { 7 int num;//学号 8 int score;//成绩 9 struct student *next;//下一个结点 10 }; 11 12 typedef struct student STU;//简写 13 14 //涉及6个函数 15 STU *init();//创建头指针,不存放数据 16 void add(STU *head, int num, int score);//插入数据到尾部 17 void print(STU *head);//打印,递归 18 int Sum(STU *head);//计算总分 19 double Average(int sum, int n);//计算平均成绩 20 void PrintUpAverage(STU *head, double average);//打印大于平均成绩的各个结点 21 22 void main() 23 { 24 int sum = 0; 25 double average = 1.0; 26 27 STU *head = init();//创建头指针,不存放数据 28 29 add(head, 1, 10);//插入数据到尾部 30 add(head, 2, 1); 31 add(head, 3, 13); 32 add(head, 4, 15); 33 add(head, 5, 16); 34 add(head, 6, 12); 35 add(head, 7, 17); 36 37 printf("打印,递归 "); 38 print(head);//打印,递归 39 40 printf("计算总分计算平均成绩 "); 41 sum = Sum(head);//计算总分 42 average = Average(sum, N);//计算平均成绩 43 printf("sum=%d,average=%lf ", sum, average); 44 45 printf("打印大于平均成绩的各个结点 "); 46 PrintUpAverage(head, average);//打印大于平均成绩的各个结点 47 48 system("pause"); 49 } 50 51 STU *init()//创建头指针,不存放数据 52 { 53 STU *head = (STU*)malloc(sizeof(STU));//创建头结点 54 if (head == NULL) 55 { 56 printf("分配内存失败 "); 57 return NULL; 58 } 59 else 60 { 61 head->next = NULL;//最后指向NULL 62 return head;//返回头指针 63 } 64 } 65 66 void add(STU *head, int num, int score)//插入数据到尾部 67 { 68 STU *new = (STU*)malloc(sizeof(STU));//第1步,创建指针new,用于存储新数据 69 if (new == NULL) 70 { 71 printf("分配内存失败 "); 72 return; 73 } 74 new->num = num;//学号 75 new->score = score;//成绩 76 new->next = NULL;//最后指向NULL 77 78 STU *p = head;//第2步,创建指针p,用于移动 79 if (p == NULL) 80 { 81 return; 82 } 83 while (p->next != NULL)//遍历 84 { 85 p = p->next; 86 } 87 88 p->next = new;//第3步,指针p指向指针new 89 } 90 91 void print(STU *head)//打印,递归 92 { 93 if (head->next == NULL) 94 { 95 return; 96 } 97 else 98 { 99 printf("num=%d,score=%d ", head->next->num, head->next->score); 100 print(head->next);//递归 101 } 102 } 103 104 int Sum(STU * head)//计算总分 105 { 106 STU *p = head;//创建指针p指向头指针 107 int sum = 0; 108 while (p->next != NULL) 109 { 110 sum += p->next->score; 111 p = p->next; 112 } 113 return sum; 114 } 115 116 double Average(int sum, int n)//计算平均成绩 117 { 118 return 1.0*sum / n; 119 } 120 121 void PrintUpAverage(STU * head, double average)//打印大于平均成绩的各个结点 122 { 123 STU *p = head;//创建指针p指向头指针 124 while (p->next != NULL) 125 { 126 if (p->score > average) 127 { 128 printf("num=%d,score=%d ", p->next->num, p->next->score); 129 } 130 p = p->next; 131 } 132 }
3 设链表中每个结点包括学号、成绩、和指针三个字段, 试编程序将成绩最高的结点作为链表的第一个结点,成绩最低的结点作为尾结点。
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 struct student 5 { 6 int num;//学号 7 int score;//成绩 8 struct student *next;//下一个结点 9 }; 10 11 typedef struct student STU;//简写 12 13 //涉及7个函数 14 STU *init();//创建头指针,不存放数据 15 void add(STU *head, int num, int score);//插入数据到尾部 16 void print(STU *head);//打印,递归 17 STU *FindMaxPre(STU *head);//查找最大值,返回最大值的前一个结点 18 STU *FindMinPre(STU *head);//查找最小值,返回最小值的前一个结点 19 void AdjustMax(STU *head);//调整最大值 20 void AdjustMin(STU *head);//调整最小值 21 22 void main() 23 { 24 STU *head = init();//创建头指针,不存放数据 25 26 add(head, 1, 10);//插入数据到尾部 27 add(head, 2, 1); 28 add(head, 3, 13); 29 add(head, 4, 15); 30 add(head, 5, 16); 31 add(head, 6, 12); 32 add(head, 7, 17); 33 34 printf("打印,递归 "); 35 print(head);//打印,递归 36 37 AdjustMax(head);//调整最大值 38 AdjustMin(head);//调整最小值 39 40 printf("调整以后 "); 41 print(head);//打印,递归 42 43 system("pause"); 44 } 45 46 STU *init()//创建头指针,不存放数据 47 { 48 STU *head = (STU*)malloc(sizeof(STU));//创建头结点 49 if (head == NULL) 50 { 51 printf("分配内存失败 "); 52 return NULL; 53 } 54 else 55 { 56 head->next = NULL;//最后指向NULL 57 return head;//返回头指针 58 } 59 } 60 61 void add(STU *head, int num, int score)//插入数据到尾部 62 { 63 STU *new = (STU*)malloc(sizeof(STU));//第1步,创建指针new,用于存储新数据 64 if (new == NULL) 65 { 66 printf("分配内存失败 "); 67 return; 68 } 69 new->num = num;//学号 70 new->score = score;//成绩 71 new->next = NULL;//最后指向NULL 72 73 STU *p = head;//第2步,创建指针p,用于移动 74 if (p == NULL) 75 { 76 return; 77 } 78 while (p->next != NULL)//遍历 79 { 80 p = p->next; 81 } 82 83 p->next = new;//第3步,指针p指向指针new 84 } 85 86 void print(STU *head)//打印,递归 87 { 88 if (head->next == NULL) 89 { 90 return; 91 } 92 else 93 { 94 printf("num=%d,score=%d ", head->next->num, head->next->score); 95 print(head->next);//递归 96 } 97 } 98 99 STU *FindMaxPre(STU *head)//查找最大值,返回最大值的前一个结点 100 { 101 STU *p = head;//创建指针p,用于移动 102 STU *MaxPre = head;//创建指针MaxPre,用于保存最大值的前一个结点 103 if (p == NULL || MaxPre == NULL) 104 { 105 return NULL; 106 } 107 else 108 { 109 while (p->next != NULL)//遍历 110 { 111 if (MaxPre->next->score < p->next->score)//查找最大值 112 { 113 MaxPre = p; 114 } 115 p = p->next;//指针移动 116 } 117 118 } 119 return MaxPre;//返回最大值的前一个结点 120 } 121 122 STU *FindMinPre(STU *head)//查找最小值,返回最小值的前一个结点 123 { 124 125 STU *p = head;//创建指针p,用于移动 126 STU *MinPre = head;//创建指针MinPre,用于保存最小值的前一个结点 127 if (p == NULL || MinPre == NULL) 128 { 129 return NULL; 130 } 131 else 132 { 133 while (p->next != NULL)//遍历 134 { 135 if (MinPre->next->score > p->next->score)//查找最小值 136 { 137 MinPre = p; 138 } 139 p = p->next;//指针移动 140 } 141 } 142 return MinPre;//返回最小值的前一个结点 143 } 144 145 void AdjustMax(STU *head)//调整最大值 146 { 147 STU *p = FindMaxPre(head);//第1步,创建指针p,指向最大值的前一个结点 148 STU *q = p->next;//第2步,创建指针q,指向最大值 149 p->next = q->next;//第3步,跳过最大值 150 q->next = head->next;//第4步,指针q的下一个结点指向原来的第一个 151 head->next = q;//第5步,头指针指向最大值 152 } 153 154 void AdjustMin(STU *head)//调整最小值 155 { 156 STU *p = FindMinPre(head);//第1步,创建指针p,指向最小值的前一个结点 157 STU *q = p->next;//第2步,创建指针q,指向最小值 158 p->next = q->next;//第3步,跳过最小值 159 STU *r = head;//第4步,创建指针r,遍历 160 while (r->next != NULL) 161 { 162 r = r->next; 163 } 164 r->next = q;//第5步,指针r指向最小值 165 q->next = NULL;//第6步,最小值指向NULL 166 }
4 建立一个链表,每个结点包括:学号、姓名、性别、年龄。输入一个年龄,如果链表中的结点所包含的年龄等于此年龄,则将此结点删去。
1 #define _CRT_SECURE_NO_WARNINGS 2 #include <stdio.h> 3 #include <stdlib.h> 4 5 struct student 6 { 7 int num;//学号 8 char name[10];//姓名 9 int sex;//性别 10 int age;//年龄 11 struct student *next;//下一个结点 12 }; 13 14 typedef struct student STU;//简写 15 16 //涉及4个函数 17 STU *init();//创建头指针,不存放数据 18 void add(STU *head, int num, const char *name, int sex, int age);//插入数据到尾部 19 void print(STU *head);//打印,递归 20 void delete(STU *head, int age);//根据年龄,删除结点 21 22 void main() 23 { 24 int age = 0;//需要删除的年龄 25 26 STU *head = init();//创建头指针,不存放数据 27 28 add(head, 1, "abc", 1, 12);//插入数据到尾部 29 add(head, 2, "def", 0, 13); 30 add(head, 3, "ghi", 1, 14); 31 add(head, 4, "jkl", 0, 14); 32 add(head, 5, "mno", 1, 15); 33 34 printf("打印,递归 "); 35 print(head);//打印,递归 36 37 scanf("%d", &age); 38 delete(head, age);//根据年龄,删除结点 39 40 printf("删除以后 "); 41 print(head);//打印,递归 42 43 system("pause"); 44 } 45 46 STU *init()//创建头指针,不存放数据 47 { 48 STU *head = (STU*)malloc(sizeof(STU));//创建头结点 49 if (head == NULL) 50 { 51 printf("分配内存失败 "); 52 return NULL; 53 } 54 else 55 { 56 head->next = NULL;//最后指向NULL 57 return head;//返回头指针 58 } 59 } 60 61 void add(STU *head, int num, const char *name, int sex, int age)//插入数据到尾部 62 { 63 STU *new = (STU*)malloc(sizeof(STU));//第1步,创建指针new,用于存储新数据 64 if (new == NULL) 65 { 66 printf("分配内存失败 "); 67 return; 68 } 69 new->num = num;//学号 70 strcpy(new->name, name);//姓名 71 new->sex = sex;//性别 72 new->age = age;//年龄 73 new->next = NULL;//最后指向NULL 74 75 STU *p = head;//第2步,创建指针p,用于移动 76 if (p == NULL) 77 { 78 return; 79 } 80 while (p->next != NULL)//遍历 81 { 82 p = p->next; 83 } 84 85 p->next = new;//第3步,指针p指向指针new 86 } 87 88 void print(STU *head)//打印,递归 89 { 90 if (head->next == NULL) 91 { 92 return; 93 } 94 else 95 { 96 printf("num=%d,name=%s,sex=%d,age=%d ", head->next->num, head->next->name, head->next->sex, head->next->age); 97 print(head->next);//递归 98 } 99 } 100 101 void delete(STU * head, int age)//根据年龄,删除结点 102 { 103 STU *p = head;//创建指针p 104 STU *q = NULL;//创建指针q 105 106 while (p->next != NULL)//遍历链表 107 { 108 if (age == p->next->age)//第1步,p指向需要删除的前面一个结点 109 { 110 q = p->next;//第2步,q指向需要删除的结点 111 p->next = q->next;//第3步,跳过需要删除的 112 free(q);//第4步,free 113 } 114 else 115 { 116 p = p->next;//继续遍历 117 } 118 } 119 }
5 逆序输出的数列
题目内容:
你的程序会读入一系列的正整数,预先不知道正整数的数量,一旦读到-1,就表示输入结束。然后,按照和输入相反的顺序输出所读到的数字,不包括最后标识结束的-1。
输入格式:
一系列正整数,输入-1表示结束,-1不是输入的数据的一部分。
输出格式:
按照与输入相反的顺序输出所有的整数,每个整数后面跟一个空格以与后面的整数区分,最后的整数后面也有空格。
输入样例:
1 2 3 4 -1
输出样例:
4 3 2 1
时间限制:2000ms内存限制:128000kb
1 #define _CRT_SECURE_NO_WARNINGS 2 #include <stdio.h> 3 #include <stdlib.h> 4 5 struct num 6 { 7 int num;//数字 8 struct num *next;//下一个结点 9 }; 10 11 typedef struct num NUM;//简写 12 13 //涉及4个函数 14 NUM *init();//创建头指针,不存放数据 15 void add(NUM *head, int num);//插入数据到尾部 16 void print(NUM *head);//打印,非递归 17 NUM *dao(NUM *head);//链表逆序,返回新的头指针 18 19 void main() 20 { 21 int num = 0; 22 23 NUM *head = init();//创建头指针,不存放数据 24 25 scanf("%d", &num); 26 27 while (num != -1)//输入 - 1表示结束 28 { 29 add(head, num);//插入数据到尾部 30 scanf("%d", &num); 31 } 32 33 NUM *newhead = dao(head);//链表逆序,返回新的头指针 34 35 print(newhead);//打印,非递归 36 37 system("pause"); 38 } 39 40 NUM *init()//创建头指针,不存放数据 41 { 42 NUM *head = (NUM*)malloc(sizeof(NUM));//创建头结点 43 if (head == NULL) 44 { 45 printf("分配内存失败 "); 46 return NULL; 47 } 48 else 49 { 50 head->next = NULL;//最后指向NULL 51 return head;//返回头指针 52 } 53 } 54 55 void add(NUM *head, int num)//插入数据到尾部 56 { 57 NUM *new = (NUM*)malloc(sizeof(NUM));//第1步,创建指针new,用于存储新数据 58 if (new == NULL) 59 { 60 printf("分配内存失败 "); 61 return; 62 } 63 new->num = num;//学号 64 new->next = NULL;//指针new指向NULL 65 66 NUM *p = head;//第2步,创建指针p,用于移动 67 if (p == NULL) 68 { 69 return; 70 } 71 while (p->next != NULL)//遍历 72 { 73 p = p->next; 74 } 75 76 p->next = new;//第3步,指针p指向指针new 77 } 78 79 NUM *dao(NUM *head)//链表逆序,返回新的头指针 80 { 81 NUM * p = NULL;//创建指针p 82 NUM * q = head->next;//创建指针q 83 NUM * r = NULL;//创建指针r 84 85 while (q) 86 { 87 r = q->next;//指针r指向q的下一个结点 88 q->next = p;//指针q指向前面结点 89 p = q;//移动指针p 90 q = r;//移动指针q 91 } 92 93 NUM *newhead = (NUM *)malloc(sizeof(NUM));//创建指针newhead,作为新头指针 94 newhead->next = p;//新头指针指向指针p 95 return newhead;//返回新头指针 96 } 97 98 void print(NUM *head)//打印,非递归 99 { 100 NUM *p = head;//创建指针,用于移动 101 int count = 0;//计数器 102 103 while (p->next != NULL) 104 { 105 if (count) 106 { 107 printf(" "); 108 } 109 printf("%d", p->next->num); 110 p = p->next; 111 count++; 112 } 113 }
6 插入排序。许多玩牌的人是以这样的方式来对他们手中的牌进行排序的:设手中原有3张牌已排好序,抓1张新牌,若这张新牌的次序在原来的第2张牌之后,第3张牌之前,那么就把这张新牌放在第3张牌的位置上,原来的第3张改为第4张, 然后再抓新牌。按着这个算法,编写一个排序程序。
注:开始一张牌也没有,从第一张牌开始抓起。
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 struct card 5 { 6 int num;//牌号 7 struct card *next;//下一个结点 8 }; 9 typedef struct card CARD;//简写 10 11 CARD *init();//创建头结点,不存放数据 12 void insert(CARD *head, int num);//插入结点,升幂排序 13 void print(CARD *head);//打印链表,递归 14 15 void main() 16 { 17 CARD *head = init();//创建头结点,不存放数据 18 19 insert(head, 5);//插入结点,升幂排序 20 insert(head, 4); 21 insert(head, 7); 22 insert(head, 6); 23 24 print(head);//打印链表,递归 25 } 26 27 CARD *init()//创建头结点,不存放数据 28 { 29 CARD *head = (CARD *)malloc(sizeof(CARD));//创建头指针 30 if (head == NULL) 31 { 32 printf("分配内存失败 "); 33 return NULL; 34 } 35 else 36 { 37 head->next = NULL;//最后指向NULL 38 return head;//返回头指针 39 } 40 } 41 42 void insert(CARD *head, int num)//插入结点,升幂排序 43 { 44 if (head == NULL)//如果传入空指针,返回 45 { 46 return; 47 } 48 49 CARD *new = (CARD *)malloc(sizeof(CARD));//创建指针new,用于存储新数据 50 if (new == NULL) 51 { 52 printf("分配内存失败 "); 53 return; 54 } 55 new->num = num;//指针new存储新数据 56 new->next = NULL;//指向new指向NULL 57 58 if (head->next == NULL)//插入结点第1种可能,原来链表为空,即是第一张牌 59 { 60 printf("插入结点第1种可能,原来链表为空,即是第一张牌 "); 61 head->next = new;//头指针指向指针new 62 } 63 else if (head->next->num > num)//插入结点第2种可能,比原来的第一张牌更小,即是插入在原来的第一张牌的前面 64 { 65 printf("插入结点第2种可能,比原来的第一张牌更小,即是插入在原来的第一张牌的前面 "); 66 new->next = head->next;//指针new指向原来的第一个结点 67 head->next = new;//头指针指向指针new 68 } 69 else 70 { 71 CARD *p = head;//创建指针p,用于移动 72 /*需要注意的是:while中两个条件的顺序不能对调!当p->next == NULL时,C编译程序将短路掉第二个条件,不做判断, 73 否则如果先判断p->next->num < num的条件,由于p->next中的值已为NULL,这是再要访问p->next->num,将会发生访问虚地址的错误操作*/ 74 while ((p->next != NULL) && (p->next->num < num))//当p指向的不是NULL,且p指向的下一个牌号比新牌小,继续移动指针p 75 { 76 p = p->next;//指针p移动 77 } 78 if (p->next == NULL)//插入结点第3种可能,新牌最大,即是插入到最后 79 { 80 printf("插入结点第3种可能,新牌最大,即是插入到最后 "); 81 p->next = new;//原来的最后一张牌指向指针new 82 } 83 else//插入结点第4种可能,插入到中间 84 { 85 printf("插入结点第4种可能,插入到中间 "); 86 new->next = p->next;//指针new指向指针p下一个结点 87 p->next = new;//指针p指向指针new 88 } 89 } 90 } 91 92 void print(CARD *head)//打印链表,递归 93 { 94 if (head->next == NULL)//结束递归 95 { 96 return; 97 } 98 else 99 { 100 printf("num=%d ", head->next->num); 101 print(head->next);//继续递归 102 } 103 }
7 有两个链表a和b。设结点中包含学号、姓名。从a链表中删除与b链表中有相同学号的那些结点。
1 #define _CRT_SECURE_NO_WARNINGS 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 6 struct student 7 { 8 int ID;//学号 9 char name[100];//姓名 10 struct student *next;//下一个结点 11 }; 12 13 typedef struct student STUDENT; 14 15 STUDENT *init();//创建头指针,不存放数据 16 void add(STUDENT *head, int ID, const char *name);//插入数据到尾部 17 void print(STUDENT *head);//打印,递归 18 void delete(STUDENT * headA, STUDENT * headB);//从a链表中删除与b链表中有相同学号的那些结点 19 20 void main() 21 { 22 STUDENT *headA = init();//创建头指针,不存放数据 23 STUDENT *headB = init();//创建头指针,不存放数据 24 25 add(headA, 1, "abc");//插入数据到尾部 26 add(headA, 2, "def"); 27 add(headA, 3, "ghi"); 28 add(headA, 3, "jkl"); 29 30 add(headB, 5, "mno");//插入数据到尾部 31 add(headB, 3, "pqr"); 32 add(headB, 2, "stu"); 33 add(headB, 7, "vwx"); 34 35 printf("打印链表a,递归 "); 36 print(headA); 37 printf("打印链表b,递归 "); 38 print(headB); 39 40 printf("从a链表中删除与b链表中有相同学号的那些结点 "); 41 delete(headA, headB);//从a链表中删除与b链表中有相同学号的那些结点 42 printf("打印链表a,递归 "); 43 print(headA); 44 printf("打印链表b,递归 "); 45 print(headB); 46 } 47 48 STUDENT *init()//创建头指针,不存放数据 49 { 50 STUDENT *head = (STUDENT *)malloc(sizeof(STUDENT));//创建头指针 51 52 if (head == NULL) 53 { 54 printf("分配内存失败 "); 55 return NULL; 56 } 57 else 58 { 59 head->next = NULL;//最后指向NULL 60 return head;//返回头指针 61 } 62 } 63 64 void add(STUDENT *head, int ID, const char *name)//插入数据到尾部 65 { 66 STUDENT *new = (STUDENT *)malloc(sizeof(STUDENT));//第1步,创建指针new,用于存储新数据 67 if (new == NULL) 68 { 69 printf("分配内存失败 "); 70 return; 71 } 72 new->ID = ID;//学号 73 strcpy(new->name, name);//姓名 74 new->next = NULL;//最后指向NULL 75 76 STUDENT *p = head;//第2步,创建指针p,用于移动 77 if (p == NULL) 78 { 79 return; 80 } 81 while (p->next != NULL)//遍历 82 { 83 p = p->next; 84 } 85 86 p->next = new;//第3步,指针p指向指针new 87 } 88 89 void print(STUDENT *head)//打印,递归 90 { 91 if (head->next == NULL) 92 { 93 return; 94 } 95 else 96 { 97 printf("ID=%d,name=%s ", head->next->ID, head->next->name); 98 print(head->next); 99 } 100 } 101 102 void delete(STUDENT * headA, STUDENT * headB)//从a链表中删除与b链表中有相同学号的那些结点,升级版delete 103 { 104 STUDENT *pa = headA;//创建指针pa指向链表a 105 STUDENT *pb = headB;//创建指针pb指向链表b 106 STUDENT *q = NULL;//创建指针q 107 int flag = 0;//1代表找到有相同的,0代表没有找到 108 109 while (pa->next != NULL)//外循环,a链表,需要删除结点的链表 110 { 111 pb = headB;//恢复到链表b开始,重新遍历 112 flag = 0;//0代表没有找到 113 114 while (pb->next != NULL)//内循环,b链表,查找相同结点的链表 115 { 116 if (pa->next->ID == pb->next->ID)//第1步,pa指向需要删除的前面一个结点 117 { 118 flag = 1;//1代表找到有相同的 119 q = pa->next;//第2步,q指向需要删除的结点 120 pa->next = q->next;//第3步,跳过需要删除的 121 free(q);//第4步,free 122 break;//结束链表b的遍历 123 } 124 else 125 { 126 pb = pb->next;//继续遍历 127 } 128 } 129 130 if (!flag)//如果没有找到,则链表a继续向前。如果找到了,之前在if语句中已经跳过需要删除的,链表a已经向前了,不能重复 131 { 132 pa = pa->next;//继续遍历 133 } 134 } 135 }
8 建立一个链表,每个结点包括的成员为:职工号、工资。用new函数开辟新结点。要求链表包括5个结点,从键盘输入结点中的有效数据。然后把这些结点的数据打印出来。要求用函数creat来建立链表,用list函数来输出数据。这5个职工的职工号是101,103,105,107,109。
在上题的基础上,新增加一个职工数据。这个新结点不放在最后,而是按职工号顺序插入,新职工号为106。写一函数insert来插入结点。
在上两题的基础上,写一函数,用来删除一个结点(按指定职工号删除)。
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 struct staff 5 { 6 int ID;//职工号 7 int salary;//工资 8 struct staff *next;//下一个结点 9 }; 10 typedef struct staff STAFF;//简写 11 12 STAFF *create();//创建头结点,不存放数据 13 void insert(STAFF *head, int ID, int salary);//插入结点,升幂排序 14 void list(STAFF *head);//打印,递归 15 void delete(STAFF * head, int ID);//根据指定职工号删除结点 16 17 void main() 18 { 19 STAFF *head = create();//创建头结点,不存放数据 20 21 insert(head, 101, 1000);//插入结点,升幂排序 22 insert(head, 103, 2000); 23 insert(head, 105, 3000); 24 insert(head, 107, 4000); 25 insert(head, 109, 5000); 26 27 insert(head, 106, 6000); 28 29 list(head);//打印,递归 30 31 printf("根据指定职工号删除结点 "); 32 33 delete(head, 105);//根据指定职工号删除结点 34 delete(head, 103); 35 36 list(head);//打印,递归 37 } 38 39 STAFF *create()//创建头结点,不存放数据 40 { 41 STAFF *head = (STAFF *)malloc(sizeof(STAFF));//创建头指针 42 43 if (head == NULL) 44 { 45 printf("分配内存失败 "); 46 return NULL; 47 } 48 else 49 { 50 head->next = NULL;//最后指向NULL 51 return head;//返回头指针 52 } 53 } 54 55 void insert(STAFF *head, int ID, int salary)//插入结点,升幂排序 56 { 57 if (head == NULL)//如果传入空指针,返回NULL 58 { 59 return; 60 } 61 62 STAFF *new = (STAFF *)malloc(sizeof(STAFF));//创建指针new,用于存储新数据 63 if (new == NULL) 64 { 65 printf("分配内存失败 "); 66 return; 67 } 68 new->ID = ID;//职工号 69 new->salary = salary;//工资 70 new->next = NULL;//最后指向NULL 71 72 if (head->next == NULL)//第1种可能,原来链表为空,即是第一个职工号 73 { 74 printf("第1种可能,原来链表为空,即是第一个职工号 "); 75 head->next = new;//头指针指向指针new 76 } 77 else if (head->next->ID > ID)//第2种可能,原来的第一个职工号大于新插入的,即是插入在原来的第一个职工号的前面 78 { 79 printf("第2种可能,原来的第一个职工号大于新插入的,即是插入在原来的第一个职工号的前面 "); 80 new->next = head->next;//指针new指向原来的第一个结点 81 head->next = new;//头指针指向指针new 82 } 83 else 84 { 85 STAFF *p = head;//创建指针p,用于移动 86 /*需要注意的是:while中两个条件的顺序不能对调!当p->next == NULL时,C编译程序将短路掉第二个条件,不做判断, 87 否则如果先判断p->next->ID < ID的条件,由于p->next中的值已为NULL,这是再要访问p->next->ID,将会发生访问虚地址的错误操作*/ 88 while ((p->next != NULL) && (p->next->ID < ID))//当p指向的不是NULL,且p指向的下一个职工号比新插入小,继续移动指针p 89 { 90 p = p->next; 91 } 92 if (p->next == NULL)//第3种可能,新插入的职工号最大,即是插入到最后 93 { 94 printf("第3种可能,新插入的职工号最大,即是插入到最后 "); 95 p->next = new;//原来的最后结点指向指针new 96 } 97 else//第4种可能,插入到中间 98 { 99 printf("第4种可能,插入到中间 "); 100 new->next = p->next;//指针new指向指针p下一个结点 101 p->next = new;//指针p指向指针new 102 } 103 } 104 } 105 106 void list(STAFF *head)//打印,递归 107 { 108 if (head->next == NULL) 109 { 110 return; 111 } 112 else 113 { 114 printf("ID=%d,salary=%d ", head->next->ID, head->next->salary); 115 list(head->next); 116 } 117 } 118 119 void delete(STAFF *head, int ID)//根据指定职工号删除结点 120 { 121 STAFF *p = head;//创建指针p 122 STAFF *q = NULL;//创建指针q 123 124 while (p->next != NULL)//遍历链表 125 { 126 if (p->next->ID == ID)//第1步,p指向需要删除的前面一个结点 127 { 128 q = p->next;//第2步,q指向需要删除的结点 129 p->next = q->next;//第3步,跳过需要删除的 130 free(q);//第4步,free 131 } 132 else 133 { 134 p = p->next;//继续遍历 135 } 136 } 137 }
9 建立两个链表,来表示x幂的两个多项式,链表中的结点有三个字段coef、exp和next,分别表示多项式每项的系数、x的指数及指向下一项的指针。编一程序,按x的降幂输入多项式的系数和指数,建立两个链表,然后编一函数来完成把两个多项式的链表叠加到第三个链表中。例如:
第一个多项式为: -4x8 +5x6 +3x4 -4x的链表为:
-4 8 5 6 3 4 -4 1
第二个多项式为: 5x9 -5x8 -3x4 +7x的链表为:
5 9 -5 8 -3 4 7 1
结果的多项式为: 5x9 -9x8 +5x6 +3x
5 9 -9 8 5 6 3 1
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 struct mi 5 { 6 int coef;//系数 7 int exp;//指数 8 struct mi *next;//下一个结点 9 }; 10 typedef struct mi MI;//简写 11 12 MI *create();//创建头结点,不存放数据 13 void insert(MI *head, int coef, int exp);//插入结点,降幂排序 14 void list(MI *head);//打印,非递归 15 void MiAdd(MI *head3, MI *head1, MI *head2);//把两个多项式的链表叠加到第三个链表中 16 17 void main() 18 { 19 MI *head1 = create();//创建头结点,不存放数据 20 MI *head2 = create(); 21 MI *head3 = create(); 22 23 insert(head1, -4, 8);//插入结点,降幂排序 24 insert(head1, 5, 6); 25 insert(head1, 3, 4); 26 insert(head1, -4, 1); 27 28 insert(head2, 5, 9);//插入结点,降幂排序 29 insert(head2, -5, 8); 30 insert(head2, -3, 4); 31 insert(head2, 7, 1); 32 33 list(head1);//打印,非递归 34 list(head2); 35 36 MiAdd(head3, head1, head2);//把两个多项式的链表叠加到第三个链表中 37 38 list(head3);//打印,非递归 39 } 40 41 MI *create()//创建头结点,不存放数据 42 { 43 MI *head = (MI *)malloc(sizeof(MI));//创建头指针 44 45 if (head == NULL) 46 { 47 printf("分配内存失败 "); 48 return NULL; 49 } 50 else 51 { 52 head->next = NULL;//最后指向NULL 53 return head;//返回头指针 54 } 55 } 56 57 void insert(MI *head, int coef, int exp)//插入结点,降幂排序 58 { 59 if (head == NULL)//如果传入空指针,返回NULL 60 { 61 return; 62 } 63 64 MI *new = (MI *)malloc(sizeof(MI));//创建指针new,用于存储新数据 65 if (new == NULL) 66 { 67 printf("分配内存失败 "); 68 return; 69 } 70 new->coef = coef;//系数 71 new->exp = exp;//指数 72 new->next = NULL;//最后指向NULL 73 74 if (head->next == NULL)//插入结点第1种可能,原来链表为空,即是第一个指数 75 { 76 printf("插入结点第1种可能,原来链表为空,即是第一个指数 "); 77 head->next = new;//头指针指向指针new 78 } 79 else if (exp > head->next->exp)//插入结点第2种可能,新插入的指数大于原来的第一个指数,即是插入在原来的第一个指数的前面 80 { 81 printf("插入结点第2种可能,新插入的指数大于原来的第一个指数,即是插入在原来的第一个指数的前面 "); 82 new->next = head->next;//指针new指向原来的第一个结点 83 head->next = new;//头指针指向指针new 84 } 85 else 86 { 87 MI *p = head;//创建指针p,用于移动 88 /*需要注意的是:while中两个条件的顺序不能对调!当p->next == NULL时,C编译程序将短路掉第二个条件,不做判断, 89 否则如果先判断(p->next->exp > exp)的条件,由于p->next中的值已为NULL,这是再要访问(p->next->exp),将会发生访问虚地址的错误操作*/ 90 while ((p->next != NULL) && (p->next->exp > exp))//当p指向的不是NULL,且p指向的下一个指数比新插入的指数大,继续移动指针p 91 { 92 p = p->next; 93 } 94 if (p->next == NULL)//插入结点第3种可能,新插入的指数最小,即是插入到最后 95 { 96 printf("插入结点第3种可能,新插入的指数最小,即是插入到最后 "); 97 p->next = new;//原来的最后结点指向指针new 98 } 99 else//插入结点第4种可能,插入到中间 100 { 101 printf("插入结点第4种可能,插入到中间 "); 102 new->next = p->next;//指针new指向指针p下一个结点 103 p->next = new;//指针p指向指针new 104 } 105 } 106 } 107 108 void list(MI *head)//打印,非递归 109 { 110 MI *p = head; 111 112 while (p->next) 113 { 114 if (p->next->coef >= 0)//如果系数是正数或者0,前面加上+ 115 { 116 printf("+"); 117 } 118 printf("%dx(%d)", p->next->coef, p->next->exp); 119 p = p->next; 120 } 121 122 printf(" "); 123 } 124 125 void MiAdd(MI *head3, MI *head1, MI *head2)//把两个多项式的链表叠加到第三个链表中 126 { 127 MI *p = head1;//p指向head1 128 MI *q = head2;//q指向head2 129 130 while (p->next || q->next) 131 { 132 if (p->next && q->next)//链表相加第1种可能,如果p的下一个结点和q的下一个结点都不为空 133 { 134 printf("链表相加第1种可能,如果p的下一个结点和q的下一个结点都不为空 "); 135 if (p->next->exp > q->next->exp)//链表相加第1.1种可能,如果p的下一个结点的指数大于q的下一个结点的指数 136 { 137 printf("链表相加第1.1种可能,如果p的下一个结点的指数大于q的下一个结点的指数 "); 138 insert(head3, p->next->coef, p->next->exp);//把p的结点插入到head3 139 p = p->next;//p继续移动 140 } 141 else if (p->next->exp < q->next->exp)//链表相加第1.2种可能,如果p的下一个结点的指数小于q的下一个结点的指数 142 { 143 printf("链表相加第1.2种可能,如果p的下一个结点的指数小于q的下一个结点的指数 "); 144 insert(head3, q->next->coef, q->next->exp);//把q的结点插入到head3 145 q = q->next;//q继续移动 146 } 147 else//链表相加第1.3种可能,如果p的下一个结点的指数等于q的下一个结点的指数 148 { 149 printf("链表相加第1.3种可能,如果p的下一个结点的指数等于q的下一个结点的指数 "); 150 if ((p->next->coef) + (q->next->coef))//链表相加第1.3.1种可能,如果p的下一个结点的系数和q的下一个结点的系数相加不等于0 151 { 152 printf("链表相加第1.3.1种可能,如果p的下一个结点的系数和q的下一个结点的系数相加之和不等于0 "); 153 insert(head3, (p->next->coef) + (q->next->coef), p->next->exp);//把系数相加后的结点插入到head3 154 } 155 else//链表相加第1.3.2种可能,如果p的下一个结点的系数和q的下一个结点的系数相加之和等于0,不需要插入 156 { 157 printf("链表相加第1.3.2种可能,如果p的下一个结点的系数和q的下一个结点的系数相加之和等于0,不需要插入 "); 158 } 159 160 p = p->next;//p继续移动 161 q = q->next;//q继续移动 162 } 163 } 164 else if (p->next && q->next == NULL)//链表相加第2种可能,如果p下一个结点不为空,q下一个结点为空 165 { 166 printf("链表相加第2种可能,如果p下一个结点不为空,q下一个结点为空 "); 167 insert(head3, p->next->coef, p->next->exp);//把p的结点插入到head3 168 p = p->next;//p继续移动 169 } 170 else//链表相加第3种可能,如果p下一个结点为空,q下一个结点不为空 171 { 172 printf("链表相加第3种可能,如果p下一个结点为空,q下一个结点不为空 "); 173 insert(head3, q->next->coef, q->next->exp);//把q的结点插入到head3 174 q = q->next;//q继续移动 175 } 176 } 177 }