【C++】关于笔面试中的ACM输入输出处理 、构造链表、构造二叉树

练习题库推荐

牛客网上有一个专门的oj输入输出练习:
练习地址

所有的测试用例输入,最后一行都有一个回车"\n"

1getline(cin,str)读取换行符 并且将换行符替换成'\0',并将换行符从输入队列中抹去。
2、cin不会读入换行符;//这个众所周知,但是可以利用这个特点来连续读入任意个字符串

C++保留两位小数

#include <iostream> 
#include <iomanip>  //不要忘了头文件
using namespace std;
int main(){
	//第一种写法
	cout<<setiosflags(ios::fixed)<<setprecision(2);
	//第二种写法
	cout.setf(ios::fixed);
	cout<<setprecision(2);
	//第三种写法
	cout<<fixed<<setprecision(2);
}
  • 要保留几位小数setprecision(n)的括号里n就换成几。
  • 前两种写法是一样的,第三种是简化写的。
  • 上面的语句写一次就行了,对之后的数字都有效。

一、cin读取

cin遇到空格时会停止读取,所以可以使用while循环不停地读取数据

1、行数不固定,列数固定

下面这种写法就是针对行数不固定,但是每行只有两个数的情况

#include <iostream>
using namespace std;

int main() {
    int a, b;
    while (cin >> a >> b) { // 注意 while 处理多个 case
        cout << a + b << endl;
    }
}
// 64 位输出请用 printf("%lld")

2、 输入多行数据,每行个数不确定

题目描述:

输入描述:
输入数据有多组, 每行表示一组输入数据。

每行不定有n个整数,空格隔开。(1 <= n <= 100)。
输出描述:
每组数据输出求和的结果
示例1
输入
复制
1 2 3
4 5
0 0 0 0 0
输出
复制
6
9
0

关于cin.get():
cin.get()遇到结束符并不会将之删除
cin.get()并不会舍弃Space,依然会将其读取进去
利用上述特性就可以利用cin.get()来判断读取的数字的下一位是否为换行符

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

int main()
{

    int cur_sum = 0;
    int x;
    while (cin >> x)
    {
        cur_sum += x;
        if (cin.get() == '\n')
        {
            cout << cur_sum << endl;
            cur_sum = 0;
        }
    }

    return 0;
}

但是如果输入的一行中最后一个数字后面是空格+换行的话,那么就会导致该行没有输出数据,举例说明,输入1 2 ‘\n’,并没有输出1+2的和
在这里插入图片描述
因为cin并不会读取空格,在读取到2时,get()判断下一位并不是\n,所以此时并不会输出数字,但是下一次循环时cin只会跳过空格和结束符,继续读取下一行的数

二、getline读取

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
int main() {
  vector<vector<int>> arr;
  string input;
  while (getline(cin, input)) {
    if (input.size() > 0) {
      stringstream stringin(input);
      int num;
      vector<int> a;
      while (stringin >> num) {
        a.push_back(num);
      }
      arr.push_back(a);
    }
  }
  // 使用自测数据按钮时调试用,正式提交时要删掉。
  cout << "rows: " << arr.size() << ", cols: " << arr[0].size() << endl;
  for (int i=0; i<arr.size(); i++) {
    for (int j=0; j<arr[i].size(); j++) {
      cout << arr[i][j] << " ";
    }
    cout << endl;
  }
}

三、scanf输入

输入时记得在变量前加&
1、不发生改变获取输入值

#include <bits/stdc++.h>
using namespace std;
int main(){
   	int a;//声明变量 
   	scanf("%d",&a);//类型一致 
	cout<<"输出为:"<<a<<endl;
    
    return 0;
}

2、改变长度

#include <bits/stdc++.h>
using namespace std;
int main(){
   	int a;//声明变量 
   	scanf("%2d",&a);//类型一致 
	cout<<"输出为:"<<a<<endl;
    
    return 0;
}
 
//此时输入123,a=12,取两位

3、滞后赋值

#include <bits/stdc++.h>
using namespace std;
int main(){
   	int a;//声明变量 
   	scanf("%*d%d",&a);//类型一致 
	cout<<"输出为:"<<a<<endl;
    
    return 0;12
}
 
//输入n个数字后,a的值为第二个

