How can I reverse a series of numbers as quickly as possible? - vector

I am trying to solve a question called 'smurf' on codebreaker.xyz, but my code is too slow. The task is to take in a series of numbers, one at a time, and reverse the array each time.
So for this input:
6
0 1 2 1 2 0
it should give the output 0 1 1 0 2 2.
The logic is correct and the code works, but how can I make it execute under 1 second for s <= 200,000...
This is the code in C++17:
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
#define int unsigned int
vector<int> S;
int s, t;
int32_t main(){
ios_base :: sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> s;
for(int i = 0; i < s; i++){
cin >> t;
S.push_back(t);
reverse(S.begin(), S.end());
}
for(int j = 0; j < s; j++){
cout << S[j] << " ";
}
}

As I understand your question, you need to reverse your container every time you add a new element. We can omit that by just adding the new number to the back or the front of the container, depending on if the container should be "reversed" or not at the moment. Since adding elements to the front of a vector is quite costly I would suggest using a list instead. An example would look like this
#include <iostream>
#include <list>
#include <ranges> //c++20
int main() {
std::list<int> numbers{};
bool reversed = false;
int N;
std::cin >> N;
while (N>0) {
int inputNumber;
std::cin >> inputNumber;
if(reversed){
numbers.push_front(inputNumber);
}
else{
numbers.push_back(inputNumber);
}
reversed = not reversed;
--N;
}
if(reversed){
for(const int i : numbers | std::views::reverse){
std::cout << i << ' ';
}
}
else{
for(const int i : numbers){
std::cout << i << ' ';
}
}
}

Related

How to change this pass by reference into pointer as function parameter

wanting to ask how to change this pass by reference into pass by pointer, cause some of my school works need pass by pointer and i doesn't really understand how to modified this code using pass by pointer
void convert(string &s){
for (int i =0; i<s.length(); i++){
s[i] = toupper(s[i]);
}
}
int main(){
string name;
cout<<"Enter your name"<<endl;
getline(cin,name);
convert(name);
cout<<name<<endl;
return 0;
}
First of all, there are some minor errors in the code.
Inlcude necessary headers.
Use std:: namespace prefix.
#include <iostream>
#include <string>
#include <cctype>
void convert(std::string &s){
for (int i =0; i < s.length(); i++){
s[i] = std::toupper(s[i]);
}
}
int main(){
std::string name;
std::cout << "Enter your name: ";
std::getline(std::cin, name);
convert(name);
std::cout << name << std::endl;
return 0;
}
Using pointer version?
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define SIZE 100
void convert(char *s, size_t size){
for (int i =0; i < size; i++){
s[i] = std::toupper(s[i]);
}
}
int main(){
char name[SIZE];
std::cout << "Enter your name: ";
std::fgets(name, SIZE, stdin);
convert(name, strlen(name));
std::cout << name << std::endl;
return 0;
}
Another version using pointers
#include <iostream>
#include <string>
#include <cctype>
void convert(std::string *s){
for (int i =0; i < s -> length(); i++){
(*s)[i] = std::toupper((*s)[i]);
}
}
int main(){
std::string *name = new std::string();
std::cout << "Enter your name: ";
std::getline(std::cin, *name);
convert(name);
std::cout << *name << std::endl;
delete name;
return 0;
}

parallelize for loop using boost MPI

