Home Bugs I Encountered (Week 3)
Post
Cancel

Bugs I Encountered (Week 3)

Problom 1 Wrong number

Original Problem:

Give you a string, extract all the negative numbers from the string.

e.g. (Source code: THU OJ)

Input:

1
2
3
4
5
6
7
This line contains 1 integer "one".
This line contains no integer.
233, next line is empty.

If you got -123.456, you should output 123 and 456.
Any digit string are considered integers, like 0123456 and 007.
You may also need to consider cases like a0a12a345a6789a.

Output:

1
2
3
4
5
6
7
1

233

123 456 123 456
0123456 007
0 12 345 6789

Solution:

  1. The main idea of the source code:

    Find the first number of each string, then find the last number of the string, here we have a total number string.

    Decide whether it is the first string, if not so, output a SPACE.

  2. Bugs in the idea of the sorce code:

(1) The source code didn’t initialize the bool-type variable.

(2) The source code mistakes the ASCII code between character and number:

'0'-'9' VS 0-9

  1. My solution

    I chose to judge whether the number string is the last one (because I’m accustomed to output a space behind a string [Facepalm])

My source code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <string>
#include <cctype>

using namespace std;

int main() {
    for (string str; getline(cin, str); ) {
        bool if_final = true;
        
        size_t length = str.size();
       /*********************************************************************************************************************
        * Judge whether the character is a number.
        * If so, find the last number following it.
        * Find out whether it is the last number string by judging whether there is still number behind this string
        * If so, it is not the last string, and you need to output a SPACE.
        *********************************************************************************************************************/
        for(size_t i = 0; i < length; ++i){
            if(str[i] >= '0' && str[i] <= '9'){
                size_t index = i;
                while(str[index] >= '0' && str[index] <= '9'){
                    putchar(str[index]);
                    ++index;
                }
                size_t inspect_back = index;
                while((str[inspect_back] < '0' || str[inspect_back] > '9') && inspect_back < length - 1){
                    ++inspect_back;
                    if(str[inspect_back] >= '0' && str[inspect_back] <= '9')
                        if_final = false;
                }
                if(!if_final) putchar(' ');
                i = index;
                if_final = true;
            }
        }
        printf("\n");
    }
    return 0;
}

Problem 2 Wrong drink

Original problem:

Give you several kinds of wine, the density is $d_i$, the price is $p_i$. Now input a series of densities, the program should output the lowest cost.

(Source code: THU OJ)

Solution:

  1. The idea of the source code is treating pairs ($d_i$, $p_i$) as a point of a 2-dimensional surface, find the convex hull, and pick two wines on the hull.

  2. Bugs in the idea:

(1) The automatically called constructor and destructor: HERE WE HAVE AN EXAMPLE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

class NewClass{
public:
    NewClass(){std::cout << "Constructor !" << std::endl; }
    ~NewClass(){std::cout << "Destructor !" << std::endl; }
};

int main(){
    printf("Object:\n");
    NewClass cls;
    printf("\n");
    
    printf("Pointer:\n");
    NewClass* ptr1;
    printf("\n");
    
    printf("New a pointer:\n");
    NewClass* ptr2 = new NewClass();
    printf("\n");
    
    // delete ptr2;
    return 0;
}

Output:

1
2
3
4
5
6
7
8
9
10
Object:
Constructor !

Pointer:

New a pointer:
Constructor !

Destructor !
Program ended with exit code: 0

Here we can find that if we just declare a pointer, both the two functions won’t be called automatically.

If you new a pointer, the constructor will be called automatically, while the destructor won’t.

If you declare an object, both the two functions will be called automatically.

Therefore we conclude that the automatically-called mechanism only works for objects. For pointer, sorry, you need to operate them manually.

(2) Special situations

Sometimes the new wine can’t be made: the minimum density is larger than the given density or the maximum density is smaller than given density. We need to deal with them seperately.

My source code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <memory>


using namespace std;

// A bottle of wine
typedef pair<int, int> dpair;

// Node
/***********************************************
 * Initialized value = 0;
 * Counter = 0 <===> Nope or destroyed
 * Counter = 1 <===> Created
************************************************/
struct Wine {
    int d, p;
    Wine* last;
    static int counter;
    Wine() { ++counter; }
    ~Wine() { --counter; }
};
int Wine::counter = 0;

/*****************************************************************
 * Memory inspector, NO MODIFYING !!!!
 * It will be destroyed when the programme ends,
 * If counter != 0, it means that the wine is not destructed
 *****************************************************************/
struct Checker {
    int _;
    ~Checker() { if (Wine::counter != 0) cout << "你的对象没有正确释放!\n"; }
} _c;


int main() {
    ios::sync_with_stdio(0);
    int n, m;
    vector<dpair> wines;
    vector<int> qs;
    
    // Input n,m and the density & price of each bottle of wine
    // Create a wine shelf
    cin >> n >> m;
    for (int i = 0; i < n; ++i) {
        int d, p;
        cin >> d >> p;
        wines.push_back(dpair(d, p));
    }
    
    // Sort according to density
    sort(wines.begin(), wines.end());

    // Create a new list
    Wine* phead = nullptr;
    Wine* temp = nullptr;
    for (int i = 0; i < n; ++i) {
        // Read in wine[i], you can say q = the corresponding struct node
        auto q = new Wine;
        q->d = wines[i].first;
        q->p = wines[i].second;
        // If two wines have the same value of d, discard the one whose q is bigger
        if ( phead && phead->d == q->d) q->~Wine();
        
        // If phead and its tail aren't NULL
        while (phead != nullptr && phead->last != nullptr) {
            // Compare slope factor, delete the nodes away from the list
            // Convert the denominator to double type to avoid singular point 
            if ((q->p - phead->p) / (double)(q->d - phead->d) <=
                (phead->p - phead->last->p) /(double)(phead->d - phead->last->d)){
                temp = phead;
                phead = phead->last;
                temp->~Wine();
            }
            else break;
        }
        
        // If phead isn't NULL or phead doesn't match q
        // The first loop go to here
        if (!phead || q->d != phead->d) {
            q->last = phead;
            phead = q;
        }
    }

    // Use vector to search
    wines.clear();
    for (auto i = phead; i; i = i->last) {
        wines.push_back(dpair(i->d, i->p));
    }
    // Delete the list
    for (auto i = phead; i; i = i->last) {
        i->~Wine();
    }
    reverse(wines.begin(), wines.end());

    
    cout.setf(ios::fixed);
    for (int i = 0; i < m; ++i) {
        int q;
        cin >> q;
        
        // Find the point which is the nearest to the the lowest hull
        // Here price is initialized to 0
        if((wines[0].first > q) || (wines[wines.size() - 1].first < q))
            cout << -1 << endl;
        else{
            auto it = lower_bound(wines.begin(), wines.end(), dpair(q, 0));
            auto ib = it - 1;
            double res = (it->first - q) / (double)(it->first - ib->first) * ib->second;
            res += (q - ib->first) / (double)(it->first - ib->first) * it->second;
            cout << setprecision(2) << res << endl;        
        }
    }
}

Acknowledgement:

Thanks for Zhixiao Xiong(熊志潇,未央工-11)’s help, after several days’ debugging, we finally found the reason why the object couldn’t be released correctly.

This post is licensed under CC BY 4.0 by the author.

Binary Search Tree (Python)

Full Permutation with Recursion