动态内存分配测试
本道题测试你的动态内存分配的掌握程度
一共有三个函数需要你完善:
int* malloc_memory( int size, int value ); // 分配内存并用指定值填充该内存
void free_memory( int type, int* p ); // 释放分配的内存
char* copy_string( const char* s ); // 分配空间并拷贝字符串
其中malloc_memory
需要你分配可以存放size
个int
的内存并将该内存用value
填充,注意分配和填充的单位是int
。你不需要释放空间,判分模板会自动释放。
free_memory
函数的type
参数为1
时,p用new
分配出来的,type
参数为2
时,p用new []
分配出来的,C语言模式下不区分这两者。请你将p
用合适的方法销毁。
copy_string
函数要求你分配足够的空间,并将字符串s
复制到对应的空间里。
#include <string.h>
int* malloc_memory( int size, int value ){
int* p=new int[size];
for(int i=0;i<size;i++)
p[i]=value;
return p;
}
void free_memory( int type, int* p ){
if(type==1) delete p;
else delete[] p;
}
char* copy_string( const char* s ){
int size=strlen(s);
char* p=new char[size];
for(int i=0;i<size;i++)
p[i]=s[i];
return p;
}
动态数组分配
描述
本道题要求你读入一个动态的一维稀疏数组,将其创建并返回。
你总是应该分配合适的大小,不能多,也不能少。
输入
输入如下:第一行是包含的条目。从第二行开始是稀疏数组的条目,第一个数字是所在的下标(从0开始),第二个数字是值。例如:
2
1 2
2 3
第一行表示有2个条目第二行表示下标1的位置值为2。第三行表示下标2的位置值为3。
所以整个数组的内容为:0 2 3
输出
返回分配完成的指针,其中参数length
请放置数组的长度。
请注意你分配的空间不能多,也不能少,要正好能把所有元素放置进去。
如果长度为0,则返回空指针。
#include <memory.h> // 你可能会用得着
#include <vector>
int* read_array( int& length ){
int n,max=0;
vector<vector<int>> ve;
cin>>n;
if(n==0){ length=0;
return NULL;}
else{
for(int i=0;i<n;i++){
int x,v;
cin>>x>>v;
if(x>max)max=x;
ve.push_back({x,v});
}
length=max+1;
int* ans=new int[max+1];
memset(ans, 0, sizeof(int)*(max+1));
for(auto o:ve){
ans[o[0]]=o[1];
}
return ans;
}
}
模拟格斗
描述
本道题需要你模拟一个格斗的场景,一共需要你实现三个函数:
PLAYER* read_player(); // 从输入中读取角色信息,创建角色对象返回指针
void destory_player( PLAYER* player ); // 销毁指定角色对象
void players_fight( PLAYER* player1, PLAYER* player2 ); // 让两个角色互殴
每个角色都有一个HP,还有一套装备,装备的数量是不固定的,以下是对应的定义:
struct EQUIPMENT{ // 装备定义
int atk; // 攻击力
int def; // 防御力
};
struct PLAYER{ // 角色定义
int HP; // 血量
int eqpt_count; // 装备的数目
EQUIPMENT* eqpts; // 放置装备列表的指针
};
角色按如下规则输入:第一行是角色的HP第二行是角色装备的数目第三行开始是角色装备的属性,攻击力在前,防御力在后例如:
50
2
10 5
10 20
说明角色的HP是50,有两件装备,第一件攻击力10、防御力5,第二件攻击力10、防御力20。
角色的攻击力和防御力等于身上所有装备的和,以上面为例,这个角色有20的攻击力和25的防御力,是一个肉盾。
当角色互殴时,有以下规则:
- 对对方造成的伤害等于己方攻击力-对方防御力
- 如果己方攻击小于对方防御力,则对对方的伤害是1点,即最少会造成1点伤害
- 如果角色受到大于自己HP的伤害时,HP归0(而不是变成负数)。
你需要正确计算双方互殴之后的剩余血量并赋值给对应角色的HP。
例如:角色1
10
2
3 1
2 1
角色2
10
2
1 2
3 1
则角色1攻击力=5,防御力=2,角色2攻击力为4,防御力为3那么角色1对角色2造成5-3=2点伤害,角色2对角色1造成4-2=2点伤害。此时双方的HP都应该是8。
又例如:角色1
10
2
3 1
2 1
角色2
1
2
9 8
7 3
角色1攻击5,防御2,角色2攻击16,防御11。角色1的攻击力比角色2的防御力低,但他依然能造成1点伤害。角色2有16点攻击,对角色1造成14点伤害,超过了角色1的10点hp。所以双方的血量都变为0,双双毙命。
输入
第一行是角色的HP第二行是角色装备的数目第三行开始是角色装备的属性,攻击力在前,防御力在后例如:
50
2
10 5
10 20
说明角色的HP是50,有两件装备,第一件攻击力10、防御力5,第二件攻击力10、防御力20。
互殴时,保证输入的指针是正确的
输出
正确配置对应的变量即可
//struct EQUIPMENT{
// int atk;
// int def;
//};
//
//struct PLAYER{
// int HP;
// int eqpt_count;
// EQUIPMENT* eqpts;
//};
PLAYER* read_player(){
PLAYER* role=new PLAYER;
cin>>role->HP>>role->eqpt_count;
EQUIPMENT* e=new EQUIPMENT[role->eqpt_count];
role->eqpts=e;
for(int i=0;i<role->eqpt_count;i++){
cin>>e[i].atk>>e[i].def;
}
return role;
}
void destory_player( PLAYER* player ){
delete[] player->eqpts;
delete player;
}
void players_fight( PLAYER* player1, PLAYER* player2 ){
int g1=0,g2=0;
int f1=0,f2=0;
for(int i=0;i<player1->eqpt_count;i++){
g1+=player1->eqpts[i].atk;
f1+=player1->eqpts[i].def;
}
for(int i=0;i<player2->eqpt_count;i++){
g2+=player2->eqpts[i].atk;
f2+=player2->eqpts[i].def;
}
int damage1=g1<f2?1:g1-f2;
int damage2=g2<f1?1:g2-f1;
player1->HP=player1->HP-damage2<=0?0:player1->HP-damage2;
player2->HP=player2->HP-damage1<=0?0:player2->HP-damage1;
}
顺序表创建与删除
描述
本道题要求你读入数据并创建顺序表,具体的数据见下方。
你还需要编写销毁的额函数,保证内存可以被正确的回收。
本道题会进行内存泄漏检查,请注意。
输入
第一行是数字n,代表元素的数目。
第二行有n个数字,以空格隔开,是具体的元素。
第三行是数字m,表示要删除的次数。
第四行有m个数字,以空格隔开,表示删除元素的下标。
例如:
5
1 2 3 4 5
2
4 2
第一二行说明有5个元素,依次是1 2 3 4 5
。
第三四行说明要求删除第两次,分别下标是4和2。
所以得到的顺序表就是1 2 4
。
请注意,下标是要执行删除时对应的下标,而不是最初的下标。
举例来说:
5
1 2 3 4 5
3
1 1 1
对下标1连续删除3次,第一次删除时,得到的顺序表是1 3 4 5
。第二次删除时,下标1对应的元素是3,因此变成1 4 5
,第三次删除时,就变成1 5
输出
create_sequence
的参数seq
应该在函数内被正确的设置,seq
即返回的创建好的顺序表。
destroy_sequence
需保证seq
的空间被正确的释放。内存泄漏将无法通过测试
//struct SEQUENCE{
// int size; // 总体分配的空间
// int count; // 现有的数据
// int* data; // data指向
//};
void create_sequence( SEQUENCE& seq ){
int n,m;
cin>>n;
seq.size=n;
seq.count=n;
seq.data=new int[n];
for(int i=0;i<n;i++)
cin>>seq.data[i];
cin>>m;
for(int i=0;i<m;i++){
int t;
cin>>t;
for(int j=t;j<seq.count-1;j++)
seq.data[j]=seq.data[j+1];
seq.count--;
}
}
void destroy_sequence( SEQUENCE& seq ){
delete[] seq.data;
}
顺序表的区间删除
描述
请编写函数
void remove_batch( SEQUENCE* seq, int begin, int end ); // C语言版本
void remove_batch( SEQUENCE& seq, int begin, int end ); // C++版本
删除[begin,end)
区间的元素。
顺序表的count
属性必须被正确的设置。
例如有顺序表:
1 2 3 4 5
要求你删除[1,4)
的区间,那么你会得到:
1 5
输入
seq
就是所要操作的顺序表,begin
和end
是区间删除的起点和终点。
请注意区间的定义是符合大多数程序员编码习惯的[begin, end)
。即所谓前闭后开区间,要删除的元素包括begin
,但不包括end
。
seq.count<1000000
输出
顺序表seq
必须被正确的设置,包括data
的值和count
。
你不需要(实际上,是不允许)对data
进行销毁,伸缩,重新赋值等操作,这些操作可能导致内存检测失败。你只需要就地修改元素的值就可以了。
//struct SEQUENCE {
// int size; // 预留的空间
// int count; // 当前的数目
// int* data; // 数据指针
//};
void remove_batch( SEQUENCE& seq, int begin, int end ){
int i=begin,j=end;
for(;j<seq.count;)
seq.data[i++]=seq.data[j++];
seq.count-=end-begin;
}
重整队列
描述
请编写重整顺序表的函数:
void reform_sequence( SEQUENCE* src, SEQUENCE* des ); // C版本
void reform_sequence( SEQUENCE& src, SEQUENCE& des ); // C++版本
对顺序表内容进行整理。
要求:去除src
里相同的数字,同时将其在des
中按顺序排列。
例如,假设src的值为:
1 1 3 3 2 2 2
去除重复数字并按顺序排列后,des的值应该为:
1 2 3
本道题必须在顺序表上进行操作,不允许调用库函数。
请注意并不保证重复的数据一定相邻,也就是说这样的数据也是可能的:
1 3 1 2 2 3 1
得到的结果也是:
1 2 3
输入
src
和des
都已初始化。des
的空间足够你写入。
输出
des
的内容应该被正确设置,包括元素和count
属性。
//struct SEQUENCE{
// int size; // 预留尺寸
// int count; // 当前数量
// int* data; // 数据
//};
#include <queue>
#include <unordered_set>
void reform_sequence( SEQUENCE& src, SEQUENCE& des ){
priority_queue<int,vector<int>,greater<int>> q;
unordered_set<int> s;
for(int i=0;i<src.count;i++){
if(s.count(src.data[i])==0)
q.push(src.data[i]);
s.insert(src.data[i]);
}
des.count=q.size();
for(int i=0;i<des.count;i++){
des.data[i]=q.top();
q.pop();
}
}
祖玛大消除(新)
描述
祖玛是大家都熟悉的游戏。如果射出的球击中球链,且此时生成的新链中相同颜色的球大于等于3个。则这些球可以被消除。
例如,你有一串链是:112233
。此时你射出一个2
的球,球击中了链中的第一个2
(第3个球),此时链变成:1122233
因为中间的2
有3个,满足消除的条件,他们会被消除,于是你获得:
1133
消除可以连击,例如:1122113
射出2
还是击中第一个2
。此时链变成112221133
,消除2
后,链变成:
111133
前后两串1
拼接在一起后,形成四个1
,又满足消除条件,继续消除,得到:
33
注意连击只能发生在重新拼接的场合,如果原来的链就可以消除,不是通过拼接达到消除条件,则不能消除。
举例来说:
当前链是11122333
,射出2
击中第一个2
,此时中间形成3个2
:111222333
,2个2
被消除,得到111333
。
尽管此时前后的1
和3
都满足消除条件,但他们不是拼接之后达到消除条件的,因此不能产生连击,最后的结果就是:
111333
基于上述的要求,我们将球组织成带头节点的双向循环链表的形式。请你编写消除的函数完成消除工作。
输入
函数
void hit_zuma_chain( DUAL_NODE* head, int pos, int color );
的第一个参数head
是链表的头节点,第二个参数是击中球链的球的位置。
位置采用如下约定,下标以0开始计算,插入对应元素的前面。例如:
12345
如果此时pos=2
,color=6,则应该形成,下标为2的元素是3,6应该插入3前面,形成
126345
的链条,而不是
162234
或者
123645ni
头指针的颜色被设计成绝对不会与其他颜色相同,这可以简化你的逻辑判断。
输出
你需要处理消除,确保head
指向的链表的结果是正确的。
//struct DUAL_NODE {
// DUAL_NODE* prev;
// DUAL_NODE* next;
// int color;
//};
void hit_zuma_chain( DUAL_NODE* head, int pos, int color ){
DUAL_NODE* node=new DUAL_NODE;
node->color=color;
DUAL_NODE* p=head->next;
for(int i=0;i<pos;i++)
p=p->next;
node->prev=p;
node->next=p->next;
p->next->prev=node;
p->next=node;
while (1) {
int num = 0;
DUAL_NODE* p = node->prev;
DUAL_NODE* n = node->next;
while (node->color == p->color && p != head) {
p = p->prev;
num++;
}
while (node->color == n->color && n != head) {
n = n->next;
num++;
}
if (num > 1) {
while (p->next != n) {
DUAL_NODE* t = p->next;
p->next = t->next;
t->next->prev = p;
delete t;
}
p->next = n; //更新p与n指针
n->prev = p;
if (n == p || n->color != p->color)
break;
if (p != head)
node = p;
else
node = n;
}
else
break;
}
}
链表排序
描述
给定带头节点的单链表head
,请编写函数sort_list
,对其中的元素进行排序。
你应该返回一个排好序的链表。你可以复用原来的链表,也可以新建链表。
当你新建链表时,你需要保证原链表被正确销毁,避免内存泄漏。
判分程序只负责销毁返回的链表,不会销毁原链表,请注意!
输入
待排序的链表head
。
输出
排好序的链表。
注意如果你新建了链表,你需要负责将原链表销毁。
//struct Node{
// int value;
// Node* next{nullptr};
//};
#include <vector>
#include <algorithm>
Node* sort_list( Node* head ){
vector<int> v;
Node* p=head->next;
while(p!=nullptr){
v.push_back(p->value);
p=p->next;
}
sort(v.begin(),v.end());
p=head->next;
int index=0;
while(p!=nullptr){
p->value=v[index++];
p=p->next;
}
return head;
}
多项式乘法--简单版
描述
本道题要求你计算多项式的乘法,但乘数只有一项:
例如:
(1+4*x^2+5*x^3+2*x^5)*(2*x^3) = 2*x^3+8*x^5+10*x^6+4*x^8
其中4*x^2表示4乘x的二次方。
多项式保存在一个链表里,节点表示为:
struct PolyNode{
int coef;
int pow;
PolyNode* next{nullptr};
};
其中coef
为系数项,即上面的4
,pow
为次数,即上面的2
,链表带头节点,各项以次数为序依次排列。
因此
1+4*x^2+5*x^3+2*x^5
可以被表示为如下的链表:
head->(coef=1, pow=0)->(coef=4,pow=2)->(coef=5,pow=3)->(coef=2,pow=5)
现在编写函数:
PolyNode* polynomial_times_term( const PolyNode* p1, int coef, int pow )
计算多项式乘某项的结果。
输入
PolyNode* polynomial_times_term( const PolyNode* p1, int coef, int pow )
p1
为被乘数,即上面的1+4*x^2+5*x^3+2*x^5
,链表带头指针。
coef
和pow
为乘数的系数项和幂次,在上例中,乘数是2*x^3
,因此coef=2
,pow=3
输出
返回乘法的结果,结果应该为一个链表,带头节点。
各项必须以幂次为单位升序排列。
//struct PolyNode{
// int coef;//系数
// int pow;//次数
// PolyNode* next{nullptr};
//};
PolyNode* polynomial_times_term( const PolyNode* p1, int coef, int pow ){
PolyNode* ans=new PolyNode;
PolyNode* node=new PolyNode;
ans->next=node;
PolyNode* p=p1->next;
while(p!=nullptr){//创建答案链表
node->coef=p->coef*coef;
node->pow=p->pow+pow;
if(p->next!=nullptr){
node->next=new PolyNode;
node=node->next;
}
p=p->next;
}
return ans;
}
多项式加法
描述
本道题要求你计算多项式的加法:
例如:
(3+2*x^1-3*x^2+2*x^5) + (1+3*x^1+3*x^2+3*x^3) = 4+5*x^1+3*x^3+2*x^5
其中3*x^2表示3乘x的二次方。
注意这里x^2
项在相加之后系数为0,应该消项。
多项式保存在一个链表里,节点表示为:
struct PolyNode{
int coef;
int pow;
PolyNode* next{nullptr};
};
其中coef
为系数项,即上面的4
,pow
为次数,即上面的2
,链表带头节点,各项以次数为序依次排列。
因此
3+2*x^1-3*x^2+2*x^5
可以被表示为如下的链表:
head->(coef=3, pow=0)->(coef=2,pow=1)->(coef=-3,pow=2)->(coef=2,pow=5)
现在编写函数:
PolyNode* polynomial_add( const PolyNode* p1, const PolyNode* p2 );
计算多项式加法的结果。
输入
p1
和p2
为待相加的两个多项式。
输出
返回乘法的结果,结果应该为一个链表,带头节点。
各项必须以幂次为单位升序排列。
//struct PolyNode{
// int coef;
// int pow;
// PolyNode* next{nullptr};
//};
PolyNode* polynomial_add( const PolyNode* p1, const PolyNode* p2 ){
PolyNode* ans=new PolyNode;
PolyNode* node=ans;
int* value=new int[1005];
for(int i=0;i<1005;i++)
value[i]=0;
PolyNode* temp=p1->next;
while(temp!=nullptr){//对p1和p2都进行一次遍历,记录x的每个次数对应的系数
value[temp->pow]+=temp->coef;
temp=temp->next;
}
temp=p2->next;
while(temp!=nullptr){
value[temp->pow]+=temp->coef;
temp=temp->next;
}
for(int i=0;i<1005;i++){//创建答案链表
if(value[i]!=0){
PolyNode* p=new PolyNode;
p->coef=value[i];
p->pow=i;
node->next=p;
node=node->next;
}
}
delete[] value;
return ans;
}
多项式乘法-完全体
描述
该来的总会来,本道题要你计算两个多项式相乘的结果。
多项式的描述不再赘述,请参考之前的内容。
注意,本题有内存泄漏检测,p1
、p2
和你返回的链表,由判题模板负责销毁。
除此之外你计算用到的临时数据,需要你自己负责销毁。
显然你需要善用上面前面两道题的结果,才能计算本道题。
输入
p1
,p2
为待相乘的两个多项式。
你不用关心p1
和p2
的销毁,由判题模板自动销毁。
输出
返回乘法的结果,结果应该为一个链表,带头节点。
各项必须以幂次为单位升序排列。
返回的链表也由判题模板负责销毁。
//struct PolyNode{
// int coef;
// int pow;
// PolyNode* next{nullptr};
//};
PolyNode* polynomial_times( const PolyNode* p1, const PolyNode* p2 ){
PolyNode* ans=new PolyNode;
PolyNode* node=ans;
int* value=new int[1005];
for(int i=0;i<1005;i++)
value[i]=0;
PolyNode* temp=p1->next;
PolyNode* t;
while(temp!=nullptr){//对于p1的每一项都与p2所有项相乘,存储相乘结果
t=p2->next;
while(t!=nullptr){
value[temp->pow+t->pow]+=temp->coef*t->coef;
t=t->next;
}
temp=temp->next;
}
for(int i=0;i<1005;i++){//创建答案链表
if(value[i]!=0){
PolyNode* q=new PolyNode;
q->coef=value[i];
q->pow=i;
node->next=q;
node=node->next;
}
}
delete[] value;
return ans;
}