I am learning to use Boost.MPI to parallelize the large amount of computation, here below is just my simple test see if I can get MPI logic correctly. However, I did not get it to work. I used world.size()=10, there are total 50 elements in data array, each process will do 5 iteration. I would hope to update data array by having each process sending the updated data array to root process, and then the root process receives the updated data array then print out. But I only get a few elements updated.
Thanks for helping me.
#include <boost/mpi.hpp>
#include <iostream>
#include <cstdlib>
namespace mpi = boost::mpi;
using namespace std;
#define max_rows 100
int data[max_rows];
int modifyArr(const int index, const int arr[]) {
return arr[index]*2+1;
}
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
int num_rows = 50;
int my_number;
if (world.rank() == 0) {
for ( int i = 0; i < num_rows; i++)
data[i] = i + 1;
}
broadcast(world, data, 0);
for (int i = world.rank(); i < num_rows; i += world.size()) {
my_number = modifyArr(i, data);
data[i] = my_number;
world.send(0, 1, data);
//cout << "i=" << i << " my_number=" << my_number << endl;
if (world.rank() == 0)
for (int j = 1; j < world.size(); j++)
mpi::status s = world.recv(boost::mpi::any_source, 1, data);
}
if (world.rank() == 0) {
for ( int i = 0; i < num_rows; i++)
cout << "i=" << i << " results = " << data[i] << endl;
}
return 0;
}
Your problem is probably here:
mpi::status s = world.recv(boost::mpi::any_source, 1, data);
This is the only way data can get back to the master node.
However, you do not tell the master node where in data to store the answers it is getting. Since data is the address of the array, everything should get stored in the zeroth element.
Interleaving which elements of the array you are processing on each node is a pretty bad idea. You should assign blocks of the array to each node so that you can send entire chunks of the array at once. That will reduce communication overhead significantly.
Also, if your issue is simply speeding up for loops, you should consider OpenMP, which can do things like this:
#pragma omp parallel for
for(int i=0;i<100;i++)
data[i]*=4;
Bam! I just split that for loop up between all of my processes with no further work needed.

Base case condition in quick sort algorithm

For the quick sort algorithm(recursive), every time when it calls itself, it have the condition if(p < r). Please correct me if I am wrong: as far as I know, for every recursive algorithm, it has a condition as the time when it entered the routine, and this condition is used to get the base case. But I still cannot understand how to correctly set and test this condition ?
void quickSort(int* arr, int p, int r)
{
if(p < r)
{
int q = partition(arr,p,r);
quickSort(arr,p,q-1);
quickSort(arr,q+1,r);
}
}
For my entire code, please refer to the following:
/*
filename : main.c
description: quickSort algorithm
*/
#include<iostream>
using namespace std;
void exchange(int* val1, int* val2)
{
int temp = *val1;
*val1 = *val2;
*val2 = temp;
}
int partition(int* arr, int p, int r)
{
int x = arr[r];
int j = p;
int i = j-1;
while(j<=r-1)
{
if(arr[j] <= x)
{
i++;
// exchange arr[r] with arr[j]
exchange(&arr[i],&arr[j]);
}
j++;
}
exchange(&arr[i+1],&arr[r]);
return i+1;
}
void quickSort(int* arr, int p, int r)
{
if(p < r)
{
int q = partition(arr,p,r);
quickSort(arr,p,q-1);
quickSort(arr,q+1,r);
}
}
// driver program to test the quick sort algorithm
int main(int argc, const char* argv[])
{
int arr1[] = {13,19,9,5,12,8,7,4,21,2,6,11};
cout <<"The original array is: ";
for(int i=0; i<12; i++)
{
cout << arr1[i] << " ";
}
cout << "\n";
quickSort(arr1,0,11);
//print out the sorted array
cout <<"The sorted array is: ";
for(int i=0; i<12; i++)
{
cout << arr1[i] << " ";
}
cout << "\n";
cin.get();
return 0;
}
Your question is not quite clear, but I will try to answer.
Quicksort works by sorting smaller and smaller arrays. The base case is an array with less than 2 elements because no sorting would be required.
At each step it finds a partition value and makes it true that all the values to the left of the partition value are smaller and all values to the right of the partition value are larger. In other words, it puts the partition value in the correct place. Then it recursively sorts the array to the left of the partition and the array to right of the partition.
The base case of quicksort is an array with one element because a one element array requires no sorting. In your code, p is the index of the first element and r is the index of the last element. The predicate p < r is only true for an array of at least size 2. In other words, if p >= r then you have an array of size 1 (or zero, or nonsense) and there is no work to do.

I am confused about topological sort

