数据结构实验(一)程序设计回顾

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 调整数组使奇数全部都位于偶数前面其他数字顺序不变

这题有个很奇怪的地方就是数据中是没有的多余的换行符的,但是输出却是用putsputs会默认输出一个换行符。所以我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" : "" );
    }
posted @ 2022-09-01 16:39  PHarr  阅读(174)  评论(0编辑  收藏  举报