四、printf输出

  • 语法:printf(“<格式化字符串>”,<参量表>);

  • 转换格式为:%[标志][宽度][.精度][类型长度]类型

1、转换为小数

#include <bits/stdc++.h>
using namespace std;
int main(){
   	float a=12;//声明变量 
   	printf("%.2f",a);//类型一致 ,两位数小数
    return 0;
}
 
//输出为12.00

2、改变位数

#include <bits/stdc++.h>
using namespace std;
int main(){
   	int a=12;//声明变量 
   	printf("%+6.5d",a);//类型一致 
    return 0;
}
 
//6表示长度,后面的.5表示五位数,最后输出为+00012

3、字符串类型

#include <bits/stdc++.h>
using namespace std;
int main(){
   	const char* a="hello world";//声明变量 
   	printf("*%20.4s*",a);//类型一致 
    return 0;
}
 
//20表示字符串宽度,后面的.4表示取的字符数,最后输出为*    hell*

五、构造链表

某公司嵌入式软开笔试题:输入一串数字到双向链表中,再将一个数字插入到该单向/双向链表中,最后按从小到大的顺序排列输出

单向链表

# include<iostream>
#include<vector>
using namespace std;


// 单链表
struct ListNode {
	int val;  // 节点上存储的元素
	ListNode* next;  // 指向下一个节点的指针
	ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
};

ListNode* creat(vector<int>& vec) {//创建n个节点
	ListNode* head = new ListNode(vec[0]);
	ListNode* temp = head;
	
	for (int i = 1; i < vec.size(); i++) {
		ListNode* node = new ListNode(vec[i]);
		
		temp->next = node;
		temp = temp->next;

	}

	return head;
}


//往链表中插入值为val的节点,尾插法,插在尾部
void insert_list(ListNode* head, int val) {
	ListNode* node = new ListNode(val);
	if (head == NULL) {
		head = node;
	}

	ListNode* temp = head;
	while (temp->next) {
		temp = temp->next;
	}
	temp->next = node;
	


}


//按照节点值从小到大的顺序进行排序
void sort_list(ListNode* head) {
	ListNode* temp = new ListNode(0);
	temp = head;

	while (temp) {
		ListNode* node = head;
		
		while (node->next) {
			if (node->next->val < node->val) {
				int val = node->next->val;
				node->next->val = node->val;
				node->val = val;
			}
			node = node->next;
		}
		temp = temp->next;

	}
	delete temp;
}

//输出链表节点值
void print_list(ListNode* head) {
	ListNode* temp = new ListNode(0);
	temp = head;
	while (temp) {
		cout << temp->val << " ";
		temp = temp->next;
	}
	cout << endl;
	delete temp;
}

int main() {
	int a = 5;
	vector<int> vec{ 1,2,3,9,6,4 };
	//cout << "请输入一串数字:";
	//while (cin >> a) {
	//	vec.push_back(a);
	//}

	ListNode* head = creat(vec);
	cout << "链表节点顺序:" << endl;
	print_list(head);

	//cout << "请输入要插入的数字:";
	//cin >> a;
	insert_list(head, a);
	insert_list(head, a);
	cout << "插入节点后链表节点顺序:" << endl;
	print_list(head);

	sort_list(head);
	cout << "排序后链表节点顺序:"<<endl;
	print_list(head);

	return 0;
}

双向链表

双向链表的头节点和尾节点是指向NULL的,而不是尾指针指向头节点形成一个环

# include<iostream>
#include<vector>
using namespace std;


// 双向链表  头节点和尾节点都指向NULL
struct ListNode {
	int val;  // 节点上存储的元素
	ListNode* pre;  // 指向上一个节点的指针
	ListNode* next;  // 指向下一个节点的指针
	ListNode(int x) : val(x), pre(NULL), next(NULL) {}  // 节点的构造函数
};


ListNode* creat(vector<int>& vec) {//创建n个节点
	ListNode* head = new ListNode(vec[0]);
	ListNode* temp = head;
	ListNode* pre_node = head;
	for (int i = 1; i < vec.size(); i++) {
		ListNode* node = new ListNode(vec[i]);
		node->pre = pre_node;
		pre_node = node;
		temp->next = node;
		temp = temp->next;

	}

	return head;
}


