Search code examples
c++c++11run-length-encoding

Problem with a run-length encoding program c++


I am trying to make a code that does run=length encoding based on the value entered by the user. Only accepts lower-case letters. Using two vectors. The problem is it doesn't with all examples: Example: zzzzzzzz output: (terminate called after throwing an instance of 'std::out_of_range' what(): basic_string::at: __n (which is 8) >= this->size() (which is 8) exit status -1)

How can it be solved?

    #include <iostream>
    #include <string>
    #include <vector>

    using namespace std;

     bool is_small_letter(char c){
      return c >= 'a' && c <= 'z';
    }

    void runLength(string str, vector<char>& charachters, vector<int>& length) {
      int count;
      int i;

      for (i = 0; i < str.size(); i++) {
        if (!is_small_letter(str.at(i))) {
          throw runtime_error("invalid input");
        }

        **count = 1;
        if (i == str.size() -1) {
          // do nothing
        } else {
          while (str.at(i) == str.at(i + 1)) {
            count++, i++;
          }**  //changed following one answer advice.
        }
        charachters.push_back(str.at(i));
        length.push_back(count);
      }
    }

    int main() {
      string str;
      vector<char>charachters;
      vector<int>length;

      cout << "Enter the data to be compressed: ";
      cin >> str;
      try {
        runLength(str, charachters, length);

        cout << "The compressed data is: ";
        for (int i = 0; i <= length.size() - 1; i++){
          cout << length.at(i) << charachters.at(i);
        }

      } catch (runtime_error &excpt) {
         cout << endl << "error: " << excpt.what();
      }

      return 0;
    }

Solution

  • unfortunately mbonness'es answer will only delay your demise.

    This happens because it didn't consider the case of what would happen if at least the last 2 characters in a string were same. for example what would happen if player entered abcdd ? since the while loop was iterating the i, it would go out of the scope within the while loop. hence the crash would happen.

    However, there is also another issue you haven't thought about yet. what happens if you have multiple characters in a string that are not next to each other? for example ababab? the current code will not handle such senario.

    This is why unfortunately you have to loop the entire str vector twice. and store each character one at a time. and whenever you start next iteration you have to check if the character is already in the characters vector. if so you ignore the scan and move on to the next.

    let's look at the function body;

      void runLength(string str, vector<char>& charachters, vector<int>& length) {
          int count;
          int i;
    
          for (i = 0; i < str.size(); i++) {
    

    so what's happening in this for loop? we keep running as long as i is less than str.size(). note that although str.size() is not a zero-based index it will work fine. why? because we are not using <= operators. we are using < operator.

    next, we going to need a bool variable to check if the current str.at(i) already added to the vector<char>charachters.

    bool charAlreadyExist = false;
    

    let's do our second inner loop to check if the characters contain the current element of the str.

     for(int l = 0; l < charachters.size(); l++)
        {
            if(charachters.at(l) == str.at(i))
            {
               charAlreadyExist = true;
               break;
            }
        }
    

    the next loop only starts if charAlreadyExist is false

     if (charAlreadyExist == false)
            {
              for(int j = 0; j < str.size(); j++)
              {
                  if (str.at(i) == str.at(j))
                  {
                    count++;
                  }
              }
    

    Notice that in the above statement we no longer increment i. this was the reason why mmbonnes'es answer would fail

    the rest of the function code would be similar to what you did.

    Here is the full function code. but try to implement it with out looking at it first though. it will help you understand the code better

    void runLength(string str, vector& charachters, vector& >!length)
    {
        int count;
        int i;
        for (i = 0; i < str.size(); i++)
        {
            count = 0;
            bool charAlreadyExist = false;
            for(int l = 0; l < charachters.size(); l++)
           {
                if(charachters.at(l) == str.at(i))
                {
                   charAlreadyExist = true;
                   break;
                }
            }
            if (charAlreadyExist == false)
            {
              for(int j = 0; j < str.size(); j++)
              {
                  if (str.at(i) == str.at(j))
                  {
                    count++;
                  }
              }
              charachters.push_back(str.at(i));
              length.push_back(count);
              if (!is_small_letter(str.at(i)))
              {
                  throw runtime_error("invalid input");
              }
            }
        }
     }

    so now when you type in abababab, it will print the correct amount of a's and b's even though they are not next to each other.

    next thing for you to do is what to do if user enters "abab ababab". i will leave that to you to figure out . hint.. cin<< will not work for getting multple words in a line from users.