I am new to graph theory and I am new to topological sort. All I know is that, to topologically sort some tasks, I have to run dfs on it and then sort the vertices according to their finishing time. Well, I have tried it. But somehow I am getting wrong answer.
Suppose for a graph with 5 vertices and 4 edges, and the edges being, 1->2, 2->3, 1->3, 1->5, my code gives the answer "4 1 5 2 3" when it should give "1 4 2 5 3". Is there anything wrong with my code or is there anything wrong with my idea of topological sort?
Here is my code.
#include<iostream>
#include<vector>
#include<cstdio>
#include<stack>
#define MAX 100000
using namespace std;
vector<int> adj_list[MAX];
int f[MAX], d[MAX];//discovery time and finishing time
int color[MAX];
int time;
stack<int> stk;
void dfs(int vertex);
void dfs_visit(int u);
int main(void)
{
freopen("input.txt", "r", stdin);
int vertex, edge;
//I am creating the adjacency list
cin >> vertex >> edge;
for(int i=1; i<=edge; i++)
{
int n1, n2;
cin >> n1 >> n2;
adj_list[n1].push_back(n2);
}
//I am starting the depth-first-search
dfs(vertex);
return 0;
}
void dfs(int vertex)
{
//If it's 0 then it means white
for(int i=1; i<=vertex; i++)
if(color[i]==0) dfs_visit(i);
//Here I am printing the vertices
while(stk.size())
{
cout << stk.top() << " ";
stk.pop();
}
cout << endl;
return;
}
void dfs_visit(int u)
{
//If it's 1 then it means grey
color[u]=1;
d[u]=++time;
for(int i=0; i<adj_list[u].size(); i++)
{
int v=adj_list[u][i];
if(color[v]==0) dfs_visit(v);
}
//If it's 2 then it means black
color[u]=2;
f[u]=++time;
//I am inserting the vertex in the stack when I am finished, searching it
stk.push(u);
}

Runtime allocation of multidimensional array

So far I thought that the following syntax was invalid,
int B[ydim][xdim];
But today I tried and it worked! I ran it many times to make sure it did not work by chance, even valgrind didn't report any segfault or memory leak!! I am very surprised. Is it a new feature introduced in g++? I always have used 1D arrays to store matrices by indexing them with correct strides as done with A in the program below. But this new method, as with B, is so simple and elegant that I have always wanted. Is it really safe to use? See the sample program.
PS. I am compiling it with g++-4.4.3, if that matters.
#include <cstdlib>
#include <iostream>
int test(int ydim, int xdim) {
// Allocate 1D array
int *A = new int[xdim*ydim](); // with C++ new operator
// int *A = (int *) malloc(xdim*ydim * sizeof(int)); // or with C style malloc
if (A == NULL)
return EXIT_FAILURE;
// Declare a 2D array of variable size
int B[ydim][xdim];
// populate matrices A and B
for(int y = 0; y < ydim; y++) {
for(int x = 0; x < xdim; x++) {
A[y*xdim + x] = y*xdim + x;
B[y][x] = y*xdim + x;
}
}
// read out matrix A
for(int y = 0; y < ydim; y++) {
for(int x = 0; x < xdim; x++)
std::cout << A[y*xdim + x] << " ";
std::cout << std::endl;
}
std::cout << std::endl;
// read out matrix B
for(int y = 0; y < ydim; y++) {
for(int x = 0; x < xdim; x++)
std::cout << B[y][x] << " ";
std::cout << std::endl;
}
delete []A;
// free(A); // or in C style
return EXIT_SUCCESS;
}
int main() {
return test(5, 8);
}
int b[ydim][xdim] is declaring a 2-d array on the stack. new, on the other hand, allocates the array on the heap.
For any non-trivial array size, it's almost certainly better to have it on the heap, lest you run yourself out of stack space, or if you want to pass the array back to something outside the current scope.
This is a C99 'variable length array' or VLA. If they are supported by g++ too, then I believe it is an extension of the C++ standard.
Nice, aren't they?

Resources