WEEK 10
10.1 结构
结构
用户自定义的数据类型
struct 结构名
{
类型名 成员变量名;
类型名 成员变量名;
类型名 成员变量名;
……
};
例:
struct Student {
unsigned ID;
char szName[20];
float fGPA;
};
Student 即成为自定义类型的名字,可以用来定义变量
Stuent s1,s2;
- 两个同类型的结构变量,可以互相赋值。但是结构变量之间不能用
“==”、“!=”、“<”、“>”、“<=”、“>=”进行比较运算。 - 一般来说,一个结构变量所占的内存空间的大小,就是结构中所有成员变
量大小之和。结构变量中的各个成员变量在内存中一般是连续存放的,
访问结构变量的成员变量
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct Date {
int year;
int month;
int day;
};
struct StudentEx {
unsigned ID;
char szName[20];
float fGPA;
Date Birthday;
};
int main()
{
StudentEx stu;
cin >> stu.fGPA;
stu.ID = 12345;
strcpy(stu.szName, "Tom");
cout << stu.fGPA;
stu.Birthday.year = 1984;
unsigned int * p = &stu.ID;
}
小声BB:原来把我搞到云里雾里的结构竟如此简单?!
结构变量的初始化
- 结构变量可以在定义时进行初始化
StudentEx stu = { 1234,"Tom",3.78,{ 1984,12,28 }};
结构数组
StudentEx MyClass [50];
StudentEx MyClass2[50] = {
{ 1234,"Tom",3.78,{ 1984,12,28 }},
{ 1235,"Jack",3.25,{ 1985,12,23 }},
{ 1236,"Mary",4.00,{ 1984,12,21 }},
{ 1237,"Jone",2.78,{ 1985,2,28 }}
};
MyClass[1].ID = 1267;
MyClass[2].birthday.year = 1986;
int n = MyClass[2].birthday.month;
cin >> MyClass[0].szName;
指向结构变量的指针
10.2 全局变量、局部变量
- 定义在函数内部的变量叫局部变量(函数的形参也是局部变量)
- 定义在所有函数的外面的变量叫全局变量
- 全局变量在所有函数中均可以使用,局部变量只能在定义它的函数内部使用
- 全局变量都是静态变量。局部变量定义时如果前面加了“static”关键字,
则该变量也成为静态变量 - 静态变量的存放地址,在整个程序运行期间,都是固定不变的
- 非静态变量(一定是局部变量) 地址每次函数调用时都可能不同,在函数的一次
执行期间不变 - 如果未明确初始化,则静态变量会被自动初始化成全0(每个bit都是0),局
部非静态变量的值则随机 - 所有静态变量只初始化一次
静态变量示例
静态变量应用:strtok的实现
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
char str[] = "- This, a sample string, OK.";
char *p = strtok(str, " ,.-");
while (p)
{
cout << p << endl;
p = strtok(NULL, " ,.-");
}
return 0;
}
这块看了好几次终于明白了,就是说先让指针走,跳过分隔字符,即:只要没走到\0并且字符都包含在sep里,则strchr返回值为1,即都是分隔字符,就一直++start,直到走到头或者遇到不是分隔字符的时候结束。下边就是判断如果是走到头儿了就return NULL,如果没有就说明是遇到了非分隔字符,此刻就将start指向的位置赋给指针q,指针q就指向非分隔字符,也就是我们需要的字符。之后,再跳过非分隔字符,即:只要指针没有走到头儿并且字符不在sep中,就一直++start,如果停下来并且没有走到头儿说明是遇到了分隔符号,即:如果*start不是0,那么将它赋值为0,也就是将分隔符号变为\0。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
char * Strtok(char * p, char * sep) //p是指针,sep是分隔符
{
static char * start; //只在第一次的时候寻找start位置
if (p)
start = p;
for (; *start && strchr(sep, *start); ++start); //跳过分隔字符
if (*start == 0)
return NULL;
char * q = start; //q指向所需字符的第一个字符
for (; *start && !strchr(sep, *start); ++start); //跳过非分隔字符
if (*start)
{
*start = 0;
++start;
}
return q;
}
int main()
{
char str[] = "- This, a sample string, OK.";
char *p = Strtok(str, " ,.-");
while (p)
{
cout << p << endl;
p = Strtok(NULL, " ,.-");
}
return 0;
}
10.3 变量的作用域和生存周期
- 静态局部变量的生存期,从定义它语句第一次被执行开始,到整个程序结束为止。
- 函数形参的生存期从函数执行开始,到函数返回时结束。
- 非静态局部变量的生存期,从执行到定义它的语句开始,一旦程序执行到了它的作用域之外,其生存期即告终止。
10.4 简单排序
选择排序
如果有N个元素需要排序,那么首先从N个元素中找到最小的那个(称为第0小的)放在第0个位子上(和原来的第0个位子上的元素交换位置),然后再从剩下的N-1个元素中找到最小的放在第1个位子上,然后再从剩下的N-2个元素中找到最小的放在第2个位子上……直到所有的元素都就位。
#include <iostream>
#include <cstdio>
using namespace std;
void SelectionSort(int a[], int size)
{
for (int i = 0; i < size - 1; ++i) //每次循环后将第i小的元素放好
{
int tmpMin = i; //用来记录从第i个到第size-1个元素中,最小的那个元素的下标
for (int j = i + 1; j < size; ++j)
{
if (a[j] < a[tmpMin])
tmpMin = j;
}
//下面将第i小的元素放在第i个位子上,并将原来占着第i个位子的元素挪到后面
int tmp = a[i];
a[i] = a[tmpMin];
a[tmpMin] = tmp;
}
}
int main()
{
int a[] = { 4,3,2,1 };
for (int i = 0; i < 4; ++i)
cout << a[i] << " ";
SelectionSort(a, 4);
for (int i = 0; i < 4; ++i)
cout << a[i] << " ";
return 0;
}
插入排序
- 将整个数组a分为有序的部分和无序的两个部分。前者在左边,后者在右边。
- 开始有序的部分只有a[0],其余都属于无序的部分
- 每次取出无序部分的第一个(最左边)元素,把它加入到有序部分。假设插入到合适位置p, 则原p位置及其后面的有序部分元素,都向右移动一个位子。有序的部分即增加了一个元素。
- 直到无序的部分没有元素
#include <iostream>
#include <cstdio>
using namespace std;
void InsertionSort(int a[], int size)
{
for (int i = 1; i < size; ++i) //a[i]是最左的无序元素,每次循环将a[i]放到合适位置
{
for (int j = 0; j < i; ++j) //有序部分的下标是从0到i-1,目的是把a[i]插入到a[0]~a[i-1]
{
if (a[j] > a[i]) //要把a[i]放到位置j,原下标j到 i-1的元素都往后移一个位子
{
int temp = a[i]; //先记住这个值
for (int k = i; k > j; --k) //后移
a[k] = a[k - 1];
a[j] = temp; //插入
break;
}
}
}
}
int main()
{
int a[] = { 4,3,2,1 };
for (int i = 0; i < 4; ++i)
cout << a[i] << " ";
InsertionSort(a, 4);
for (int i = 0; i < 4; ++i)
cout << a[i] << " ";
return 0;
}
冒泡排序
- 将整个数组a分为有序的部分和无序的两个部分。前者在右,后者在左边(与插入排序相反)。
- 开始,整个数组都是无序的。有序的部分没有元素。
- 每次要使得无序部分最大的元素移动到有序部分第一个元素的左边。移动的方法是:依次比较相邻的两个元素,如果前面的比后面的大,就交换他们的位置。这样,大的元素就像水里气泡一样不断往上浮。移动结束有序部分增加了一个元素。
- 直到无序的部分没有元素
#include <iostream>
#include <cstdio>
using namespace std;
void BubbleSort(int a[], int size)
{
for (int i = size - 1; i > 0; --i) //i右边的元素,i+1到size-1的元素已经排好序
{//每次要将未排序部分的最大值移动到下标i的位置
for (int j = 0; j < i; ++j)
{
//依次比较相邻的两个元素
if (a[j] > a[j + 1])
{
int tmp = a[j];
a[j] = a[j + 1];
a[j + 1] = tmp;
}
}
}
}
int main()
{
int a[] = { 4,3,2,1 };
for (int i = 0; i < 4; ++i)
cout << a[i] << " ";
BubbleSort(a, 4);
for (int i = 0; i < 4; ++i)
cout << a[i] << " ";
return 0;
}