//往链表中插入值为val的节点,尾插法,插在尾部
void insert_list(ListNode* head, int val) {
	ListNode* node = new ListNode(val);
	if (head == NULL) {
		head = node;
	}

	ListNode* temp = head;
	while (temp->next) {
		temp = temp->next;
	}
	temp->next = node;
	node->pre = temp;


}


//按照节点值从小到大的顺序进行排序
void sort_list(ListNode* head) {
	ListNode* temp = new ListNode(0);
	temp = head;

	while (temp) {
		ListNode* node = head;
		
		while (node->next) {
			if (node->next->val < node->val) {
				int val = node->next->val;
				node->next->val = node->val;
				node->val = val;
			}
			node = node->next;
		}
		temp = temp->next;

	}
	delete temp;
}

//输出链表节点值
void print_list(ListNode* head) {
	ListNode* temp = new ListNode(0);
	temp = head;
	while (temp) {
		cout << temp->val << " ";
		temp = temp->next;
	}
	cout << endl;
	delete temp;
}

int main() {
	int a = 5;
	vector<int> vec{ 1,2,3,9,6,4 };
	//cout << "请输入一串数字:";
	//while (cin >> a) {
	//	vec.push_back(a);
	//}

	ListNode* head = creat(vec);
	cout << "链表节点顺序:" << endl;
	print_list(head);

	//cout << "请输入要插入的数字:";
	//cin >> a;
	insert_list(head, a);
	insert_list(head, a);
	cout << "插入节点后链表节点顺序:" << endl;
	print_list(head);

	sort_list(head);
	cout << "排序后链表节点顺序:"<<endl;
	print_list(head);

	return 0;
}

六、ACM构造二叉树

说明:输入一个数组,将其转换成二叉树,其中-1代表空节点。

用一个数组来存储二叉树,根据给定的数组构造二叉树
从二叉树 推导到 序列,可以发现这就是层序遍历。
在这里插入图片描述
如果父节点的数组下标是i,那么它的左孩子下标就是i * 2 + 1,右孩子下标就是 i * 2 + 2。
构造函数的返回值是二叉树的根节点,力扣上输入变量也是二叉树的根节点

#include<iostream>
#include<vector>
#include <queue>
using namespace std;

struct TreeNode
{
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode(int x) :val(x), left(NULL),right(NULL) {};
};

//构建二叉树
TreeNode* construct_tree(vector<int> vec, TreeNode* head, int i) {
	//如果父节点的数组下标是i,那么它的左孩子下标就是i * 2 + 1,右孩子下标就是 i * 2 + 2
	//使用递归
	if (i >= vec.size()||vec[i]==-1) return head;//如果i超过数组范围或者此节点为空节点  直接返回

	//说明此节点不是空节点
	head->val = vec[i];
	TreeNode* left = new TreeNode(-1);
	head->left = construct_tree(vec, left, 2 * i + 1);
	TreeNode* right = new TreeNode(-1);	
	head->right = construct_tree(vec, right, 2 * i + 2);


	return head;

}

//层次遍历法打印二叉树
void print_tree(TreeNode* head) {
	queue<TreeNode*> que;//使用队列保存每层的节点
	que.push(head);
	vector<vector<int>> result;
	while (!que.empty()) {
		int size = que.size();
		vector<int> vec;
		for (int i = 0; i < size; i++) {
			TreeNode* node = que.front();
			que.pop();
			vec.push_back(node->val);//注意这个不能放在下面if判断语句里面,因为空节点也需要打印
			if (node->val != -1) {//如果node节点不是空节点,可以将左右节点放进队列里面
				que.push(node->left);
				que.push(node->right);
			}

		
		}
		result.push_back(vec);
	}
	for (int i = 0; i < result.size(); i++) {
		for (int j = 0; j < result[i].size(); j++) {
			cout << result[i][j]<< " ";
		}
		cout << endl;
	}


}

int main() {
	vector<int> vec{ 4,1,6,0,2,5,7,-1,-1,-1,3,-1,-1,-1,8 };//用-1代表空指针
	TreeNode* head = new TreeNode(-1);
	head=construct_tree(vec, head, 0);
	print_tree(head);
	return 0;
}

输出结果如下:

4
1 6
0 2 5 7
-1 -1 -1 3 -1 -1 -1 8
-1 -1 -1 -1

还有其他一些类似题目:根据前序中序数组重建二叉树等
剑指 Offer 07. 重建二叉树

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值