程序设计:算法和数据结构 笔记2——数据结构
概述
栈(Stack)
规则
后入先出(Last In First Out,LIFO)
操作
- push(X):在栈的顶部压入元素X
- pop(): 从栈的顶部取出元素
- isEmpty():检查栈是否为空
- isFull(): 检查栈是否已满
一般情况下,栈还具有 “引用栈顶元素”和”检查栈中是否含有指定数据“的操作
队列(Queue)
规则
先入先出(First In First Out)
操作
-
enqueue(x):在队列的末端添加元素x
-
dequeue(): 从队列开头取出元素
-
isEmpty(): 检查队列是否为空
-
isFull():检查队列是否已满
一般情况下,队列还具有 “引用队列第一个元素”和”检查队列中是否含有指定数据“的操作
应用
逆波兰表示法(栈的应用)
逆波兰表示法是一种将操作符写在操作数后面的方法,又叫后缀表示法**,相较于我们日常使用的中缀表示法,它的优势在于不需要括号
例:$(1+2)\times (5+4) $ ==>>$1\space 2 + 5\space 4 + \times $
- 将 1 2 压入栈中
- 遇到运算符,从栈中取出两个操作数,按运算符运算,例中为+,将运算结果压入栈中,栈中数据变成了 3
- 将 5 4 压入栈中,栈中数据变为了 3 5 4
- 遇到操作符+ 取出两个操作数5 4 运算结果为9,压入栈中,栈中变为3 9
- 遇到操作符$\times$ 取出3 9 运算结果为27
一个并不完善的简单过程
#include<stdio.h>
#include<stdlib.h>
//本程序仅支持0-9的数字运算
int top,stack[1000];
void push(int x){
stack[++top]=x;
}
int pop(){
return stack[top--];
}
int main(){
char s[1000];
int i,a,b;
i=0;
top=0;
scanf("%s",s);
while(s[i]!='\0'){
if(s[i]=='+'){
a=pop();
b=pop();
push(a+b);
}else if(s[i]=='-'){
a=pop();
b=pop();
push(a-b);
}else if(s[i]=='*'){
a=pop();
b=pop();
push(a*b);
}else if(s[i]=='/'){//整除结果
a=pop();
b=pop();
push(a/b);
}else
{
push(s[i]-48);
}
i++;
}
printf("%d",pop());
return 0;
}
运行结果:
队列
现有名称为namei且处理时间为timei的n个任务按照顺序排成一列,
CPU通过循环调度法逐一处理这些任务,每个任务最多处理q ms
(这个时间称为时间片)。如果q ms之后任务尚未处理完毕,那么该任务
将被移动至队伍最末尾,CPU随即开始处理下一个任务
举个例子,假设q是100,然后有如下任务队列。
A(150) -- B(80) -- C(200) -- D(200)
首先A被处理100 ms,然后带着剩余的50 ms移动至队尾
B(80) -- C(200) -- D(200) -- A(50)
随后B被处理80 ms,在总计第180 ms时完成处理,从队列中消失
C(200) -- D(200) -- A(50)
接下来C被处理100 ms,然后带着剩余的100 ms移动至队尾。
D(200) -- A(50) -- C(100)
之后同理,一直循环到处理完所有任务。
请编写一个程序,模拟循环调度法。
输入
输入形式如下
n q
name1 time1
name2 time2
...
namen timen
第一行输入表示任务数的整数n与时间片的整数q,用一个空格隔开
接下来n行输入各任务的信息。字符串namei与timei用一个空格隔开。
输出
按照任务完成的先后顺序输出各任务名以及结束时间,任务名与对应结束时间用空格隔开,
每一对任务名与结束时间占一行。
限制
1 ≤n ≤100 000
1 ≤q ≤1000
1 ≤timei ≤50 000
1 ≤字符串namei的长度 ≤10
1 ≤timei的和 ≤1 000 000
输入示例 输出示例
5 100 p2 180
p1 150 p5 400
p2 80 p1 450
p3 200 p3 350
p4 350 p4 800
p5 20
#include<stdio.h>
#include<stdlib.h>
/*
以数组实验队列
*/
#define MAX 100005
long tail ,head ; //头尾元素位置
typedef struct queue{
char name[10];
long time;
}q;
q Q[MAX];
int isEmpty(){
if(tail==head) return 1;
return 0;
}
int isFull(){
if (tail+1==head) return 1;
return 0;
}
void enqueue(q p){
if(!isFull()){
Q[tail]=p;
tail=(tail+1)%MAX;
}
}
q dequeue(){
q p;
if(!isEmpty()){
p=Q[head];
head=(head+1)%MAX;
}
return p;
}
int main(){
tail=head=0;
long elaps=0;
int i=0;
q u;
long n,qtime;
scanf("%ld %ld",&n,&qtime);
while(i<n){
scanf("%s %ld",u.name,&u.time);
enqueue(u);
i++;
}
while(!isEmpty()){
u=dequeue();
if (u.time-qtime<=0)
{
elaps+=u.time;
printf("%s %ld\n",u.name,elaps);
continue;
}
elaps+=qtime;
u.time-=qtime;
enqueue(u);
}
}
运行结果:
STL(C++标准库)
C++库以提供“模板”为主,是指不必预先制定类型的函数或类。
STL为用户提供了多种名为辅容器(Container)的类,用于管理数据集合。在创建动态数组、表、栈、队列等结构时,只需要定义对应的容器。然后就可以通过调用成员函数或方法使用。
stack
函数名 | 功能 | 复杂度 |
---|---|---|
size() | 返回栈的元素数 | O(1) |
top() | 返回栈顶元素 | O(1) |
pop() | 从栈中取出并删除元素 | O(1) |
push(x) | 向栈中添加元素x | O(1) |
empty() | 当栈为空时返回true | O(1) |
#include<iostream>
#include<stack>
using namespace std;
int main()
{
stack<int> S;
S.push(1);
S.push(2);
S.push(3);
cout<<"栈的大小:"<<S.size()<<endl;
cout<<"栈顶元素:"<<S.top()<<endl;
S.pop();
cout<<"栈的大小:"<<S.size()<<endl;
cout<<"栈顶元素:"<<S.top()<<endl;
}
运行结果:
通过栈模板实现逆波兰表示
#include<iostream>
#include<stack>
using namespace std;
int main()
{
int i=0,a,b;
string s;
stack<int> stk;
cin>>s;
while (s[i]!='\0')
{
switch(s[i]){
case '+':
a=stk.top();stk.pop();
b=stk.top();stk.pop();
stk.push(a+b);
break;
case '-':
a=stk.top();stk.pop();
b=stk.top();stk.pop();
stk.push(a-b);
break;
case '*':
a=stk.top();stk.pop();
b=stk.top();stk.pop();
stk.push(a*b);
break;
default:
stk.push(s[i]-48);
}
i++;
}
cout<<stk.top()<<endl;
return 0;
}
运行结果:
queue
函数名 | 功能 | 复杂度 |
---|---|---|
size() | 返回队列中的元素数目 | O(1) |
front() | 返回队头的元素 | O(1) |
pop() | 从队列中取出并删除元素 | O(1) |
push(x) | 在队列中添加元素x | O(1) |
empty() | 当队列为空时返回true | O(1) |
#include<iostream>
#include<queue>
#include<string>
using namespace std;
int main()
{
queue<string> que;
que.push("red");
que.push("yellow");
que.push("yellow");
que.push("blue");
cout<<que.front()<<"\tnow size:"<<que.size()<<endl;
que.pop();
cout<<que.front()<<"\tnow size:"<<que.size()<<endl;
que.pop();
cout<<que.front()<<"\tnow size:"<<que.size()<<endl;
que.pop();
cout<<que.front()<<"\tnow size:"<<que.size()<<endl;
que.pop();
return 0;
}
运行结果:
用标准库模板实现上面的队列
#include<iostream>
#include<queue>
#include<string>
using namespace std;
int main()
{
queue<pair<string,int>> que;
string name;
int n,q,t;
int elaps=0;
cin>>n>>q;
while(n--){
cin>>name>>t;
que.push(make_pair(name,t));
}
pair<string,int> u;
while(!que.empty())
{
u=que.front();
que.pop();
if(u.second-q<=0){
elaps+=u.second;
cout<<u.first<<' '<<elaps<<endl;
continue;
}
u.second-=q;
elaps+=q;
que.push(u);
}
return 0;
}
运行结果:
pair是保存对数值的结构体模板,声明时需要在<>中指令两个数据结构。make_pair用于生成一对数值,第一个元素通过first访问,第二个通过second访问
vector
可以在添加元素是增加长度的数组成为动态数组或可变长数组。相对地,必须事先指定长度的是静态数组
STL中的vector(向量)实现了动态数组
函数名 | 功能 | 复杂度 |
---|---|---|
size() | 返回向量的元素数目 | O(1) |
push_back(x) | 在向量的末尾添加x | O(1) |
pop_back() | 删除向量的最后一个元素 | O(1) |
begin() | 返回指向向量开头的迭代器 | O(1) |
end() | 返回指向向量结尾的迭代器 | O(1) |
insert(p,x) | 在向量中迭代器p指向的位置插入x | O(n) |
erase(p) | 删除向量中迭代器p指向的元素 | O(n) |
clear() | 删除向量中所有元素 | O(n) |
#include<iostream>
#include<vector>
#include<string>
using namespace std;
void output(vector<double> v){
for (int i = 0; i < v.size(); i++)
{
cout<<v[i]<<" ";
}
cout<<endl;
}
int main()
{
vector<double> vec;
vec.push_back(0.1);
vec.push_back(0.2);
vec.push_back(0.3);
vec[2]=0.4;
output(vec);
vec.insert(vec.begin()+2,0.8);
output(vec);
vec.erase(vec.begin()+1);
output(vec);
return 0;
}
输出结果:
list
list是一个双向列表
函数名 | 功能 | 复杂度 |
---|---|---|
size() | 返回向量的元素数目 | O(1) |
push_back(x) | 在向量的末尾添加x | O(1) |
push_front(x) | 在向量的开头添加x | O(1) |
pop_back() | 删除向量的最后一个元素 | O(1) |
pop_front() | 删除向量的开头元素 | O(1) |
begin() | 返回指向向量开头的迭代器 | O(1) |
end() | 返回指向向量结尾的迭代器 | O(1) |
insert(p,x) | 在向量中迭代器p指向的位置插入x | O(1) |
erase(p) | 删除向量中迭代器p指向的元素 | O(1) |
clear() | 删除向量中所有元素 | O(n) |
#include<iostream>
#include<list>
#include<string>
using namespace std;
int main()
{
list<char> li;
li.push_back('b'); //[b]
li.push_front('a'); //[ab]
li.push_back('c'); //[abc]
cout<<li.front(); //a
cout<<li.back(); //c
li.pop_front(); //[bc]
li.push_back('d'); //[bcd]
cout<<li.front(); //b
cout<<li.back(); //d
return 0;
}
运行结果:
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 程序员小航
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果