一.栈(stack)
1.概念
栈是一种线性的数据结构,采用先进后出的方式管理数据,一端的位置固定 (栈底) ,另外一端随着数据的进出随时改变 (栈顶)
2.提供的接口
创建,入栈(压栈),出栈(弹栈),判空,判满
push pop
3.实现
栈是一种逻辑概念,可以使用顺序结构来实现 (顺序栈) ,也可以使用链式结构来实现 (链式栈)
顺序栈记录栈顶下标,提供从尾部插入作为入栈,尾部删除作为出栈
链式栈可以使用单链表来实现,以头结点作为栈顶,从头部插入作为入栈,从头部删除作为出栈
4.使用
定义stack.h头文件
#ifndef _STACK_H_
#define _STACK_H_
#define STACK_SIZE 4
#define EEMPTY 32767
typedef int T;
typedef struct{
T *pdate;
int top;
}sqstack_t,*stacklist_t;
stacklist_t create_emptystack();//创建空栈
int is_empty(stacklist_t stack);//判空
int is_full(stacklist_t stack);//判满
void stack_push(stacklist_t stack,T dt);//入栈
T stack_pop(stacklist_t stack);//出栈
T stack_top(stacklist_t stack);//获取栈顶元素
void make_empty(stacklist_t stack);//置空栈
void destory_stack(stacklist_t *pstack);//销毁栈
#endif
创建空栈
stacklist_t create_emptystack()
{
stacklist_t stack = (stacklist_t)malloc(sizeof(sqstack_t));
if(stack)
{
stack->pdate = (T*)malloc(sizeof(T)*STACK_SIZE);
if(stack->pdate == NULL)
{
free(stack);
stack = NULL;
return NULL;
}
stack->top = 0;
}
return stack;
}
判空
int is_empty(stacklist_t stack)
{
return stack->top == 0;
}
判满
int is_full(stacklist_t stack)
{
return stack->top == STACK_SIZE;
}
入栈
void stack_push(stacklist_t stack,T dt)
{
if(is_full(stack))
{
printf("stack is full!\n");
return;
}
stack->pdate[stack->top++] = dt;
}
出栈
T stack_pop(stacklist_t stack)
{
if(is_empty(stack) == 1)
{
printf("stack if NULL!\n");
return -EEMPTY;
}
return stack->pdate[--stack->top];
}
获取栈顶元素
T stack_top(stacklist_t stack)
{
return stack->pdate[stack->top-1];
}
置空栈
void make_empty(stacklist_t stack)
{
stack->top = 0;
}
销毁栈
void destory_stack(stacklist_t *pstack)
{
free((*pstack)->pdate);
(*pstack)->pdate = NULL;
free(*pstack);
*pstack = NULL;
}
二.队列(queue)
1.概念
队列也是一种线性的数据结构,采用先进先出的方式来管理数据,存入(队尾)和取出(队首)在两个不同的端点进行,需要记录两个端点各自的位置
2.提供的接口
创建,入队,出队,判空,判满
3.实现
队列是一种逻辑概念,可以使用顺序结构来实现 (顺序队列) ,也可以使用链式结构来实现 (链式队列)
顺序队列需要记录头和尾,一般的顺序队列的队列空间只能使用一次,为了重复使用队列空间,顺序队列会被设计为环形队列(循环队列)
环形队列理论上空和满都是队首和队尾重合,为了方便区分,强制定义当队尾在队首前一个位置时队列为满
链式栈可以用带尾结点的单链表来实现,以头结点作为队首,以尾结点作为队尾,入队相当于尾部插入,出队相当于头部删除
4.使用
定义queue.h头文件
#ifndef _QUEUE_H_
#define _QUEUE_H_
#define N 100
#define EEMPTY 32767
typedef int T;
typedef struct{
T date[N];
int head,tail;
}sequeue_t,*queue_t;
queue_t create_emptyqueue();//创建空队列
int is_empty(queue_t sq);//判空
int is_full(queue_t sq);//判满
void queue_push(queue_t sq,T dt);//入队
T queue_pop(queue_t sq);//出队
#endif
创建空队列
queue_t create_emptyqueue()
{
queue_t sq = (queue_t)malloc(sizeof(sequeue_t));
if(sq)
{
sq->head = 0;
sq->tail = 0;
}
return sq;
}
判空
int is_empty(queue_t sq)
{
return sq->head == sq->tail;
}
判满
int is_full(queue_t sq)
{
return sq->head == (sq->tail+1)%N;
}
入队
void queue_push(queue_t sq,T dt)
{
if(is_full(sq))
{
printf("queue is full!\n");
return;
}
sq->date[sq->tail] = dt;
sq->tail = (sq->tail+1)%N;
}
出队
T queue_pop(queue_t sq)
{
if(is_empty(sq))
{
printf("queue is NULL!\n");
return -EEMPTY;
}
T i=sq->date[sq->head];
sq->head = (sq->head+1)%N;
return i;
}
三.树
1.概念
将线性结构中允许数据有多个跟随数据就形成树,计算机中可以用顺序结构来存储,也可以使用链式结构来存储
树的源头叫做根,根可以代表整棵树,处理树时先将树转换为二叉树
树中两个有直接联系的数据具有父子关系,靠近根的数据是父亲,另一个数据是孩子
二叉树指的是每一个数据最多拥有两个跟随数据,这样的树就叫二叉树
二叉树的跟随数据用左右区分,任何一颗二叉树可以分为 根 左子树 右子树
左子树是以左孩子为根的二叉树,右子树以右孩子为根的二叉树
对任何一个二叉树的操作可以拆分为对以上三部分进行操作,通常使用递归来处理二叉树
如果一颗二叉树所有的叶子处于树的最后一层,并且其他节点都有两个孩子,这样的数叫满二叉树
如果一颗二叉树的叶子节点只存在于最后一层的左边和倒数第二层的右边,这样的树叫完全二叉树
2.二叉树的存储
(1)顺序结构
先将二叉树转换成完全二叉树,再将数据存入顺序结构的空间,没有数据的位置空出来
(2)链式存储
节点结构:
struct node{
T data;//数据域
struct node *left;//左孩子
struct node *right;//右孩子
};
3.二叉树的补充概念
(1)深度
二叉树的深度指的是二叉树的层数
(2)二叉树的平衡性
如果二叉树的左子树和右子树的深度差小于等于1,那么该二叉树就是一颗平衡二叉树
二叉树的平衡度越好,访问效率越高
4.二叉树的遍历
二叉树有三种遍历方法:前序遍历 中序遍历 后序遍历
前序遍历:根 左子树 右子树
中序遍历:左子树 根 右子树
后序遍历:左子树 右子树 根