结构体-Struct

1.1 创建结构体

(1)声明类型

struct  tag  {  member-list;  }  variable-list;                                  声明结构体类型

其中,struct tag 即为创建的结构体类型;tag为结构体标签。

member-list表示结构体中的所有成员变量variable-list表示定义出的全局结构体变量,可写可不写。

typedef struct tag { member-list; } typename;                    声明结构体类型并重命名

添加typedef前缀之后,typename即为创建的结构体类型

(2)定义变量

struct  tag  s1 = { ...... };

typename  s1= { ...... };                                                  两种方式都可以创建结构体变量

s1为定义出的局部结构体变量

同理,若s1为嵌套结构体,则定义结构体变量的语法为:typename s1 = { ...{ .... }... };  

1.2 结构体成员访问

(1) 直接访问成员

typename  s1 ;

s1 . member ;                                            

s1结构体变量member为结构体类型声明里的成员变量名。

同理,若s1为嵌套结构体,则访问最内部成员变量的语法为:s1.s2.member ;

(2) 通过指针访问成员

typename  s1;          typename * p = &s1;

p -> member ;

p为存储结构体首地址指针变量

注:对于结构体函数传参而言,运用指针进行地址传参显然更优,因为只用开辟4Byte的内存用于储存首地址,而直接传参需要开辟与原结构体等大的内存。(函数传参时,参数需要压栈,结构体过大时压栈的系统开销较大,导致系统性能的下降)此外,在数据结构的接口函数中,必须用访问地址的方式对实参进行改变。


 2.1 动态内存分配

当我们使用结构体数组等占用内存大但不知道分配多大空间的数据类型时,需要使用动态内存分配的相关函数。需要调用的头文件是:<stdlib.h>

(1) malloc函数

int *p = (int*) malloc (10 * sizeof (int) );                      向内存申请10个整型的连续空间

malloc函数的返回值是一个指针(若内存分配失败则返回空指针)。此时p存放的是分配的动态内存空间的地址。

(2) free函数

free ( p );                                                                        回收空间

当动态申请的空间不再使用时,应该还给操作系统。free(p)后,p指向的地址不变。因此应该在添加:p = NULL;防止野指针的出现。

此外还有realloc(重新分配内存)、calloc(和malloc相似,但会使分配的内存数据置为0)等内存分配函数。

 2.2 顺序表

(1)静态顺序表(数组)

typedef struct SeqList

{   int  a[n];  int  size; } SL;                        a[n]存储数组,size表示数组中存储数据个数

而用于该数据结构输入、输出、修改的函数被称为接口函数,如:

void SeqListPushBack(SL * ps ,SLDataType x);

接口函数的形参一般都是指针变量,方便通过访问地址的方式修改实参。

静态顺序表的特点是数据会被存满,因此不方便定义存储的空间大小。定义过大会造成空间的浪费。

(2)动态顺序表

typedef struct SeqList

{   int  *p;  int  size; int  capacity  } SL

                                       将定义的数组改成指针,新增capacity表示数组能存放的空间容量

例如,当顺序表已经存储五个数据{0,1,2,3,4}时,size = 5;而此时还可以存放2个空间,则capacity=7,若size = capacity则进行增容。p[n]表示存储的第(n-1)个数据。

显然,在动态顺序表中,我们分配内存的地址在SL.p中,结构体只是帮助记录数组信息。

动态顺序表的接口实现:

接口函数包括初始化、尾插数据、尾删数据等。这里以尾部添加数据为例。

函数声明:

void SeqListPushBack ( SL *slp, SLDataType x){......}

其中slp是指向结构体的指针。x为要添加的数据。SLDataType为顺序表中存放的数据类型。

1.当 (slp->capacity) > (slp->size) 时,只需简单插入数据即可。

slp -> p[ slp ->size ] = x;

slp -> size ++;                                                     p[slp ->size]表示当前要存放的数组位置

2.当(slp->capacity) = (slp->size) 时说明数据已存满或该顺序表刚刚初始化,则进行扩容。

int newcapacity = ( slp -> capacity == 0 ?4 :slp->capacity * 2 ); 

                                                                                                                    使用三目运算符

表示若此时顺序表容量为0则容量改为4,若为4则容量变为两倍。

然后用realloc函数修改开辟的空间:

slp = (SLDataType * ) realloc ( slp ->p,newcapacity * sizeof(SLDataType));

slp -> p = tmp;

slp -> capacity = newcapacity;                                             重新分配slp指向的内存空间

由于接口函数大多使用了malloc,realloc等内存分配方式,通常都需要Destroy接口函数来free所有内存空间,销毁顺序表,并将slp->p置空,防止p变成野指针。顺序表使用结束后记得销毁

2.3 单链表

链表和顺序表统称为线性表。

顺序表需要频繁扩容,且会造成空间的浪费,且从中间插入或删除数据需要挪动之后所有数据,效率不高。针对顺序表的缺陷设计出链表。

struct SListNode{ SLDateType data; struct SListNode* next ; } ;

单链表由多个结点(node)构成,每个结点是一个结构体。一般每个单链表的头结点数据域存放的是关于该链表的长度等相关数据。每个链表有一个头指针指向头结点。

单链表的接口函数以打印单链表为例:

void SListPrint (SLTNode * phead)

{    SLTNode * cur = phead;

     while (cur != NULL)

        {   printf("%d->",cur -> data);

            cur = cur -> next;  }

}

2.4 栈

栈的数据存储特点是先进后出。分为顺序栈链栈共享栈

(1)动态顺序栈

struct Stack { STDataType * p ;  int top ; int capacity; } ; 

本质上是将顺序表的size改为top,不再关注已存储的数量。用p[top]取出栈顶数据。

(2)共享栈

两个栈的栈底相互对立,栈顶相互靠拢,直至栈顶相遇即为栈满。

(3)链栈

typedef struct StackNode

{ ElemType data; struct StackNode *next; }StackNode, *LinkStackPrt;
                                                                                                           链表的结点结构体
typedef struct LinkStack{ LinkStackPrt top ;  int count ; } LinkStack ;

                                                                                                           链栈的结构体

与顺序栈不同,链栈的栈顶top是指针

2.5 队列

队列特点是先进先出。入栈时rear指针后移,出栈时front指针后移。

链队列:

typedef struct QueueNode{ QueueNode* next ; QDataType data ; }QNode ;

typedef struct Queue{ QNode* head ; QNode* tail ; };

顺序队列:

#define MAXSIZE 50   
typedef struct{ ElemType data[MAXSIZE];  int front,rear; }SqQueue;

循环队列:

利用front或rear与MAXSIZE的求模运算来保证队列填入数据的循环。

为了区分队空和队满,空出一个单元不存放数据

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值