数据结构实验(一)程序设计回顾
6-1 最大子段和
因为是字段和,所以要尽可能的多加,如果在加的过程中当前和为负数时,往后累加一定不会比保留当前值更优秀,所以要把之前的部分抛弃重新累加
int mis(int a[], const int n) {
int res = 0 , sum = 0 ;
for( int i = 0 ; i < n ; i ++ ){
sum += a[i];
if( sum > res ) res = sum;
if( sum < 0 ) sum = 0;
}
return res;
}
6-2 日期类型
判断闰年的标准操作
int IsLeapYear(int year){
if( year % 4 == 0 && year % 100 != 0 || year % 400 == 0 ) return 1;
return 0;
}
6-3 调整数组使奇数全部都位于偶数前面其他数字顺序不变
这题有个很奇怪的地方就是数据中是没有的多余的换行符的,但是输出却是用puts
,puts
会默认输出一个换行符。所以我exit
函数提前结束了程序,没有使用主程序给的输出函数
void fun ( char s[] ){
for( int i = 0 ; i < strlen(s) ; i ++ )
if( (s[i] - '0') % 2 == 1 ) printf("%c" , s[i] );
for( int i = 0 ; i < strlen(s) ; i ++ )
if( (s[i] - '0') % 2 == 0 ) printf("%c" , s[i] );
exit(0);
}
7-1 链表操作
这里的链表操作是非常基础的
首先输出是反复被调用的,所以可以先写输出链表的函数,这里输出的时候可以使用结构化绑定非常好用
void print(){
for( auto [ id , name , age ] : l )
cout << id << " " << name << " " << age << "\n";
}
要注意的是,最初建立链表是逆向链表,这里我用了双向链表,每次都在头部插入。
删除第 m 个节点其实也比较简单,就是从第一个节点向后跳 m 次删除就好了。
删除指定的学号就要把整个序列一遍就好了。
#include<bits/stdc++.h>
using namespace std;
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
typedef tuple<int,string,int> stu;
list<stu> l;
void print(){
for( auto [ id , name , age ] : l )
cout << id << " " << name << " " << age << "\n";
}
void getStu( stu & it ){
auto & [ id , name , age ] = it;
id = read() , cin >> name , age = read();
}
void solve(){
int n = read();
l.clear();
for( stu it ; n ; n -- ){
getStu(it);
l.push_front( it );
}
print();
{
int m = read();
stu cur ;
getStu(cur);
auto it = l.begin();
while( m ) it ++ , m --;
l.insert( it , cur );
}
print();
{
int id = read();
for( list<stu>::iterator it = l.begin() ; it != l.end() ; it ++ )
if( get<0>(*it) == id ) it = l.erase(it) -- ;
}
print();
}
int32_t main() {
for( int T = read() ; T ; T -- )
solve() , cout << ( T == 1 ? "" : "\n");
return 0;
}
7-2 单链表基本操作
这个题其实相比上一题更加简单了,我就手写一下链表,还是很轻松的
不过这道题还是让我发现了一个值得考虑的问题,来看一下我最初写的链表的构造函数
List(){
size = 0;
begin = end = nullptr;
}
看似是没有问题,那么在看一下我的插入函数吧
void insert( int pos , int val ){
if( pos > size ) return;
auto it = begin;
while( pos ) pos -- , it = it->next ;
it->next = new Node( val , it->next );
size ++;
}
这个时候,我在插入第一个元素的时候就会直接执行it->next = new Node( val , it->next)
但是此时我的 it
就是begin
,而begin
还是指向nullptr
的就会直接导致RE
,所以因为这里是单链表,正确的解决方法是
List(){
size = 0;
end = nullptr;
begin = new Node( 0 , end );
}
让begin
指向一个空节点就好了。那么此时要注意的就是实际上链表的第一个节点应该是begin->next
。
虽然这个问题有其他的解决方法,要注意的是这里道题问题是可能会在0
的位置插入节点,所以其他的方法还有特判begin==nullptr
或者是直接写双向链表。
#include<iostream>
struct Node{
int val ;
Node * next;
Node( int val , Node * next ) : val(val) , next(next){};
};
class List{
private:
int size;
Node * begin , * end;
public:
List() {
size = 0;
end = nullptr;
begin = new Node( 0 , end );
}
void insert( int pos , int val ){
if( pos > size ) return;
auto it = begin;
while( pos ) pos -- , it = it->next ;
it->next = new Node( val , it->next );
size ++;
}
void print(){
for( auto it = begin->next ; it != end ; it = it->next )
std::cout << it->val << " ";
std::cout << "\n";
}
void remove( int pos ){
if( pos > size || pos == 0 ) return;
auto it = begin;
while( pos > 1 ) pos -- , it = it->next;
it->next = it->next->next;
size --;
}
};
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
int main(){
List list;
int n = read();
for( int v , i = 0 ; i < n ; i ++ )
v = read() , list.insert( i , v );
for( int m = read() , op , k , v ; m ; m -- ){
op = read();
if( op ){
k = read();
list.remove(k);
}
else{
k = read() , v = read();
list.insert( k , v );
}
}
list.print();
return 0;
}
7-3 报销
这题其实非常简单的,定义一个结构体,然后重载一下运算符就好了
#include<bits/stdc++.h>
using namespace std;
struct account{
int id , val;
string name;
account( int id , int val , string name ) : val(val) , name(name) , id(id){};
friend bool operator < ( account a , account b ){
if( a.val != b.val ) return a.val > b.val;
if( a.name != b.name ) return a.name < b.name;
return a.id < b.id;
}
};
void solve(){
int n , m;
cin >> n >> m;
vector< account > ve;
vector<int> rank;
for( auto [ id , name , val ] = tuple{ 1 , (string)"" , 0 } ; id <= n ; id ++ , val = 0 ){
cin >> name;
for( int x , i = 1 ; i <= m ; i ++ )
cin >> x , val += x;
ve.push_back( account( id , val , name ) );
rank.push_back(val);
}
sort( ve.begin() , ve.end() ) , sort( rank.begin() , rank.end() , greater<int>() );
for( auto [id , val , name] : ve ){
int rk = lower_bound( rank.begin() , rank.end() , val ,greater<int>() ) - rank.begin() + 1 ;
cout << rk << " " << id << " " << name << " " << val << "\n";
}
}
int main(){
int T ;
cin >> T;
for( int i = 1 ; i <= T ; i ++ )
cout << "Case " << i << ":\n" ,solve() , cout << ( i != T ? "\n" : "" );
}