队列的实现
队列是很常见的数据结构,它的存取方式是“先进先出”。生活中的排队,就是队列的原型
队列有两种实现方式:链队列和循环队列。
-
链队列实际上和单向链表一样,用指针把各个结点连接起来。
-
循环队列使用一组连续的存储单元依次存放队列元素,用指针 head指示队列头元素,rear指向尾元素。当 head 和 rear走到底时,下一步回到开始的位置,从而在这组连续空间内循环。设计成循环能解决溢出问题。
手写循环队列
#define MAXQSIZE 100003 //自定义队列大小
struct myqueue{
int data[MAXQSIZE]; //分配静态空间
int head; //队头,指向队头的元素
int rear; //队尾,指向下一个可以放元素的空位置
bool init(){ //初始化
head = rear = 0;
return true;
}
int size(){ //返回队列长度
return (rear - head + MAXQSIZE) % MAXQSIZE;
}
bool empty(){ //判断队列是否为空
if(size()==0) return true;
else return false;
}
bool push(int e){ //队尾插入新元素。新的rear指向下一个空的位置
if((rear + 1) % MAXQSIZE == head ) return false; //队列满
data[rear] = e;
rear = (rear + 1) % MAXQSIZE;
return true;
}
bool pop(int &e){ //删除队头元素,并返回它
if(head == rear) return false; //队列空
e = data[head];
head = (head + 1) % MAXQSIZE;
return true;
}
int front(){ //返回队首,但是不删除
return data[head];
}
};>
STL queue
queue<Type> q; //定义队列,Type为数据类型,如int,float,char等 q. push(item); //把item放进队列 q.front(); //返回队首元素,但不会删除 q.pop(); //删除队首元素 q.back(); //返回队尾元素 q.size(); //返回元素个数 q.empty(); //检查队列是否为空
栈的用法以及实现
栈只有唯一的一个出入口,从这个口进入,也从这个口出来,而队列有一个入口和一个出口,这是栈和队列最大的区别。栈的代码比队列的代码更简单,栈像一个只有一个门的房子,而队列这个房子有前门和后门。
那么栈该如何实现呢?
在这里看一下栈的基本用法:
push(): 向栈内压入一个成员;
pop(): 从栈顶弹出一个成员;
empty(): 如果栈为空返回true,否则返回false;
top(): 返回栈顶,但不删除成员;
size(): 返回栈内元素的大小;
编程中常用的递归,在系统中是用栈来保存现场的。栈需要用空间存储,如果栈的深度太大,或者存进栈的数组太大,那么总数会超过系统为栈分配的空间,就会爆栈导致栈溢出。做题需要使用栈时,直接用STL stack或者自己写栈。
下面为自己手写的栈
const int N = 100100; //定义栈的大小
struct mystack{
int a[N]; //存放栈元素
int t = -1; //栈顶位置
void push(int x){ a[++t] = x; } //送入栈
int top() { return a[t]; } //返回栈顶元素
void pop() { t--; } //弹出栈顶
int empty() { return t==0?1:0;} //返回1表示空
};
下面是STL stack
#include<iostream>
#include<stack>
using namespace std;
int main()
{
stack <int>stk;
//入栈
for(int i=0;i<50;i++){
stk.push(i);
}
cout<<"栈的大小:"<<stk.size()<<endl;
while(!stk.empty())
{
cout<<stk.top()<<endl;
stk.pop();
}
cout<<"栈的大小:"<<stk.size()<<endl;
return 0;
}
二叉树的初步和实现
二叉树是每个结点最多有两个子树的树结构,即结点的度最大为2。通常子树被称作”左子树”和”右子树”。二叉树是一个连通的无环图。
二叉树是递归定义的,其结点有左右子树之分,逻辑上二叉树有五种基本形态:(1)、空二叉树;(2)、只有一个根结点的二叉树;(3)、只有左子树;(4)、只有右子树;(5)、完全二叉树。
二叉树类型:
(1)、满二叉树:深度(层数)为k,且有2^k-1个结点的二叉树。这种树的特点是每一层上的结点数都是最大结点数。即除了叶结点外每一个结点都有左右子树且叶节点都处在最低层。
(2)、完全二叉树:除最后一层外,其余层都是满的,并且最后一层或者是满的,或者是在右边缺少连续若干节点,即叶子结点都是从左到右依次排布。具有n个节点的完全二叉树的深度为floor(log(2n))+1。深度为k的完全二叉树,至少有2^(k-1)个结点,至多有(2^k)-1个结点。
完全二叉树编写序号一般从1开始, Lchild/2=parent,孩子节点除以二等于父节点
(3)、平衡二叉树:又被称为AVL树,它是一颗二叉排序树,且具有以下性质:它是一颗空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树。
遍历二叉树:
按一定的规则和顺序走遍二叉树的所有结点,使每一个结点都被访问一次,而且只被访问一次。对一颗二叉树的遍历有四种情况:先序遍历、中序遍历、后序遍历、按层遍历。
(1)、先序遍历:先访问根结点,再先序遍历左子树,最后再先序遍历右子树,即先访问根结点-------左子树------右子树。
void preorder (node *root){ cout << root ->value; //输出 preorder (root -> lson); //递归左子树 preorder (root -> rson); //递归右子树 }
(2)、中序遍历:先中序遍历左子树,然后再访问根结点,最后再中序遍历右子树,即先访问左子树------根结点------右子树。
void inorder (node *root){ inorder (root -> lson); //递归左子树 cout << root ->value; //输出 inorder (root -> rson); //递归右子树 }
(3)、后序遍历:先后序遍历左子树,然后再后序遍历右子树,最后再访问根结点,即先访问左子树------右子树------根结点。
void postorder (node *root){ postorder (root -> lson); //递归左子树 postorder (root -> rson); //递归右子树 cout << root ->value; //输出 }
如果知道「中序遍历+先序遍历」的结果,或者「中序遍历+后序遍历」的结果,也都能确定一棵树。但是,如果不知道中序遍历,只有「先序遍历+后序遍历」的结果,则不能确定一棵二叉树。
对于二叉树的一个结点,我们通常要存储结点的值、左右子结点。在算法竞赛中,为了编码简单,加快速度,一般用静态数组来实现二叉树。比如定义一个大小为 NN 的结构体数组,用它来存一棵二叉树。代码如下:
struct Node{ //静态二叉树 char value; int lson, rson; //左右孩子,编码时把lson简写为ls或者l }tree[N]; //编码时把tree简写为t
再次特别说明,二叉树并不明白,需要进一步详解
typedef struct treeNode{ char data; struct treeNode *Lchild; struct treeNode *Rchild; }TREE,*LPTREE; //别名中lp一般表示是指针别名 LPTREE createNode(char data) { LPTREE newNode=(LPTREE)malloc(sizeof(TREE)); newNode->data=data; newNode->Lchild=NULL; newNode->Rchild=NULL; return newNode; } //没有规律的树 void insertNode(LPTREE parentNode,LPTREE Lchild,LPTREE R child) { parentNode->Lchild=Lchild; parentNode->Rchild=Rchild; } //打印当前节点中的元素 void printcurnodedata(LPTREE curData) { printf("%c\t",curData->data); } //递归法 //先序 void preOrder(LPTREE root) { if(root!=NULL) { printfcurnodedata(root); preOrder(root->Lchild); preOrder(root->Rchild); } } int main() { //死板的创建过程,无实际作用 LPTREE A=createNode('A'); LPTREE B=createNode('B'); LPTREE C=createNode('C'); LPTREE D=createNode('D'); LPTREE E=createNode('E'); LPTREE F=createNode('F'); insertNode(A,B,C); insertNode(B,D,NULL); insertNode(D,NULL,G); insertNode(C,E,F); return 0; }
![image-20220121102754766](C:\Users\86150\AppData\Roaming\Typora\typora-user-images\image-20220121102754766.png)