大一数据结构基础考核
数据结构基础
1. 实现一个函数,参数为一个字符串,该字符串中只包含左花括号
{ 和右花括号 } ,如果左右括号是匹配的,那么函数返回 True,
否则返回 False
比如,这个字符串是匹配的:{{}}
还有这样:{}{{}}{}{{}{}}
但是这样的字符串是不匹配的:{}}}{{}{}{{}}}
利用数据结构的知识解题。
- 非常裸的一个栈题
- 把字符串a传入 rev函数中 ,遍历a中的所有元素,
碰到左括号 就push,栈顶指针top++,
碰到 右括号 尝试pop,如果当前栈定没有 左括号
则pop失败,直接返回 0,如果成功pop,栈顶指针向下移动一位 top--
最后判断top == 0 是否成立,如果字符串是完全匹配的,栈为空,top==0
反之,top!=0 栈内还有元素
#include <bits/stdc++.h>
using namespace std;
const int N=5e5;
char a[N],b[N];
int top=0;
int rev(char *s){
int len=strlen(s);
for(int i=0;i<len;++i){
if(s[i]=='{'){
b[top++] = s[i];
}
else if(s[i]=='}'){
if(b[top-1]=='{'){
top--;
}
else return 0;
}
}
if(top == 0) return 1;
else return 0;
}
int main(){
gets(a);
if(rev(a)==1) printf("True\n");
else printf("False\n");
return 0;
}
2. 实现所给函数,完成单向链表的反转
(不允许开辟新的空间,不允许修改所给结构/类以及函数的定义)
注意:使用递归满分,其他视情况给分
- 思路是把链表的所有箭头都反向,指向他前一个
- 比如 1 -> 2 -> 3 -> 4 -> 5
rev: 1 <- 2 <- 3 <- 4 <- 5
- 因为是单链表 只有i->next,所以需要储存当前节点 now 和上一个节点 pre
正好用递归可以实现,node *now = rev(pre->next); 当前节点now是递归的末尾节点
now->next = pre , 当前节点指向上一个节点
pre的下一个节点设置成NULL,然后return pre ,作为上一个节点的now,继续递归,当前节点now为空
因为这个算法只改变了箭头的指向,而没有改变head 和 end,
所以遍历的时候,从end开始遍历。
if(now != NULL){
now->next = pre;
pre->next = NULL;
}
#include <bits/stdc++.h>
using namespace std;
struct node{
int data;
node *next;
};
class li{
node *head,*end;
public:
li():head(NULL),end(NULL){}
void push(int x){
node *newnode = new node;
newnode->data = x;
newnode->next = NULL;
if(head == NULL){
head = newnode;
}
else {
end->next = newnode;
}
end = newnode;
}
void print(){
node *thead = head;
while(thead!=NULL){
cout<<thead->data<<" ";
thead = thead->next;
}
}
node *rev(node *pre){
if(pre==NULL) return NULL;
if(pre->next==NULL) return pre;
node *now = rev(pre->next);
if(now != NULL){
now->next = pre;
pre->next = NULL;
}
return pre;
}
void chang(){
rev(head);
node *tend = end;
while(end!=NULL){
cout<<end->data<<" ";
end = end->next;
}
}
};
int main(){
li A;
int n,t;
cin>>n;
while(n--){
cin>>t;
A.push(t);
}
A.chang();
return 0;
}
3. 使用栈实现队列的下列操作:
push(x) -- 将一个元素放入队列的尾部。
pop() -- 从队列首部移除元素。
peek() -- 返回队列首部的元素。
empty() -- 返回队列是否为空。
- 用两个栈来模拟队列
push 就是入栈
pop 移除队列首部的第一个元素
因为stack是 后进先出,所以尝试把stack中的每一个元素中重新装入一个新的stack
这样就把原来的栈中的元素,完全颠倒了位置,达到了队列的要求(先进先出)
peek 同样使用pop中的方法实现
empty 调用stack中的empty
#include <bits/stdc++.h>
using namespace std;
stack<int > s,q;
void push(int i){
s.push(i);
}
bool empty(){
if(s.empty()) return 1;
else return 0;
}
void pop(){
while(!s.empty()){
q.push(s.top());
s.pop();
}
int val = q.top();
q.pop();
while(!q.empty()){
s.push(q.top());
q.pop();
}
}
int peek(){
while(!s.empty()){
q.push(s.top());
s.pop();
}
int val = q.top();
while(!q.empty()){
s.push(q.top());
q.pop();
}
return val;
}
int main(){
int x;
string ch;
while(1){
cin>>ch;
if(ch=="push"){
cin>>x;
push(x);
}
if(ch=="pop"){
pop();
}
if(ch=="exit") break;
if(ch=="peek"){
cout<<peek()<<endl;
}
if(ch=="empty"){
cout<<empty()<<endl;
}
}
}
4. 实现所给函数,实现删除链表的倒数第 n 个节点,并且返回链表的头结点。
(不允许修改所给结构/类以及函数的定义)
比如:一个单链表为 1->2->3->4->5,输入 n = 3 后,
得到的答案应该
为:1->2->4->5
输入的 n 保证是合法有效的。
注意:使用一遍扫描实现满分,其余视情况给分
- 实现倒数第k个,相当于正数第n-k+1个,
使用两个指针,都指向head,第一个指针先走k步,
然后第二个指针再开始走,等第一个指针走到链表的尾部时,第二个指针停止的地方就是要删除的元素
因为要删除它,所以应该让第二个指针指向 被删除元素的前一个元素,
那么第一个指针就要多走一步。
然后 thead->next = thead->next->next 就行了
不过还要特判一下 删除倒数第n个元素,即正数第一个元素
直接 让 head = head->next即可,就是把指针头移到第二个元素那么,当做头节点
#include <bits/stdc++.h>
using namespace std;
struct node{
int data;
node *next;
};
class li{
node *end,*head;
public:
li():end(NULL),head(NULL){}
void push(int x){
node *newnode = new node;
newnode->data = x;
newnode->next = NULL;
if(head==NULL){
head = newnode;
}
else {
end->next = newnode;
}
end = newnode;
}
void print(){
node *thead = head;
while(thead!=NULL){
cout<<thead->data<<" ";
thead = thead->next;
}
}
void updata(int i){
node *p = head,*thead = head;
while(i--&&p->next!=NULL) p = p->next;
cout<<p->data<<endl;
if(p->next==NULL) head = head->next;
else{
p = p->next;
while(p!=NULL){
thead = thead->next;
p = p->next;
}
thead->next = thead->next->next;
}
}
};
int main(){
li A;
int t,n;
cin>>n;
for(int i=0;i<n;++i) {
cin>>t;
A.push(t);
}
A.print();
cin>>t;
cout<<endl;
A.updata(t);
A.print();
return 0;
}
5. 实现一个函数,参数为两个整数a和b,且保证 a + b < 2147483647,
函数返回他们的和,即 a + b。
(WQH:真的以为这么简单?)
要求:不允许使用符号 + - * /
- 用位运算实现 +
#include <bits/stdc++.h>
using namespace std;
int add(int a,int b){
int ret = 0;
while(b){
ret = a^b;
b = (a&b)<<1;
a = ret;
}
}
int main(){
int a,b;
cin>>a>>b;
cout<<add(a,b);
return 0;
}