An in-place algorithm for String Transformation in C++



For a given string, transfer all even positioned elements to end of string. While transferring elements, keep the relative order of all even positioned and odd positioned elements same.

For example, if the given string is "a1b2c3d4e5f6g7h8i9j1k2l3m4”, transform it to “abcdefghijklm1234567891234” in-place and in O(n) time complexity.

Following are the steps

  • Cut out the highest prefix sub-string of size of the form 3^k + 1. In this step, we locate the highest non-negative integer k such that 3^k+1 is less than or equal to n (length of string)

  • Implement cycle leader iteration algorithm ( it has been explained below ), starting with index 1, 3, 9…… to this sub-string. Cycle leader iteration algorithm transfers all the items of this sub-string to their correct positions, that means, all the alphabets are moved to the left half of the sub-string and all the digits are moved to the right half of this sub-string.

  • Process the remaining sub-string recursively implementing steps no. 1 and no. 2.

  • At present, we only required to join the processed sub-strings together. Start from any end (say from left), select two sub-strings and implement the following steps −

    • Just opposite or reverse the second half of first sub- string.

    • Just opposite or reverse the first half of second sub-string.

    • Just opposite or reverse the second half of first sub-string and first half of second sub-string together.

  • Repeat step no. 4 until and unless all sub-strings are joined. It is same as k-way merging where first sub-string is joined with second. The resultant is merged with third and so on.

The code is given below based on above algorithm −

// C++ application of above approach
#include <bits/stdc++.h>
using namespace std;
// A utility function to swap characters void swap ( char* a1, char* b1 ) {
   char t = *a1; *a1 = *b1; *b1 = t;
}
// A utility function to reverse string str1[low1..high1]
void reverse ( char* str1, int low1, int high1 ) {
   while ( low < high ) {
      swap(&str1[low1], &str1[high1] ); ++low1; --high1;
   }
}
// Cycle leader algorithm to shift all even
// positioned elements at the end.
void cycleLeader ( char* str1, int shift1, int len1 ) {
   int j;
   char item1;
   for (int i = 1; i < len1; i *= 3 ) {
      j = i; item1 = str1[j + shift1];
      do{
         // odd index if ( j & 1 )
         j = len1 / 2 + j / 2;
         // even index or position else j /= 2;
         // keep the back-up of element at new index or position
         swap (&str1[j + shift1], &item1);
      }
   while ( j != i );
   }
}
// The main function to convert a string. This function
// mainly implements cycleLeader() to convert void moveNumberToSecondHalf( char* str1 ) {
   int k, lenFirst1; int lenRemaining1 = strlen( str1); int shift1 = 0;
   while ( lenRemaining1) {
      k = 0;
      // Step 1: Find the highest prefix
      // subarray of the form 3^k + 1
      while ( pow( 3, k ) + 1 <= lenRemaining1)
      k++; lenFirst1 = pow( 3, k - 1 ) + 1;
      lenRemaining1 -= lenFirst1;
      // Step 2: Implement cycle leader algorithm
      // for the highest subarray cycleLeader ( str1, shift1, lenFirst1 );
      // Step 4.1: Just opposite or reverse the second half of first subarray reverse ( str1,
         shift1/2, shift1 - 1 );
      // Step 4.2: Just opposite or reverse the first half of second sub-string. reverse ( str1,
         shift1, shift1 + lenFirst1 / 2 - 1 );
      // Step 4.3 Just opposite or reverse the second half of first sub-string and first half of
         second sub-string together reverse ( str1, shift1 / 2, shift1 + lenFirst1 / 2 - 1 );
      // Now increase the length of first subarray Shift1 += lenFirst1;
  }
}
// Driver program to verify or test above function int main() {
   char str1[] = "a1b2c3d4e5f6g7"; moveNumberToSecondHalf( str1 ); cout<<str1; return 0;
}

Output

abcdefg1234567

Advertisements