结构体基础知识总结以及在高级数据结构中的写法

在写了几种数据结构之后觉得结构体非常重要,但自己掌握得并不好,需要一点小总结。

以下基础知识大多来自网站菜鸟教程:
http://www.runoob.com/cprogramming/c-structures.html

格式:

struct tag {                      ----------结构体名字
    member-list                ----------成员列表
    member-list 
    member-list  
    ...
} variable-list ;            ----------变量列表

例如:

1.
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;

几种形式:
原则:结构体名、成员名、变量名,三者至少出现其二

没有结构体名、声明了一个变量s1
2.
struct 
{
    int a;
    char b;
    double c;
} s1;
 
3.
struct SIMPLE
{
    int a;
    char b;
    double c;
};
有结构体的名字了就可以用它来声明变量了   
这种情况要在前面带上struct
struct SIMPLE t1, t2[20], *t3;
4.
typedef是用来给类型取一个新的名字的,使用之后新名字和原来的名字有一样的作用,声明出来的变量和原来的类型一致
注意这种形式非常常见
这种和上面那个差不多,但是有了一个typedef,上面没有结构体名的时候是没办法再去声明变量的,但现在可以了
typedef struct
{
    int a;
    char b;
    double c; 
} Simple2;
现在可以用Simple2作为类型声明新的结构体变量:Simple2 u1, u2[20], *u3;

注意,Simple2的位置如果没有typdef的时候只是一个变量,有了typdef了就可以用他来声明结构体变量了,相当于把Simple2 作为一个结构体的名字了。

这种与上面的同理,也更为常见
typedef struct s
{
    int a;
    char b;
    double c; 
} Simple2;

此结构体的声明包含了指向自己类型的指针
struct NODE
{
    char string[100];
    struct NODE *next_node;
};
如果两个结构体**互相包含**,则需要对其中一个结构体进行不完整声明,如下所示:

struct B;    //对结构体B进行不完整声明
 
//结构体A中包含指向结构体B的指针
struct A
{
    struct B *partner;
    //other members;
};

结构体指针
struct Books *struct_pointer;
指针变量中存储结构变量的地址:
struct_pointer = &Book1;
访问结构体变量
struct_pointer->title;


实例:注意是函数的参数列表是结构体指针时,调用函数的时候是对变量取地址(变量的地址也就是指针存的值)struct Books Book1;        /* 声明 Book1,类型为 Books */

printBook( &Book1 );

void printBook( struct Books *book )

--------------------------------------------------------------------------------------------------------------------分割线,以下是个人感想
结构体的基础知识看起来并不多,总结一下也比较清晰,但是写了几种数据结构之后,会发现也许并不是那么回事…
甚至在声明结构体的时候就出现了问题导致程序到后来各种类型不匹配根本运行不了。
以下从写过的几种数据结构经验角度写一点总结:
注意:下面的结构体并不绝对,只是个人选择问题,但可以放在一起总结。
(不知道为什么不用代码块写的星号*有时候显示不出来…可能因为我代码是复制贴过来的?有时候还莫名其妙的斜体,讲究看一下)

1.这是在写二项堆的时候的结构体

typedef struct _BNode *BinomialNode;
typedef struct _BNode                              //结点的结构体
{
	Type key;
	int degree;
    BinomialNode child;
    BinomialNode parent;
    BinomialNode sibling;
}Node;

typedef struct Heap *BinomialHeap;
typedef struct Heap                                   //每个二项堆的堆顶连成一个链表
{
	BinomialNode head;
}Binheap;

高级数据结构上,结构体一般都要声明一个结构体变量和一个结构体指针,还有一个特点是结构体的成员需要声明成该结构体类型的指针变量(比如结构体是一个node,成员一般都是一些child,parent等,他们本身就是node).
一种情况就是这样,先把指针变量给声明出来,typedef struct _BNode *BinomialNode; 之后再成员定义指针变量的时候就直接用这个指针变量定义BinomialNode child;(没有星号)

以下为对应的分配空间以及引用: BinomialNode x = (BinomialNode)malloc(sizeof(Node));

