又想让数据元素类型相同,且具有先后顺序;
设集合X上有一全序关系,如果我们把这种关系用 ≤ 表述,则下列陈述对于 X 中的所有 a, b 和 c 成立:
如果 a ≤ b 且 b ≤ a 则 a = b (反对称性)
如果 a ≤ b 且 b ≤ c 则 a ≤ c (传递性)
a ≤ b 或 b ≤ a (完全性)
配对了在其上相关的全序的集合叫做全序集合(totally ordered set)、线序集合(linearly ordered set)、简单序集合(simply ordered set)或链(chain)。
(任意两个元素可比)
偏序是指,集合中只有部分元素之间可以比较的关系。比如复数集中并不是所有的数都可以比较大小,那么“大小”就是复数集的一个偏序关系。
tree:b,c不可比,则不存在x可以同时与b,c比较。tree是几条线序关系的连接(维度增加)。
graph:
来自简书的链接(非原创)
数据结构有很多种,一般来说,按照数据的逻辑结构对其进行简单的分类,包括线性结构和非线性结构两类。
线性结构
简单地说,线性结构就是表中各个结点具有线性关系。如果从数据结构的语言来描述,线性结构应该包括如下几点:
1、线性结构是非空集。
2、线性结构有且仅有一个开始结点和一个终端结点。
3、线性结构所有结点都最多只有一个直接前趋结点和一个直接后继结点。
线性表就是典型的线性结构,还有栈、队列和串等都属于线性结构。
非线性结构
简单地说,非线性结构就是表中各个结点之间具有多个对应关系。如果从数据结构的语言来描述,非线性结构应该包括如下几点:
1、非线性结构是非空集。
2、非线性结构的一个结点可能有多个直接前趋结点和多个直接后继结点。
在实际应用中,数组、广义表、树结构和图结构等数据结构都属于非线性结构。
**初始化!!!!!!!!!!!
数组的逐元素操作
练习2. 定义一个能容纳10个元素的整形数组a,
1)从键盘读取多个整数存放到数组中,以换行结束。
2)然后,从键盘再次读取整数x,要求删除数组 a中值为x的元素。要求被删除的数组元素之后的元素都要前移。
留言条:int len/last
真正有效的边界
用数组保存输入的多个整数
查找数组中值为x的元素下标i
将i之后的数组元素逐个前移
打印整个数组
#include<stdio.h>
int main() {
int a[10]={0},n,x,find;
int last=-1,i,j;
char ch=0;
while('\n'!=ch&&last<9){
scanf("%d",&n);
last++;
a[last]=n;
ch=getchar();
//防止输入不满十个数时的情况
}
scanf("%d",&x);
for (i=0,find=0;i<=last && !find;i++) if (a[i]==x) find=1;
printf("i=%d\n",i);
if (find){
for (j=i;j<=last;j++) a[j-1]=a[j];
last--;
}
for (i=0;i<=last;i++) printf("%d ",a[i]);
return 0;
}
练习3.
定义一个能容纳10个元素的整形数组a, 从键盘读取多个整数(换行结束)倒序存放到数组中。
分析:如何倒序?
模仿栈,每读一个整数,插入到数组a[0],原有 元素从尾到头逐个后移。
倒序打印数组
int main() {
int a[10]={0};
int last=-1,i;
char ch=0;
while('\n'!=ch&&last<9){
scanf("%d",&n);
last++;
a[last]=n;
ch=getchar();
}
for (i=last;i>=0;i--) printf("%d ",a[i]);
return 0;
}
倒序存储数组的算法设计
将下标0到last的 元素逐个后移
a[0]=读取的新数
打印整个数组
int main() {
int a[10]={0},n,x,find;
int last=-1,i,j;
char ch=0;
while('\n'!=ch&&last<9){
scanf("%d",&n);
for (i=last;i>=0;i--) a[i+1]=a[i]; //退一格,前端输入,退一格
last++;
a[0]=n;
ch=getchar();
}
for (i=0;i<=last;i++) printf("%d ",a[i]);
return 0;
}
数组作为函数参数的处理
数组用作函数参数有两种形式,
1、将 数组元素 (下标变量)作为实参传递给函数;
2、将 数组名 作为实参传递给函数,目的是让被调用函数能访问、操作该数组。
数组名实际上是数组的首元素地址
一、数组元素作函数实参
数组元素就是下标变量,它与普通变量并无区别。 因此它作为函数实参使用时与普通变量完全相同,在发生函数调用时,把作为实参的数组元素的值传送给形参,实现单向的按值传送。
二、将 数组名 作为函数的实参
目的:数组名作为函数的实参时,传递的是数组的首地址 (第一个元素的地址)。 使得被调用函数能够访问、操 作原数组!
方法:要求形参和相对应的实参都必须是类型相同的数组, 都必须有明确的数组说明,此时被调函数实际操作的是原数组。同时,通常要将数组的大小传递给函数。
机理:将数组名作为实参传递给函数,函数就获得了数组的首地址,根据首地址能计算出原数组各个元素的内存地址,从而访问这些数组元素。
数组作为函数参数的处理
#include<stdio.h>
#define SIZE 5
void sizeofArrayPara(int [],int);/*函数原型中数组类型的参数 ,[]中不必包含数组的长度*/
int main() {
int a[SIZE]={1,2,0,3,4};
int i;
printf("array a size is %d\n",sizeof(a));
sizeofArray(a,5);
}
void sizeofArrayPara(int b[],int size){
printf("array b size is %d\n",sizeof(b));
printf("%d",size*sizeof(int));
}
数组作为函数参数的处理
由于数组总是通过模拟传引用的方式传递的, 所以难以防范函数修改数组的值。为了限制函数对数组的修改,可以使用const限定符。
eg.void outputArray(const int data[], int last)
尾插法创建数组
int createArrayTail(int data[], int size) {
int last=-1;
char ch=0;
while('\n'!=ch&&last<size-1){
scanf("%d",&n);
last++;
data[last]=n;
ch=getchar();
}
return last;
}
头插法创建数组
int createArrayHead(int data[], int size) {
int last=-1,i;
char ch=0;
while('\n'!=ch&&last<size-1){
scanf("%d",&n);
for (i=last;i>=0;i--) data[i+1]=data[i];
last++;
data[0]=n;
ch=getchar();
}
return last;
}
➢线性表处理可抽象出一些基本操作,如:
➢增加/删除表中的元素
➢查找/修改表中的某个元素
➢输入/输出表
➢排序
➢一般地,线性表的程序设计采用模块化思想 (C语言的函数),通过定义和调用模块,完成线性表的各种应用。在设计模块(函数)时, 应遵循"高内聚、低耦合"的设计原则。
线性表的基本操作— 查找数组元素
设计一个函数,查找某个元素在数组中的下标并返回。 若存在多个符合条件的元素,则只返回第一个符合条 件元素的下标。
函数设计考虑:
参数设计 :
➢数组名为参数传入
➢数组的最大有效位置作为参数传入;
➢要查找的值作为参数传入;
返回结果 :若找到,则返回元素下标,否则返回-1 ;
线性表的基本操作— 删除表中元素的函数
函数设计考虑:
参数设计 :
➢数组名、数组最尾元素下标作为参数传入;
➢删除元素的下标作为参数传入;
返回结果 :如果待删除元素在数组中,则返回1;否 则返回-1
功能设计 :删除数组中指定下标,需要移动数组的元素,将待删元素后面的元素依次往前移一个位置。
线性表的基本操作— 插入元素
函数设计考虑:
参数设计 :
➢数组名、数组的大小作为参数传入;
➢数组中已存放的元素个数作为参数传入;
➢插入元素、插入位置作为参数传入;
返回结果 :成功插入,则返回1;数组未满但插入位置不合理(if i<0 && i>last+1),返回-1;数组已满(if last == size-1) 而无法插入,返回 -2 ;
功能设计 :需要移动数组的元素,为待插入的元素留出位置。
数组用于存储线性表,线性表中的元素是相邻的,这就要求它们在数组中的存储单元也要相邻。如果它们在数组中不是使用连续的存储空间,那就无法标识哪些是有效的数组元素。
设计一个递归函数,逆序打印整数数组.
void prtArrayRec(int a[], int last) {
if (last==-1) return;
if (last>0) prtArrayRec(&a[1],last-1);
printf("%d ",a[0]);
}
字符数组
在C语言中没有专门的字符串变量。通常用一个字符数组来存放一个字符串,并以字符‘\0’作为字符串的结束符。‘\0’对应的ASCII码为0。
在声明一个容纳字符串的字符数组时,数组的大小应足以容纳字符串中的字符以及字符串结束符 ‘\0’
字符数组初始化三种方式:
char a[]={‘f’, ‘i’, ‘r’, ‘s’,‘t’, ‘\0’};
也可写为:char a[]={“first”};
或去掉{}写为: char a[]=“first”;
字符数组初始化 三种方式: char a[]={‘f’, ‘i’, ‘r’, ‘s’,‘t’, ‘\0’}; 也可写为:char a[]={“first”}; 或去掉{}写为: char a[]=“first”;
后两种初始化情况中,‘\0’是系统自动加上的。 上述声明中没有指定数组的长度,编译器会根据字符串 的长度来确定数组的长度(字符串长度+1)
注意:对一个字符数组,如果不作初始化赋值,则必须说明数组长度,否则编译出错!
在采用字符串方式后,字符数组的输入输出有以下几种方式:
1.定义字符数组时进行初始化。 2.使用循环语句逐个地输入、输出每个字符。 3.用printf函数/scanf函数、gets函数/puts函数一 次性输出、输入一个字符数组中的所有字符。
用printf函数和scanf函数一次性输出、 输入一个字符数组中的所有字符
void main() {
char st[200]; printf(“input string:\n”);
scanf("%s",st); /注意:是st而不是&st!因为数组 名代表了数组的首地址/
printf("%s",st); /注意:转换说明符是%s/
}
scanf函数读取用户键入的字符到字符数组,直到遇到空格、回车、或文件结束符(EOF)为止。空格、回车、 或文件结束符被丢弃,最后一个字符读入后往字符数组 中写入结束符‘\0’。 Printf输出时‘\0’不输出。
注意:scanf不关心字符数组的大小,所以它往数组中写 字符时,所写入的字符可能超出数组的范围。程序员必 须自己控制
字符数组
scanf("%s",&st[1]); /将输入存放到字符数组 第二个单元起的连续单元中/
printf("%s",&st[1]);/输出字符数组中从第二个 字符开始的所有字符。注意必须有&,否则出错!
读、写一行字符:
• char * gets(char * s); 从标准输入设备(如键盘)读取字符到s所指向的数组中,直到读到文件末尾或者新行符‘\n’。新行符被丢弃,最后一个字符读入后写入一个‘\0’。若成功则返回s,若无字符读入数组或者读取失败返回空指针NULL。
• int puts(const char * s); 将s所指向的字符串输出到标准输出设备(如显示器),并在输出中添加一个新行符‘\n’ 。终止 字符串的 ‘\0’不被输出。
使用gets,若只是输入回车,则未读取任何字符到数组。
使用scanf,若只是输入回车或者空格,则程序一直在等待,直到输入一个非回车、非空格字符。 即:scanf无法实现空行的读取!
gets的输入分割符只有回车,gets能够读入空格
scanf在读取非空白符之前会忽略回车,读取之后如果遇到空白字符会停止输入,将其留着缓冲区里;gets只要一遇到回车就输入结束,并把这个回车从缓冲区里移走。
gets可以读取空回车,但是scanf不能。
strcat函数 #include<string.h>
函数原型为char *strcat( char *to, const char *from );
strcat的作用是连接两个字符数组中的字符串,把字符串from接 到字符串to的后面,函数调用后得到字符数组to的地址。
eg.
char str1[30]={″People′s Republic of ″};
char str2[]={″China″};
print(″%s″,strcat(str1,str2));
输出: People′s Republic of China
strcpy函数 #include<string.h>
函数原型为char *strcpy( char *to, const char *from );
strcpy作用是将字符串from复制到字符数组to中去。
eg.
char str1[10],str2[]={″China″};
strcpy(str1,str2);
PS:str1必须定义得足够大,以便容纳被复制的字符串。
strcmp函数 #include<string.h>
函数原型为int strcmp( const char *str1, const char *str2 );
strcmp的作用是比较字符串1和字符串2;若str1<str2,返回 负数;若str1=str2则返回0;若str1>str2,返回正数。
eg.
strcmp(str1,str2);
strcmp(″China″,″Korea″);
strcmp(str1,″Beijing″);
strlen函数 #include<string.h>
函数原型为 size_t strlen( char *str );
strlen是测试字符串长度的函数。函数的值为字符串中的实际长 度(不包括′\0′在内)。
eg.
char str[10]={″China″};
printf(″%d″,strlen(str));
strlwr函数 #include<string.h>
char *strlwr(char *str);
strlwr函数的作用是将字符串中大写字母换成小写字母,返回字符串地址。
strupr函数 #include<string.h>
char *strupr(char *str);
strupr函数的作用是将字符串中小写字母换成大写字母。
strlwr()和strupr()不是标准库函数,只能在 windows下(VC、MinGW等)使用,Linux GCC中需要自己定义。