cank
在写一道题时,首先想到的是怎么取存储输入输出的数据,使我们操作更加方便,处理的更快,所以我们来认识数据结构,认识数据存储:
单值:变量
连续:1维数组(行)、2维数组(面)、3维数组(体)
离散:链表(插入删除多的1维数组)
行长度不同的二维表:vector<string>
或vector<vector>
…
不要拘泥于现有认知的数据结构,可以通过STL的组合灵活构造。
- 1 栈stack
- 2 队列queue
- 3 链表
- 4 二叉树
- 5 哈夫曼树
- 6 二叉排序树
- 7 前缀树
- 8 搜索(DFS/BFS/A*)
- 8.1 暴力枚举
-
- 9 图论算法(并查集、最小生成树、最短路径、拓扑)
1 栈stack
只能在栈顶一端进行入栈和弹栈操作,它满足先进后出的特性
只能在栈顶一端进行入栈和弹栈操作,它满足先进后出的特性
只能在栈顶一端进行入栈和弹栈操作,它满足先进后出的特性
STL栈stack:
#include <stack>
中可以用stack<int> st
来定义一个全局栈来储存整数的空的stack。当然stack可以存任何类型的数据,比如stack<string> st
等等。
数组模拟栈:
只能使用C语言机试的同学直接用数组模拟栈即可。
int stk[N], top=-1;
stk[++top] = x;
c = stk[top--];
stk[top];
if (top == -1)
常见应用方式:
1、计算表达式的值
2、带优先级的括号匹配问题
2 队列queue
只能在队尾入队和队头出队操作,它满足先进先出的特性
只能在队尾入队和队头出队操作,它满足先进先出的特性
只能在队尾入队和队头出队操作,它满足先进先出的特性
STL队列queue:
#include <queue>
中可以用queue<int> q
来定义一个全局队列来储存整数的空的queue。当然queue可以存任何类型的数据,比如queue<string> q
等等。
q.push(something);
q.pop();
q.top();
q.empty();
STL优先队列priority_queue:自动排序(可重复)
#include <priority_queue>
priority_queue <int,vector<int>,greater<int> > q;
priority_queue <int,vector<int>,less<int> >q;
priority_queue<int> a;
struct tmp1 {
int x;
tmp1(int a) {x = a;}
bool operator<(const tmp1& a) const {
return x < a.x;
}
};
priority_queue<tmp1> d;
3 链表
对于使用OJ测评的院校的同学来说,这类问题可以用数组来实现,没有必要用链表去实现,写起来慢不说,还容易出错,所以我们一般都直接用数组来实现,反正最后OJ能AC就行。
但是对于非OJ测评的院校来说,链表类问题可以说是必考的题型。
一般来说有以下三种常见考点:
1、约瑟夫环
解析:n个节点的循环链表
建立之后,按照题意(间隔m个节点)删除节点,求删除顺序。三种解法:数组
、循环链表
、递归
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,e) for(int i=s;i<e;i++)
#define per(i,s,e) for(int i=s;i>e;i--)
struct node{
int num;
node* next=nullptr;
};
struct node* create(int n) {
struct node *head, *now, *pre;
rep(i,1,n+1) {
now = new node;
if (i == 1) {
head = now;
pre = now;
}
now->num = i;
now->next = head;
pre->next = now;
pre = now;
}
return head;
};
void print(node*root){
int flag=1;
node *current=root,*pre;
while(current->next!=current){
if(flag){
flag=0;
pre=current->next;
current=pre->next;
pre->next=current->next;
}
else{
pre=current->next->next;
current=pre->next;
pre->next=current->next;
}
cout<<current->num;
}
}
int main(){
int n;
cin>>n;
node *root=create(n);
print(root);
return 0;
}
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,e) for(int i=s;i<e;i++)
#define per(i,s,e) for(int i=s;i>e;i--)
int a[101]={0};
int main(){
int n,m;
int cnt=0,i=0,k=0;
cin>>n>>m;
while(cnt!=n){
i++;
if(i>n) i=1;
if(a[i]==0){
k++;
if(k==m){
a[i]=1;
cnt++;
cout<<i<<" ";
k=0;
}
}
}
return 0;
}
2、有序链表合并
解析:这个和两个有序数组合并为一个有序数组原理一样
。
3、链表排序
解析:使用冒泡排序
进行链表排序,因为冒泡排序是相邻两个元素进行比较交换
,适合链表。
4 二叉树
- 树的本质就是多个子节点的链表,根节点指针=表头指针,子节点用
vector<node*> childern
保存。 - 二叉树就是限定每个节点的子节点不超过2个,子节点用
node* left; noed* right
保,左子树和右子树是有顺序的,次序不能任意颠倒。
二叉树的建立:
二叉树的遍历:(递归实现)
前序遍历(根左右)
:从二叉树的根结点出发,当第一次到达结点时就输出结点数据,按照先向左再向右的方向访问。对于上图,遍历顺序如下:ABDHIEJCFG中序遍历(左根右)
:从二叉树的根结点出发,当第二次到达结点时就输出结点数据,按照先向左再向右的方向访问。对于上图,遍历顺序如下:HDIBJEAFCG后序遍历(左右根)
:从二叉树的根结点出发,当第三次到达结点时就输出结点数据,按照先向左再向右的方向访问。对于上图,遍历顺序如下:HIDJEBFGCA层序遍历
:按照树的层次自上而下的遍历二叉树。对于上图,遍历顺序如下:ABCDEFGHIJ
判断二叉树对称:先建树,先序遍历的“根左右” = 先序遍历的“根右左”
,则二叉树对称。
遍历常考考点(建树!!!)
对于二叉树的遍历有一类典型题型。
通过中序遍历和先序遍历 可以 确定一个树
通过中序遍历和后续遍历 可以 确定一个树
通过先序遍历和后序遍历 不可以 确定一个树。
1)前序序列+中序序列,构建二叉树。
- 前序遍历是ABDECFG
- 中序遍历是DBEACGF
这样我们就构造出第一个点。以preOrder[1…3]作为新的前序,inOrder[0…2]作为新的中序,就可以构造出A的左子树(右也同理)。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,e) for(int i=s;i<e;i++)
#define per(i,s,e) for(int i=s;i>e;i--)
typedef struct node{
node *lchild=NULL, *rchild=NULL;
char data;
}node,*Tree;
void createTree(Tree&T,string pre,string in){
T=new node;
T->lchild=NULL;T->rchild=NULL;
T->data=pre[0];
if(pre.size()==1) return;
int mid=in.find(pre[0]);
if(mid!=0)
createTree(T->lchild,pre.substr(1,mid+1),in.substr(0,mid));
if(mid!=in.size()-1)
createTree(T->rchild,pre.substr(mid+1),in.substr(mid+1));
}
void postOrder(node* p) {
if(p!=NULL){ postOrder(p->lchild); postOrder(p->rchild); cout<<p->data; }
}
main() {
string pre,in; cin>>pre>>in;
node * root = new node;
createTree(root,pre,in);
postOrder(root);
}
2)后序序列+中序序列,构建二叉树。
后序遍历中最后访问的为根结点,因此可以按照上述同样的方法,找到根结点后分成两棵子树,进而继续找到子树的根结点,一步步确定二叉树的形态。
代码还有错误,带改
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,e) for(int i=s;i<e;i++)
#define per(i,s,e) for(int i=s;i>e;i--)
typedef struct node{
node *lchild=NULL, *rchild=NULL;
char data;
}node,*Tree;
void in_post_createTree(Tree&T,string in,string post){
T=new node;
T->lchild=NULL;T->rchild=NULL;
T->data=post[post.size()-1];
if(post.size()==1) return;
int mid=in.find(T->data);
if(mid!=0)
in_post_createTree(T->lchild,in.substr(0,mid),post.substr(0,mid));
if(mid!=in.size()-1)
in_post_createTree(T->rchild,in.substr(mid+1),post.substr(mid+1,post.size()-1-mid));
}
void preOrder(node* p) {
if(p!=NULL){ cout<<p->data; preOrder(p->lchild); preOrder(p->rchild); }
}
main() {
string in,post; cin>>in>>post;
node * root = new node;
in_post_createTree(root,in,post);
preOrder(root);
}
例题,二叉树的建立和遍历
题目描述:
建立以二叉链作为存储结构的二叉树,实现 1)先序遍历; 2)中序遍历; 3)后序遍历; 4)层序遍历; 5)编程计算二叉树的叶子结点个数。
输入描述:
按照先序遍历序列输入二叉树中数据元素的值,没有的输入0表示。
输出描述:
第一行输出先序遍历序列 第二行输出中序遍历序列 第三行输出后序遍历序列 第四行输出叶子结点的个数。
输入样例:
A B C 0 0 0 D E 0 F 0 0 G 0 0
输出样例:
A B C D E F G
C B A E F D G
C B F E G D A
3
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,e) for(int i=s;i<e;i++)
#define per(i,s,e) for(int i=s;i>e;i--)
typedef struct node{
char data;
struct node *lchild,*rchild;
}*BitTree;
string line;
int i;
char c;
void CreatBitTree(BitTree &T) {
if(i==line.size()) return;
c=line[i++];
if (c == '0') T = NULL;
else {
T = new node;
T->data = c;
T->lchild=NULL;
T->rchild=NULL;
CreatBitTree(T->lchild);
CreatBitTree(T->rchild);
}
}
void PreOrderTraverse(BitTree T) {
if (T != NULL) {
cout << T->data << ' ';
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
void InOrderTraverse(BitTree T) {
if (T != NULL) {
InOrderTraverse(T->lchild);
cout << T->data << ' ';
InOrderTraverse(T->rchild);
}
}
void PostOrderTraverse(BitTree T) {
if (T != NULL) {
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
cout << T->data << ' ';
}
}
int Leaf(BitTree T) {
if (T == NULL) return 0;
if (T->lchild == NULL && T->rchild == NULL) return 1;
return Leaf(T->lchild) + Leaf(T->rchild);
}
int Deepth(BitTree T) {
if (T == NULL) return 0;
int x = Deepth(T->lchild);
int y = Deepth(T->rchild);
return max(x,y) + 1;
}
int main(){
while(cin>>line){
i=0;
CreatBitTree(T);
InOrderTraverse(T); cout << endl;
InOrderTraverse(T); cout << endl;
PostOrderTraverse(T); cout << endl;
cout << Leaf(T) << endl;
}
return 0;
}
5 哈夫曼树
6 二叉排序树
7 前缀树
8 搜索(DFS/BFS/A*)
8.1 暴力枚举
枚举算法是在分析问题时,逐个列举出所有可能情况,然后根据条件判断此答案是否合适,合适就保留,不合适就丢弃,最后得出一个结论。主要利用计算机运算速度快、精确度高的特点,对要解决问题的所有可能情况,一个不漏地进行检验,从中找出符合要求的答案,因此枚举法是通过牺牲时间来换区答案的全面性。
举例说明
有一个整数ABCD,一定是四位数,A不能为0,其中ABCD*4=DCBA。 其中A、B、C、D都是一个数字,求ABCD是多少?
如何解决这个问题呢?
我们可以直接枚举ABCD四个数的值
8.2 DFS深度优先搜索
9 图论算法(并查集、最小生成树、最短路径、拓扑)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)