先讲一下我们的malloc函数, 专门用来分配空间的,对应头文件<stdlib.h>或者<malloc.h>.
函数原型extern void星malloc(unsigned int num_bytes);
void星 表示未确定类型的指针,void星 可以指向任何类型的数据,申请内存空间时还不知道用户是用这段空间来存储什么类型的数据 例如: char星a = NULL;//声明一个char类型的指针 a = (char)malloc(100sizeof(char));//使用malloc分配内存的首地址,然后赋值给a (这个形式就和上面那个BinomialNode很对应了,请对起来看。malloc前面其实是一种强制转化(因为本身是void未定类型),转化成(char*)类型,也就是a的类型,malloc后面是他的真正的参数,分配100个单位char大小的空间)

写数据结构的时候我们也发现,有时候一个节点要用到malloc,有时候又不用,大概是这么个意思:

扫描二维码关注公众号,回复: 4114367 查看本文章

没有用到malloc的指针是没有指向有效的内存地址的,是不能对这样的指针指向的地址进行赋值的。如果用了malloc,就可以对它指向的地址里面赋值或者其他操作了。也就是只需要一个指针做指向性的操作就不需要给他malloc,如果要进行值的操作就需要malloc.

对结构体的引用,还有参数列表也需要单独提出来。
写成上面那种形式看起来就很方便很好理解了,参数列表一般都是这种情况:
void DELETE(BinomialHeap H, BinomialNode x)
直接用指针引用堆顶元素的链表或者用指针引用结点,后续基本不怎么会用到取值取地址等操作。

2.这是在写红黑树的时候写的结构体(想起被红黑树支配三天的恐惧)

typedef struct rbtree     //定义红黑树的结构
{
	Color color;
	type key;
	struct rbtree *left;
	struct rbtree *right;
	struct rbtree *parent;

}node, *tree;

同样的惯例,声明一个结构体变量和一个结构体指针。
不同的是成员是用struct rbtree *left;来声明的,如果没有像上面一样,先用typedef struct _BNode *BinomialNode;是不能再结构体成员声明的时候用到这个指针的,于是就直接用了结构体的最原始的名字。声明指针就加星号了。
下面的malloc和参数:
p = (node星 )malloc(sizeof(node));
创造结点要用node星去强制转换。
node星 create(type key, node *left, node *right, node *parent) //创建结点
void left_rotate(tree &t, node *x)
调用结点需要每次都加上星号,调用树要用他的地址。

3.B树用到的结构体


typedef struct TreeNode *PtrBTNode;      //定义一个结点和一个指向结点的指针
typedef struct TreeNode BTNode;

typedef struct TreeNode {                        //结点的结构体,包含位置,判断是否为叶子结点,关键字,孩子结点的指针
	int Num;                                      //Num是当前结点的关键字的个数
	bool IsLeaf;
	PtrElementType Key;
	PtrBTNode *Child;    
};          


typedef struct Tree *PtrBT;     //定义指向树根的指针
typedef struct Tree {             
	PtrBTNode Root;           
};  

这个B树的声明和二项堆类似,也是先就把指针变量typedef了,然后就可以在结构体里面用了。
malloc和参数也类似
PtrBTNode NewNode = (PtrBTNode)malloc(sizeof(BTNode)); //新建一个结点,分配空间
void BTDelete(PtrBT T, PtrBTNode CurrentNode, ElementType Val)
值得注意的是,child用了PtrBTNode *Child; 是和二项堆不一样的地方。
其实二项堆的child指的是父节点的最左边的孩子,B树的child就是所有的child有很多个,我们是用一个数组来存放这些child的结点的。声明的时候用了一个二级指针,指针child里面存放的地址是另一个指向BTNode类型的指针。数组和指针的关系,*child就是数组的首地址,指针移动数组也能移动,就相当于有一个指向数组的指针了,跟前面的情况就相似了。
就像这样:
for (j = 0; j < MinDegree; j++) { //z的子女就等于FullNode的后一半的子女
z->Child[j] = FullNode->Child[MinDegree + j];
}

就写这么多吧

猜你喜欢

转载自blog.csdn.net/alike_meng/article/details/83245670