简体   繁体   中英

String reverse performance in C & C++ using swapping and recursion

I was practising my C & C++ skills and then I decided to do the string reverse problem in using method used in both languages. I wrote a recursive solution and and indexing method. There are 4 reverse functions here; 2 use strictly C methods to compute, and the other 2 use C++ (STL, String, algorithm) calls.

  • Is this a good comparison to see the speed of each method or am I missing something?
  • Also I want to find out how much memory each method uses but I have not figured out how to do that.
// C++ reverse string
#include <string> // string
#include <algorithm> // reverse
#include <iostream> // cout

#include <cstring> // std::strcpy
#include <stdio.h> // printf
#include <sys/time.h> // gettimeofday

inline void swap_characters(char* left, char* right) {
    char temp = *left;
    *left = *right;
    *right = temp;
}

void c_index_reverse(char* input, size_t inputSize) {

    const size_t strSize = inputSize - 1;
    char temp;

    for(int i=0 ; i < inputSize / 2 ; i++) {
        swap_characters(&input[i], &input[strSize - i]);
    }
}

void c_recursive_reverse(char str[], int index, int size)
{
    swap_characters(&str[index], &str[size - index]);

    if (index == size / 2)
        return;

    c_recursive_reverse(str, index + 1, size);
}


void c_plusplus_index_reverse(std::string& input) {

    const size_t strSize = input.length();

    for(int i=0 ; i < strSize / 2 ; i++)
        std::swap(input[i], input[strSize - i - 1]);
}


std::string c_plusplus_recursive_reverse(std::string& input) {

    if(input.length() <= 1) {
        return input;
    }

    std::string tmp = std::string(input.begin() + 1, input.end());
    return c_plusplus_recursive_reverse(tmp) + input[0];
}


double timeit(struct timeval &start, struct timeval &end){
    double delta = ((end.tv_sec - start.tv_sec) * 1000000u + end.tv_usec - start.tv_usec) / 1.e6;
    return delta;
}

int main() {

    struct timeval start,end;

    // using C++ STL
    std::string temp = "something very weird is another word that includes a longer text to see the delay" \
    "something very weird is another word that includes a longer text to see the delay" \
    "something very weird is another word that includes a longer text to see the delay" \
    "something very weird is another word that includes a longer text to see the delay" \ 
    "something very weird is another word that includes a longer text to see the delay" \
    "something very weird is another word that includes a longer text to see the delay" \
    "something very weird is another word that includes a longer text to see the delay";
    std::cout << temp << std::endl;

    // using c++ recursive reverse function - 4
    gettimeofday(&start, NULL);
    std::reverse(temp.begin(), temp.end());
    gettimeofday(&end, NULL);

    std::cout << temp << std::endl;
    printf("%lf \n",timeit(start, end));


    // use C++ style functions
    // using recersive - 5
    gettimeofday(&start, NULL);
    temp = c_plusplus_recursive_reverse(temp);
    gettimeofday(&end, NULL);
    std::cout << temp  << std::endl;
    printf("%lf \n",timeit(start, end));

    // using index reverse - 3
    gettimeofday(&start, NULL);
    c_plusplus_index_reverse(temp);
    gettimeofday(&end, NULL);
    std::cout << temp << std::endl;
    printf("%lf \n",timeit(start, end));



    // Now do C style
    char *cStr = new char[temp.length() + 1];
    std::strcpy(cStr, temp.c_str());


    // using index - 1
    gettimeofday(&start, NULL);
    c_index_reverse(cStr, temp.length());
    gettimeofday(&end, NULL);
    printf("%s \n", cStr);
    printf("%lf \n",timeit(start, end));


    // using recersive - 2
    gettimeofday(&start, NULL);
    c_recursive_reverse(cStr, 0, temp.length() - 1);
    gettimeofday(&end, NULL);
    printf("%s \n", cStr);
    printf("%lf \n",timeit(start, end));


    return 0;
}

Having an inline function swap_characters() is making a big job for only three lines of code, creating more pointers when you already have them (although compiler might optimise). Using another indexing var, say j , which is decremented until it meets i would be more efficient.

void c_index_reverse(char* input, size_t inputSize) {

    int j = inputSize - 1;
    char temp;

    for(int i=0; i<j; i++) {
        temp = input[i];
        input[i] = input[j];
        input[j--] = temp;
    }
}

"Also I want to find out how much memory each method uses" . The non-recursive method uses minimal memory, since it only uses pointers and indexers. But the recursive method uses a lot more memory, since every string character (up to half the string length) invokes recursion, so more stack usage. As your string "something very weird ..." has about 600 chars, that is a lot of stack usage, and most of the execution time is spent calling, manipulating stack frames, and returning, with very little time spent swapping chars.

Recursion here is a "hiding to nowhere".

The C++ recursive function is really bad: using iterators increases the speed and it's cleaner code:

void c_plusplus_recursive_reverse(std::string::iterator start, 
    std::string::iterator end) 
{
    if(start >= end) {
        return;
    }

    std::iter_swap(start, end);
    c_plusplus_recursive_swap_reverse(++start, --end);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM