1.结构型
结构型可以理解为用户用以有的数据类型(int,char。。)为原料制作新的结构类型。
typedef struct
{
int a
char a
}Typea;
上面语句构造了一个新的数据类型,即Typea类型。
2.指针型
变量里所装的是数据元素的内容,而指针型变量里装的是变量的地址,通过这个地址可以找到这个变量在内存中的位置,就像一个指示方向的指针,因此叫做指针型。
int *a;//定义了一个int型指针变量
char *b;//定义了一个char型指针变量
Typea *d;//定义了一个Typea型指针变量
上面的语句中分别定义了指向整型变量的指针a,指向字符变量类型的指针b,指向Typea类型的指针d。指针型变量的定义只是在变量名前面加个‘*’
如果a是个指针变量,它指向一个变量b,则a中存放变量b的地址。*a就是取变量b的内容,x=*a等价于x=b。&b就是取变量b的地址,语句a=&b;就是将变量b的地址存于a中,即指针a指向b。
3.结点的构造
(1)链表结点的定义
链表结点有两个域,一个是数据域存放数据,一个指针域,用来存放下一个结点的位置。
typedet struct Node
{
int data;
struct Node *next;//指向Node型变量的指针
}Node;
上面结构型的名字是Node,因为组成此结构体的成员中有一个指向和自己类型相同的变量的指针,内部要用自己来定义这个指针,所以写成struct Node *next;。这里指出,凡是结构型(假设为a)的内部有这样的指针型(假设名为b),即b是用来存放和a类型相同的结构体变量地址的指针型,则在定义a的typedef struct 语句之后都要加上a这个结构型的名字。
(2)二叉树结点的定义
typedef struct BTNode
{
int data;
struct BTNode *lchild;//指向左孩子结点指针
struct BTNode *rchild;//指向右孩子结点指针
}BTNode;
对于结构型,只需要掌握以上两种结点的定义方法,其他结点都是由这两种衍生而来。上面那二叉树结点的定义有些参考书这样写:
typedef struct BTNode
{
int data;
struct BTNode *lchild;//指向左孩子结点指针
struct BTNode *rchild;//指向右孩子结点指针
}BTNode,*btnode;
其实就是在最后面多写了一个*btnode,其实当我们定义结点指针p的时候,BTNode *p等价于btnode p;对于定义结点指针,BTNode *p;这种写法很符合我们之前的 int *a,char *b这种定义。因此通常不采用这种写法。
通过上面我们知道了链表结点和二叉树结点的定义方法。结构型定义后,我们需要用他来制作新结点。
以二叉树结点为例子,有下面两种写法。
1. BTNode BT;
2. BTNode *BT;
BT=(BTNode *)malloc(sizeof(BTNode));
第一句中用一句代码就制作了一个结点,而第二句中需要两句,我们基本上使用的第二句。相比之下,第一句中BT就是某个结点的名字,一旦定义好,就不能脱离这个结点,而第二句中,BT是一个指针型变量,用来存储刚制作好的结点的指针,在以后可以离开这个结点而指向其他结点,所以第二句更灵活。
第二句执行过程:线定义一个结点的指针BT,然后用函数malloc()来申请一个结点的内存空间,最后让指针BT指向这片内存空间,这样就完成了。
第二句就是用系统已有 的函数malloc()申请新结点所需内存空间的方法。模式固定,容易记忆。
除此之外,还有一个动态申请数组空间的方法,相对于上面提到的一次只能申请一个结点,这种方法可以一次申请一组结点,语法如下:
int *p;
p=(int *)malloc(n*sizeof(int));
这样就申请了一个由指针p所指的(p指向数组中第一个地址),元素为int型的,长度为n的动态数组。去元素时和一般的数组一样,如取第三个,就p【3】。
对于1和2的BT取分量的操作也不同,对于1,需要使用‘.’来取分量,x=BT.data;对于2,x=BT->data;一般来说,用结构体变量直接取分量,用‘.’。用指向结构体变量的指针来取分量,用‘->’。