Print heap array in tree format - c++

So I've been trying to implement an algorithm to output a heap array in tree format. For
instance if I have an array like A[10,6,8,2,4,3,6,0,1,3,2,2,1,0,2] I would like the output to be:
10-----6-----2-----0
| | |--1
| |--4-----3
| |--2
|--8-----3-----2
| |--1
|--6-----0
|--2
Update: Solved my question, I made an answer with the code for those interested.

A possible solution is to insert placeholders into the array and thus form a MxN matrix out if it. Then you can simply loop over it, insert a line feed after every row and indent cells having a placeholder.

This C++11 program outputs heap in a little bit different format:
// 10
// ||--------------||
// 6 8
// ||------|| ||------||
// 2 4 3 6
//||--|| ||--|| ||--|| ||--||
// 0 1 3 2 2 1 0 2
#include<iostream>
#include<vector>
#include<sstream>
#include<string>
#include<cmath>
#include<iomanip>
// http://stackoverflow.com/questions/994593/how-to-do-an-integer-log2-in-c
// will be used to compute height of the heap
size_t IntegerLogarithm2(size_t arg) {
size_t logarithm = 0;
while (arg >>= 1) ++logarithm;
return logarithm;
}
// will be used to compute number of elements at the level i
size_t IntegerPower2(size_t arg) {
if(arg)
return (size_t)2 << (arg-1);
else
return 1;
}
// returns total line length for the level
size_t LineLength(size_t level, size_t item_width, size_t spaces_between) {
return IntegerPower2(level) * (item_width + spaces_between) - spaces_between;
}
int main()
{
// The input heap array
std::vector<int> A = {10, 6, 8, 2, 4, 3, 6, 0, 1, 3, 2, 2, 1, 0, 2};
// The heap array split by levels
std::vector<std::vector<int> > levels;
// Height of the heap
size_t levels_number = IntegerLogarithm2(A.size() + 1);
levels.resize(levels_number);
// Now fill the levels
for (size_t i = 0; i < levels.size(); ++i) {
size_t elements_number = IntegerPower2(i);
levels[i].resize(elements_number);
for (size_t j = elements_number - 1, p = 0; p < elements_number; ++j, ++p)
levels[i][p] = A[j];
}
if (levels_number < 1) return 0;
int magnitude = (abs(A[0]) <= 1 ? 1 : abs(A[0]));
size_t tab_width = (size_t)floor(log(double(magnitude)) / log(10.0)) + 1;
// size_t longest_line = LineLength(levels_number - 1, tab_width, tab_width);
std::vector<std::string> text;
text.reserve(levels_number * 2 - 1);
// Do the aligned output to the strings array
for (size_t i = 0; i < levels_number; ++i) {
size_t outer_space_width = IntegerPower2(levels_number - 1 - i) - 1;
size_t inner_space_width = outer_space_width * 2 + 1;
std::string outer_space(outer_space_width * tab_width, ' ');
std::string inner_space(inner_space_width * tab_width, ' ');
std::ostringstream line;
line << outer_space;
if (i > 0) {
std::ostringstream branchline;
std::string joint(tab_width, '|');
std::string branch(inner_space_width * tab_width, '-');
branchline << outer_space;
if (levels[i].size() > 0) {
branchline << joint;
}
bool isline = true;
for (size_t j = 1; j < levels[i].size(); ++j, isline = !isline) {
if(isline)
branchline << branch << joint;
else
branchline << inner_space << std::setfill(' ') <<
std::setw(tab_width) << joint;
}
branchline << outer_space;
text.push_back(branchline.str());
}
if (levels[i].size() > 0) {
line << std::setfill(' ') << std::setw(tab_width) << levels[i][0];
}
for (size_t j = 1; j < levels[i].size(); ++j) {
line << inner_space << std::setfill(' ') <<
std::setw(tab_width) << levels[i][j];
}
line << outer_space;
text.push_back(line.str());
}
// Output the text
for (auto& i : text)
std::cout << i << std::endl;
return 0;
}
Yap, harder than it initially seemed. Effectively does what Sebastian Dressler proposed.

Here is the final implementation. Formatting scales with number length.
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
std::string do_padding (unsigned index, unsigned mlength){
std::string padding;
if (int((index-1)/2) != 0){
return (int((index-1)/2) % 2 == 0) ?
(do_padding(int((index-1)/2),mlength) + std::string(mlength+4,' ') + " ") :
(do_padding(int((index-1)/2),mlength) + std::string(mlength+3,' ') + " |") ;
}
return padding;
}
void printer (std::vector<int> const & tree, unsigned index, unsigned mlength){
auto last = tree.size() - 1 ;
auto left = 2 * index + 1 ;
auto right = 2 * index + 2 ;
std::cout << " " << tree[index] << " ";
if (left <= last){
auto llength = std::to_string(tree[left]).size();
std::cout << "---" << std::string(mlength - llength,'-');
printer(tree,left,mlength);
if (right <= last) {
auto rlength = std::to_string(tree[right]).size();
std::cout << "\n" << do_padding(right,mlength) << std::string(mlength+ 3,' ') << " | ";
std::cout << "\n" << do_padding(right,mlength) << std::string(mlength+ 3,' ') << " └" <<
std::string(mlength - rlength,'-');
printer(tree,right,mlength);
}
}
}
void print_tree (std::vector<int> & tree){
unsigned mlength = 0;
for (int & element : tree){
auto clength = std::to_string(element).size();
if (clength > mlength) {
mlength = std::to_string(element).size();
}
}
std::cout << std::string(mlength- std::to_string(tree[0]).size(),' ');
printer(tree,0,mlength);
}
int main() {
std::vector<int> test;
for(auto i =0; i<50; ++i){
test.push_back(rand() % 1000 + 1);
}
std::make_heap(test.begin(),test.end());
std::cout << "\n";
print_tree(test);
}

Related

How to build Perfect Hash in C++?

I'd like to know how to build a Perfect Hash in C++.
Perfect Hash is such a hash that 1) Has no collisions at all, 2) Is built only for fixed set of values, 3) Maps set of N values to a range of numbers of 0 .. N * 1.23 - 1, i.e. it maps not to numbers till N, but till some bigger multiple of N, like N * 1.23.
I've read this Wiki article about Perfect Hash.
And decided to post this short question only to send my own Answer.
So I don't provide any Minimal Reproducible Example, only because answer is fully contained.
Suppose we have set S of N integer elements. We want to perfect-hash this set.
There are different ways of building perfect hash. But one way, according to Wiki, is following way:
First we choose some function g(x) = k * x mod p mod n, where P is some quite large prime. And K is some random constant. N is number of elements in a set.
Then we map through g(x) all elements of a set, these elements map to some integers in a range 0..N-1 which may collide. Collided integers form separate buckets.
We create infinite amount of Hash functions. For example in my below C++ code I use same as g(x) functions equal to Hash[i](x) = RandomConstant[i] * x mod Prime[i] mod M, where M = N * 1.23, here 1.23 is some small constant, it can be something like 1.2-1.5.
Each bucket B_i is hashed separately in such a way that it forms set K_i = Hash[l](x) for x in B_i, so that l is minimal and |K_i| = |B_i|, and K_i doesn't intersect with any previous K_i. Each minimal found l is stored as sigma(i) = l.
sigma(i) is compressed into bit vector in such a way that we can get value l = sigma(i) in O(1) time. Using any compact bit packing technique like Gamma Coding or Unary Coding.
Finally, to get perfect hash of value x we do PerfectHash(x) = Hash[sigma(g(x))](x).
Full code below. It generates N random numbers, then perfect hashes them and finally outputs amount of bits per number.
Try it online!
#include <cstdint>
#include <bit>
#include <vector>
#include <random>
#include <cstring>
#include <stdexcept>
#include <string>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <unordered_map>
#include <array>
#define ASSERT_MSG(cond, msg) { if (!(cond)) throw std::runtime_error("Assertion (" #cond ") failed at line " + std::to_string(__LINE__) + "! Msg: '" + std::string(msg) + "'."); }
#define ASSERT(cond) ASSERT_MSG(cond, "")
#define DASSERT_MSG(cond, msg) ASSERT_MSG(cond, msg)
#define DASSERT(cond) DASSERT_MSG(cond, "")
using u8 = uint8_t;
using u32 = uint32_t;
using u64 = uint64_t;
template <typename T>
bool IsPrime(T const & n) {
if (n % 2 == 0)
return false;
for (size_t d = 3; d * d <= n; d += 2)
if (n % d == 0)
return false;
return true;
}
template <typename T>
T NextPrime(T const & i) {
if (i <= 2) return 2;
for (T j = i | 1;; j += 2)
if (IsPrime(j))
return j;
}
class BitVector {
static size_t constexpr index_block = 1 << 9;
public:
BitVector() {}
BitVector(size_t size) : size_(size), bits_((size_ + 7) / 8) {}
void Clear() {
size_ = 0;
bits_.clear();
index_.clear();
}
size_t Size() const { return size_; }
bool Get(size_t i) const {
return (bits_[i / 8] >> (i % 8)) & u8(1);
}
void Set(size_t i, bool val = true) {
if (val)
bits_[i / 8] |= u8(1) << (i % 8);
else
bits_[i / 8] &= ~(u8(1) << (i % 8));
}
void Push(bool val) {
++size_;
if (size_ - 1 >= bits_.size() * 8)
bits_.resize((size_ + 7) / 8);
Set(size_ - 1, val);
}
void Index() {
index_.clear();
for (size_t i = 0; i < size_; i += index_block) {
size_t sum = 0;
size_t const portion = std::min(index_block, size_ - i);
for (size_t k = i; k < i + portion; k += 64)
if (i + portion - k >= 64)
sum += std::popcount(*(u64*)&bits_[k / 8]);
else {
u64 x = 0;
std::memcpy(&x, &bits_[k / 8], bits_.size() - k / 8);
sum += std::popcount(x);
}
index_.push_back(index_.empty() ? sum : (index_.back() + sum));
}
}
size_t Select1(size_t idx) const {
size_t const d = std::distance(index_.data(), std::upper_bound(index_.data(), index_.data() + index_.size(), idx));
ASSERT_MSG(d < index_.size(), "idx " + std::to_string(idx));
size_t const prev_sum = d == 0 ? 0 : index_[d - 1], hi = std::min<size_t>(size_, index_block * (d + 1));
size_t csum = 0, i = 0;
u64 word = 0;
for (i = index_block * d; i < hi; i += 64) {
size_t const portion = std::min<size_t>(hi - i, 64);
size_t word_sum = 0;
if (portion == 64)
word = *(u64*)&bits_[i / 8];
else {
word = 0;
std::memcpy(&word, &bits_[i / 8], bits_.size() - i / 8);
}
word_sum = std::popcount(word);
if (prev_sum + csum + word_sum > idx)
break;
csum += word_sum;
}
size_t sum0 = 0;
while (true) {
size_t const i1 = std::countr_zero(word);
ASSERT(i1 < 64);
if (prev_sum + csum + sum0 >= idx) {
ASSERT(prev_sum + csum + sum0 == idx);
ASSERT(Get(i + i1));
return i + i1;
}
word &= word - 1;
++sum0;
}
}
std::string Dump() const {
std::string r;
for (size_t i = 0; i < size_; ++i)
r.append(1, Get(i) ? '1' : '0');
return r;
}
u64 Word(size_t i) const {
return (*(u64*)&bits_[i / 8]) >> (i % 8);
}
private:
size_t size_ = 0;
std::vector<u8> bits_;
std::vector<size_t> index_;
};
class GammaBitVector {
static size_t constexpr index_block = 1 << 7;
public:
template <typename T>
void GammaEncodeVec(std::vector<T> const & nums) {
for (auto n: nums) {
auto [x, b] = GammaEncode(std::max<size_t>(n, 1) - 1);
//std::cout << n << ": " << b << " " << x << std::endl;
for (size_t i = 0; i < b; ++i) {
bv_.Push(bool(x & 1));
x >>= 1;
}
}
//std::cout << "GammaEncodedVec " << bv_.Size() << std::endl;
//std::cout << bv_.Dump() << std::endl << std::endl;
}
void Index() {
size_t i = 0, cnt = 0;
while (i < bv_.Size()) {
auto const [n, ebits, dbits] = GammaDecode(bv_.Word(i));
++cnt;
i += ebits;
if (cnt < index_block && i < bv_.Size())
continue;
index_.push_back(i);
cnt = 0;
}
}
size_t Get(size_t i) const {
size_t j = i / index_block * index_block, sum = i / index_block > 0 ? index_.at(i / index_block - 1) : 0;
while (sum < bv_.Size()) {
auto const [n, ebits, dbits] = GammaDecode(bv_.Word(sum));
if (j >= i)
return n + 1;
++j;
sum += ebits;
}
ASSERT(false);
}
size_t Size() const { return bv_.Size(); }
size_t GetBitOffset(size_t i) const {
size_t j = i / index_block * index_block, sum = i / index_block > 0 ? index_.at(i / index_block - 1) : 0;
while (sum < bv_.Size()) {
auto const [n, ebits, dbits] = GammaDecode(bv_.Word(sum));
if (j >= i)
return sum;
++j;
sum += ebits;
}
ASSERT(false);
}
private:
static u64 Shl(u64 w, size_t cnt) {
return cnt >= 64 ? u64(0) : (w << cnt);
}
static u64 Shr(u64 w, size_t cnt) {
return cnt >= 64 ? u64(0) : (w >> cnt);
}
static u64 Mask(size_t n) {
return n >= 64 ? ~u64(0) : (u64(1) << n) - 1;
}
static size_t NumBits(u64 n) {
return 64 - std::countl_zero(n);
}
static std::tuple<u64, size_t> GammaEncode(u64 n) {
++n;
DASSERT(n != 0);
size_t const nbits = NumBits(n);
static auto lo = []{
std::array<u32, 32> r{};
for (size_t i = 0; i < r.size(); ++i)
r[i] = u32(1) << i;
return r;
}();
size_t const rnbits = nbits - 1;
DASSERT(rnbits < lo.size());
return std::make_tuple((Shl(n & Mask(rnbits), nbits) | u64(lo[rnbits])), rnbits + nbits);
}
static std::tuple<u64, size_t, size_t> GammaDecode(u64 n) {
static size_t constexpr c_tab_bits = 8;
static auto tab = []{
std::array<u8, (1 << c_tab_bits)> r{};
for (size_t i = 0; i < r.size(); ++i) {
size_t j = i, sr = 0;
if (i == 0)
sr = 0xFF;
else
while (!bool(j & 1)) {
++sr;
j >>= 1;
}
r[i] = u8(sr);
}
return r;
}();
size_t cnt = tab[n & Mask(c_tab_bits)];
if (cnt == 0xFF) {
ASSERT(n != 0);
cnt = 0;
u64 m = n;
while (!bool(m & 1)) {
++cnt;
m >>= 1;
}
ASSERT(cnt <= 31);
}
return std::make_tuple(u64((((n >> (cnt + 1)) & Mask(cnt)) | (u64(1) << cnt)) - 1), size_t(2 * cnt + 1), size_t(cnt + 1));
}
BitVector bv_;
std::vector<size_t> index_;
};
class PerfectHash {
public:
// https://en.wikipedia.org/wiki/Perfect_hash_function
void Build(std::vector<u64> const & nums) {
size_t const n = nums.size();
m_ = 1.5 * n;
n_ = n;
primes_.clear();
primes_.push_back({rng_(), NextPrime(n_)});
primes_.push_back({rng_(), NextPrime(m_)});
std::vector<std::vector<size_t>> Bs(n);
for (size_t i = 0; i < n; ++i) {
Bs[g(nums[i])].push_back(nums[i]);
//std::cout << "i " << i << ": " << nums[i] << ": " << g(nums[i]) << ", ";
}
//std::cout << std::endl;
std::vector<u64> K;
BitVector Tb(m_);
std::vector<u32> sigma_l(n);
size_t max_bucket_size = 0;
for (size_t i = 0; i < n; ++i) {
auto const & B = Bs.at(i);
max_bucket_size = std::max<size_t>(max_bucket_size, B.size());
if (B.empty())
continue;
size_t l = 0;
for (l = 1; l < 10'000; ++l) {
bool exists = false;
K.clear();
for (size_t iB = 0; iB < B.size(); ++iB) {
auto const j = B[iB];
auto const h = HashFunc(l, j);
if (Tb.Get(h)) {
exists = true;
break;
}
for (auto k: K)
if (k == h) {
exists = true;
break;
}
if (exists)
break;
K.push_back(h);
}
if (!exists)
break;
}
ASSERT(l < 10'000);
sigma_l[i] = l;
for (auto j: K)
Tb.Set(j);
}
sigma_bv_.Clear();
//std::cout << "MaxBucket " << max_bucket_size << std::endl;
//std::cout << "Sigma: ";
for (size_t i = 0; i < sigma_l.size(); ++i) {
auto const l = sigma_l[i];
//std::cout << l << ", ";
sigma_bv_.Push(1);
for (size_t i = 0; i + 1 < l; ++i)
sigma_bv_.Push(0);
}
//std::cout << std::endl;
sigma_gbv_.GammaEncodeVec(sigma_l);
sigma_gbv_.Index();
//std::cout << "Sigma from GBV: ";
for (size_t i = 0; i < sigma_l.size(); ++i) {
//std::cout << sigma_gbv_.Get(i) << ", ";
ASSERT_MSG(std::max<size_t>(1, sigma_l[i]) == sigma_gbv_.Get(i), "i " + std::to_string(i) + " sigma_l " + std::to_string(std::max<size_t>(1, sigma_l[i])) + " sigma_Get(i) " + std::to_string(sigma_gbv_.Get(i)) + " sigma_GetOff(i) " + std::to_string(sigma_gbv_.GetBitOffset(i)) + " sigma_GetOff(i - 1) " + std::to_string(sigma_gbv_.GetBitOffset(i - 1)));
}
//std::cout << std::endl;
sigma_bv_.Index();
for (size_t i = 0; i < sigma_bv_.Size(); ++i) {
//std::cout << (sigma_bv_.Get(i) ? "1" : "0");
}
//std::cout << std::endl;
}
size_t Hash(u64 const & x) {
return HashFunc(Sigma(g(x)), x);
}
size_t NumBits() const {
return sigma_gbv_.Size();
}
size_t HashFunc(size_t i, u64 const & x) {
while (i >= primes_.size())
primes_.push_back({rng_(), NextPrime(primes_.back().second + 1)});
auto const [k, p] = primes_[i];
auto v = (k * x) % p;
size_t const mod = i == 0 ? n_ : m_;
while (v >= mod)
v -= mod;
return v;
}
size_t g(u64 const & x) {
return HashFunc(0, x);
}
size_t Sigma(size_t i) {
size_t const i1 = sigma_gbv_.Get(i);
//std::cout << "Sigma: " << i << ": " << i1 << std::endl;
return i1;
/*
size_t cnt = 0;
for (size_t i = i1 + 1, size = sigma_bv_.Size(); i < size; ++i, ++cnt) {
std::cout << i << " (" << std::boolalpha << sigma_bv_.Get(i) << "), ";
if (sigma_bv_.Get(i))
break;
}
std::cout << std::endl << "Val: " << (cnt + 1) << std::endl;
return cnt + 1;
*/
}
size_t N() const { return n_; }
size_t M() const { return m_; }
private:
std::mt19937_64 rng_{123};
size_t n_ = 0, m_ = 0;
BitVector sigma_bv_;
GammaBitVector sigma_gbv_;
std::vector<std::pair<u64, u64>> primes_;
};
int main() {
try {
std::mt19937_64 rng{123};
std::vector<u64> nums(1 << 17);
for (size_t i = 0; i < nums.size(); ++i)
nums[i] = rng();
PerfectHash ph;
ph.Build(nums);
std::cout << "Nums " << nums.size() << std::endl;
std::cout << "PerfectHash Bits " << ph.NumBits() << ", " << std::setprecision(3)
<< (double(ph.NumBits()) / nums.size()) << " bits/num" << std::endl;
std::unordered_map<u64, u64> hashes;
for (size_t i = 0; i < nums.size(); ++i) {
//std::cout << "i " << i << std::endl;
auto const hash = ph.Hash(nums[i]);
if (i < 16) {
//std::cout << nums[i] << ": " << hash << std::endl;
}
ASSERT(hash < ph.M());
ASSERT_MSG(!hashes.count(hash),
"i " + std::to_string(i) + " nums[i] " + std::to_string(nums[i]) +
" hash " + std::to_string(hash) + " g(x) " + std::to_string(ph.g(nums[i])) +
" sigma " + std::to_string(ph.Sigma(ph.g(nums[i]))) +
" hash_func " + std::to_string(ph.HashFunc(ph.Sigma(ph.g(nums[i])), nums[i])) +
" prev_i " + std::to_string(hashes.at(hash)) + " nums[hashes.at(hash)] " +
std::to_string(nums[hashes.at(hash)]) + " prev_g(x) " +
std::to_string(ph.g(nums[hashes.at(hash)])) + " prev_sigma " +
std::to_string(ph.Sigma(ph.g(nums[hashes.at(hash)]))) + " prev_hash_func " +
std::to_string(ph.HashFunc(ph.Sigma(ph.g(nums[hashes.at(hash)])), nums[hashes.at(hash)]))
);
hashes[hash] = i;
}
ASSERT(hashes.size() == nums.size());
return 0;
} catch (std::exception const & ex) {
std::cout << "Exception: " << ex.what() << std::endl;
return -1;
}
}
Console Output:
Nums 131072
PerfectHash Bits 244430, 1.86 bits/num

How to print and modify char in C++

I want to create a project that will print the '|' character as 4 layers going 1 3 5 7 something like
|
|||
|||||
|||||||
I wrote a for loop for this and the code is here:
for (int i = 1; i <= 4; i++) {
//for loop for displaying space
for (int s = i; s < 4; s++) {
cout << " ";
}
//for loop to display star equal to row number
for (int j = 1; j <= (2 * i - 1); j++) {
cout << "|";
}
// ending line after each row
cout << "\n";
}
So how can I make a code that will take user input like
cout << "Please enter a row number \n" << "Please enter a column number" << endl;
and let say the user entered 2 as row number 2 as column number I want the output to be something like
|
|
|||||
|||||||
Deletes 2 '|' character from the 2nd row
First I think putting every character in a array like char arr[] = { '|' , '||' , '|||', '||||'}
and deleting according to user input but I failed. Any help?
Here is a solution:
#include <iostream>
#include <vector>
std::size_t getLayerCount( )
{
std::cout << "How many layers to print: ";
std::size_t layerCount { };
std::cin >> layerCount;
return layerCount;
}
std::vector< std::vector<char> > generateShape( const std::size_t layerCount )
{
const std::size_t MAX_CHAR_COUNT_IN_A_ROW { layerCount * 2 };
constexpr char spaceChar { ' ' };
std::vector< std::vector<char> > shape( layerCount, std::vector<char>( MAX_CHAR_COUNT_IN_A_ROW, spaceChar ) );
for ( std::size_t row { }; row < layerCount; ++row )
{
for ( std::size_t offset { layerCount - row - 1 }; offset < layerCount + row; ++offset )
{
shape[ row ][ offset ] = '|';
}
shape[ row ][ MAX_CHAR_COUNT_IN_A_ROW - 1 ] = '\0';
}
return shape;
}
void printShape( const std::vector< std::vector<char> >& shape )
{
for ( const auto& row : shape )
{
std::cout.write( row.data( ), row.size( ) ).write( "\n", 1 );
}
}
void deleteSpecificChars( std::vector< std::vector<char> >& shape )
{
std::cout << "Please enter a row number: ";
std::size_t rowNumber { };
std::cin >> rowNumber;
std::cout << "Please enter a column number: ";
std::size_t colNumber { };
std::cin >> colNumber;
--rowNumber;
--colNumber;
const std::size_t layerCount { shape.size( ) };
const std::size_t posOfFirstCharInRow { layerCount - rowNumber - 1 };
const std::size_t posOfTargetCharInRow { posOfFirstCharInRow + colNumber };
const std::size_t posOfLastCharInRow { posOfFirstCharInRow + ( 2 * rowNumber ) };
for ( std::size_t idx { posOfTargetCharInRow }; idx <= posOfLastCharInRow; ++idx )
{
shape[ rowNumber ][ idx ] = ' ';
}
}
int main( )
{
const std::size_t layerCount { getLayerCount( ) };
std::vector< std::vector<char> > shape { generateShape( layerCount ) };
printShape( shape );
deleteSpecificChars( shape );
printShape( shape );
return 0;
}
Sample input/output:
How many layers to print: 4
|
|||
|||||
|||||||
Please enter a row number: 2
Please enter a column number: 2
|
|
|||||
|||||||
Another one:
How many layers to print: 5
|
|||
|||||
|||||||
|||||||||
Please enter a row number: 4
Please enter a column number: 4
|
|||
|||||
|||
|||||||||
Limiting your pile of bars to 4 levels, this should work:
You basically just want a fixed size string of bars, '|'.
Then remove n consecutive characters from that string.
The only thing you have to calculate is the starting index to start removing from, then replace n characters with blanks.
You can add some checks for row and col boundaries.
[Demo]
#include <iostream> // cout
#include <string>
int main()
{
std::string bars(16, '|');
auto get_start_deleting_pos = [](int row, int col) {
if (row == 1) { if (col > 1) { return -1; } return 0; }
else if (row == 2) { if (col > 3) { return -1; } return col; }
else if (row == 3) { if (col > 5) { return -1; } return 3 + col; }
else if (row == 4) { if (col > 7) { return -1; } return 8 + col; }
else return -1;
};
auto print_bars = [&bars]() {
std::cout << " " << bars[0] << "\n";
std::cout << " " << bars.substr(1, 3) << "\n";
std::cout << " " << bars.substr(4, 5) << "\n";
std::cout << bars.substr(9) << "\n";
};
auto start_deleting_from_row{4};
auto start_deleting_from_col{1};
auto num_chars_to_delete{4};
auto pos{ get_start_deleting_pos(start_deleting_from_row, start_deleting_from_col) };
if (pos != -1)
{
bars.replace(pos, num_chars_to_delete, num_chars_to_delete, ' ');
}
print_bars();
}
And if you want a more generic solution, where the user inputs the level, the row and col to start deleting from, and the number of characters to delete:
[Demo]
#include <iostream> // cout
#include <string>
auto get_size_for_levels(int l) { return l*l; }
auto get_index_for_row_and_col(int row, int col) { return (row - 1) * (row - 1) - 1 + col; }
auto get_num_cols_for_row (int row) { return row * 2 - 1; }
auto check_row_and_col(int levels, int row, int col) {
if (row < 1 or levels < row) { return false; }
if (col < 1 or get_num_cols_for_row(row) < col) { return false; }
return true;
}
int main()
{
auto levels{7}; // levels start at 1
auto start_deleting_from_row{4}; // rows start at 1
auto start_deleting_from_col{5}; // cols start at 1
auto num_chars_to_delete{6};
std::string bars(get_size_for_levels(levels), '|');
if (check_row_and_col(levels, start_deleting_from_row, start_deleting_from_col))
{
bars.replace(
get_index_for_row_and_col(start_deleting_from_row, start_deleting_from_col),
num_chars_to_delete,
num_chars_to_delete,
' ');
}
for (int l{1}; l <= levels; ++l)
{
std::cout
<< std::string(levels - l, ' ')
<< bars.substr(get_index_for_row_and_col(l, 1), get_num_cols_for_row(l))
<< "\n";
}
}

Program containing threading in cpp is not executed completely

Code given below is not executed completely;
I have looked for everything on web but I don't know why it is working for starting numbers from nums (i.e. 1000 and sometimes 5000) and after that it starts execution but in between program terminates itself and stopes working.
#include <bits/stdc++.h>
// #include <iostream>
// #include <chrono>
// #include <vector>
#define UPPER_LIMIT 10
using namespace std;
using namespace std::chrono;
bool inTimeLimit = true;
bool isFinished = false;
bool isRunning = true;
class Timer {
public:
time_point<high_resolution_clock> start, end;
Timer() {
start = high_resolution_clock::now();
}
~Timer() {
end = high_resolution_clock::now();
auto durationTime = durationCounter();
cout << "\n\nTaken time Duration " << (unsigned long long)durationTime << " us; " << (unsigned long long)durationTime * 0.001 << "ms.";
}
float durationCounter() {
auto currTime = high_resolution_clock::now();
auto durationTime = duration_cast<microseconds>(currTime - start);
return durationTime.count();
}
};
void printVector(vector <int> v) {
cout << endl;
for (int x : v) {
cout << setw(3) << x << " ";
}
}
void printVectorToFile(ofstream &fout , vector <int> v, string msg) {
fout << "\n\n===================\n\n";
fout << msg << endl;
fout << endl;
for (int x : v) {
fout << setw(5) << x << " ";
}
fout << endl;
}
void swap (int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
vector <int> randomArrayGenerator(int n) {
vector<int> v(n);
for (int i = 0; i < n; ++i)
v[i] = i + 1;
srand(time(0));
for (int i = 0; i < n; ++i)
{
int pos = rand() % n;
swap(&v[i], &v[pos]);
}
return v;
}
string sortingChecker(vector<int> v) {
for (int i = 0; i < (int)v.size() - 1; ++i)
{
if (v[i] > v[i + 1]) return "false";
}
return "true";
}
bool sortChecker(vector<int> v) {
for (int i = 0; i < (int)v.size() - 1; ++i)
{
if (v[i] > v[i + 1]) return false;
}
return true;
}
// Merge function
void merge(vector <int> &v, int begin, int middle, int end) {
vector <int> left, right;
for (int i = begin; i < middle + 1; ++i)
{
left.push_back(v[i]);
}
for (int i = middle + 1; i <= end; ++i)
{
right.push_back(v[i]);
}
int p1 = 0, p2 = 0, n1 = left.size(), n2 = right.size(), p = begin;
while ((p1 < n1 ) || (p2 < n2)) {
if ((p1 != n1 ) && ((p2 == n2) || left[p1] < right[p2]))
v[p++] = left[p1++];
else
v[p++] = right[p2++];
}
}
void mergeSortByIteration(vector <int> &v, bool &isTimeDelayed) {
int low = 0, high = v.size();
cout << "Thread ID: " << this_thread::get_id() << endl;
// n :for taking individual block of vector containing number of elements n=[1,2,4,8,..]
for (int n = 1; n < high; n *= 2) {
if (isTimeDelayed) return;
// taking block according to n and then sorting them by merge function
// n=1 => i=0,2,4,8,16
// n=2 => i=0,4,8
for (int i = 0; i < high; i += 2 * n) {
if (isTimeDelayed) return;
int begin = i;
int mid = i + n - 1;
int end = min(i + 2 * n - 1 , high - 1);
merge(v, begin, mid, end);
}
}
}
// Merge by recurision
void mergeSortByRecursion (vector <int> &v, int begin, int end, bool &isTimeDelayed) {
if (end <= begin || isTimeDelayed) return;
int middle = begin + (end - begin) / 2;
mergeSortByRecursion(v, begin, middle, isTimeDelayed);
mergeSortByRecursion(v, middle + 1, end, isTimeDelayed);
merge(v, begin, middle, end);
}
int main() {
int nums[] = {1000, 5000, 10000, 50000, 100000};
// int nums[] = {50000};
ofstream vectorOutput ;
vectorOutput.open("outputTexts\\prac1_resultedArrays.txt", ios::trunc);;
for (int n : nums)
// ``````` Merge by Iteration ````````
{
vector<int> num, arr = randomArrayGenerator(n);
cout << "\n=======";
cout << "\n\nMerge by Iteration:" << endl;
num = arr;
cout << "Array size: " << num.size() << endl;
bool isTimeOut = false, isSorted = false;
Timer timer;
std::thread worker(mergeSortByIteration, ref(num), ref(isTimeOut));
// mergeSortByIteration(num, isTimeOut);
// std::thread worker(mergeSortByRecursion, ref(num), 0, n - 1, ref(isTimeOut));
while ( ( ( timer.durationCounter() / 1000000 ) < 5) && (!isSorted ) ) {
// this_thread::sleep_for(seconds(1));
// cout << timer.durationCounter() << " ";
isSorted = sortChecker(num);
}
if ( ( ( ( timer.durationCounter() / 1000000 ) > 5) && (!isSorted ) ) )
{
isTimeOut = true;
cout << endl << "!!!!!Execution Terminated ---- Time Limit reached!!!!!!" << endl;
}
if (worker.joinable())
worker.join();
printVector(num);
cout << "\nCheck result for sorted Vector:" << (isSorted ? "true" : "false") << endl;
// printVectorToFile(vectorOutput, num, "Merge By Iteration for size:" + to_string(n) );
}
cout << "\n\ndone" << endl;
return 0;
}
can anyone help me out here?
If issue is not clear fill free to ask.

How to move elements in an array, putting odds to the beginning of the array (smallest to largest), and evens to the back ( largest to smallest )

I have to write a functioncalled moveAndSortInt() that will receive an array of integers as an argument, and move all the even values down to the second half of the array and sort them from largest to smallest, while all the odd values will be sorted from smallest to largest. How can I improve my code?
#include <iostream>
using namespace std;
void moveAndSortInt(int[], int);
void displayName();
int main() {
int ary1[] = { -19, 270, 76, -61, 54 };
int size = 5;
int i;
int ary2[] = {9, 8, -103, -73, 74, 53};
int size2 = 6;
int j;
displayName();
cout << endl;
cout << "Original ary1[]" << endl;
for (i = 0; i < size; i++) {
cout << " " << ary1[i] << " ";
}
cout << endl;
cout << "\nCallingMoveAndSortInt() --\n " << endl;
moveAndSortInt(ary1, size);
cout << "Updated ary1[]" << endl;
for (i = 0; i < size; i++) {
cout << " " << ary1[i] << " ";
}
cout << endl;
cout << "\nOriginal ary2[]" << endl;
for (j = 0; j < size2; j++) {
cout << " " << ary2[j] << " ";
}
cout << endl;
cout << "\nCallingMoveAndSortInt() --\n" << endl;
moveAndSortInt(ary2, size2);
cout << "Updated ary2[]" << endl;
for (j = 0; j < size2; j++) {
cout << " " << ary2[j] << " ";
}
}
void moveAndSortInt(int ary[], int size) {
int i, j;
int temp;
for (i = 0; i < 1 + size / 2; i++) {
if (ary[i] % 2 == 0) {
for (j = size - 1; j > size / 2; j--) {
if (ary[j] % 2 != 0) {
temp = ary[i];
ary[i] = ary[j];
ary[j] = temp;
j = 0;
}
}
}
}
return;
I would suggest using std::sort, the standard algorithm for sorting, which is often implemented with a Quicksort. It is very fast, and also supports custom comparison. Here's some code to get you started:
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> data = { 2, 213, 2, 2, 3 ,123, 4, 213, 2132, 123 };
std::sort(data.begin(), data.end(), [](int lhs, int rhs)
{
if (lhs % 2) // if lhs is odd
if (rhs % 2) // and rhs is odd then just use comparision
return lhs < rhs;
else // and if rhs is even then rhs is "bigger"
return false;
else // if lhs is even
if (rhs % 2)
return true; // and rhs is odd then lhs is "bigger"
else // and if they are both even just use comparision.
return lhs < rhs;
});
}
I'm sorry if that code is a little hard to read, but it does the trick.
This of course would work with C-style arrays too, just replace data.begin() with data and data.end() with data + size.
Alright, so I looked at it a bit. Let's start with conventions.
int i;
for (i = 1; i < 10; i++)
Can be shortened to:
for (int i = 1; i < 10; i++)
Which looks better and is more readable. It would also be nice to have a few more comments, but that's something everyone needs to get better at, no matter how good they are.
So it seems that your code does correctly sort the array into even and odd halves. That's all you need to do yourself as long as you know where they end because sorting them largest to smallest is something that std::sort can do for you.
Edit: It was pointed out to me that my previous example is not exactly the same, as with the second one i can only be used in the loop. For your purposes, they work the same.
You can just reorder it
#include <algorithm>
#include <climits>
#include <iostream>
#include <vector>
int main()
{
auto const shuffle = [] (int input)
{
if ( input % 2 )
{
unsigned const dist_from_min = (unsigned)input - INT_MIN;
return dist_from_min >> 1;
}
else
{
unsigned const dist_from_max = INT_MAX - (unsigned)input;
return INT_MIN + (dist_from_max >> 1);
}
};
auto const ordering = [shuffle] (int left, int right)
{ return shuffle (left) < shuffle (right); };
std::vector <int> data =
{ 5, 2, 3, 0, -1, -3, 1, 100
, INT_MIN, INT_MIN + 1, INT_MAX, INT_MAX - 1
, -567, -765, 765, 567, -234, -432, 234, 432
};
std::sort ( data.begin ( ), data.end ( ), ordering );
for ( auto item : data )
std::cout << item << "\n";
}

Split array into sub blocks

What I am trying to achieve is this:
I have an image and I need to split it into sub blocks of 16x16 and I am working on the algorithm for this. For testing purposes though, I am using a small matrix:
A = {1, 2, 3, 4}
Now what I want to end up is this: 2 blocks containing:
A[1] = {1 2};
A[2] = {3, 4};
I have tried to use the following:
double matrix[4] = {1, 2, 3, 4};
for(int i = 0; (i < 4); i++)
{
for(unsigned j=i; (j < 2); j +=2)
{
std::cout << j << ' ';
}
std::cout << std::endl;
}
My thought process was to loop through the entire array (4) and then increment by 2 each time to create the 1x2 block. This did not work however.
Where am I going wrong here?
Something like that? (Does both output and assignment)
int LEN = 4;
int INNER = 2;
int OUTER_LEN = LEN/INNER_LEN;
double matrix[LEN] = {1, 2, 3, 4};
double* matrix2[OUTER_LEN];
for(int i = 0; i < OUTER_LEN; i++)
{
matrix2[i] = &matrix[i*INNER_LEN];
for(unsigned j=0; j < INNER_LEN; j++)
{
std::cout << matrix[i*INNER_LEN+j] << ' ';
}
std::cout << std::endl;
}
Just for output you could do something like that:
#include <iostream>
int main(){
const size_t SIZE = 4;
const size_t PART_SIZE = 2;
double matrix[4] = {1, 2, 3, 4};
for(int i = 0; (i < SIZE); i += PART_SIZE)
{
for(size_t j = i; (j < i + PART_SIZE) && j < SIZE; j += 1)
{
std::cout << matrix[j] << ' ';
}
std::cout << std::endl;
}
}
To add another matrix:
#include <iostream>
int main(){
const size_t SIZE = 4;
const size_t PART_SIZE = 2;
size_t partsNumber = SIZE / PART_SIZE; // Beware of SIZE that is not divisible by PART_SIZE - partsNumber will be too small
double matrix[4] = { 1, 2, 3, 4 };
// To do it properly I should make it dynamic array with size of partsNumber instead of the 2 literals
double parts_matrix[2][PART_SIZE];
for (int i = 0; (i < SIZE); i += PART_SIZE) {
for (size_t j = i; (j < i + PART_SIZE) && j < SIZE; j += 1) {
std::cout << matrix[j] << ' ';
parts_matrix[j / partsNumber][j % PART_SIZE] = matrix[j];
}
std::cout << std::endl;
}
std::cout << parts_matrix[0][0] << " " << parts_matrix[0][1] << std::endl << parts_matrix[1][0] << " " << parts_matrix[1][1]; // Check if it works
}
The following is a demo of how to do the splitting for custom block size (rough cut though, corner cases and input verification are ommited) using boost range and the boost::slice functionality (here "output creation" is presented)
#include <iterator>
#include <iostream>
#include <boost/range/adaptor/sliced.hpp>
#include <boost/range/algorithm/copy.hpp>
using namespace std;
using namespace boost::adaptors;
template<typename T, size_t N>
void split(T (&input)[N], size_t block_size)
{
for (size_t i(0); i <= N-block_size; i += block_size)
{
cout << "{ ";
boost::copy(input | sliced(i, i+block_size),
std::ostream_iterator<int>(std::cout, " "));
cout << "}\n";
}
}
int main()
{
int A[] = {1, 2, 3, 4};
split(A, 2);
}
Demo
Output
{ 1 2 }
{ 3 4 }
What if I don't want to do output
To some the following may look more readable
template<typename T, size_t N>
void split(T (&input)[N], size_t block_size)
{
for (size_t i(0); i <= N-block_size; i += block_size)
{
cout << "{ ";
// do whatever with the i slice (again I'm showing output)
for (auto k : (input | sliced(i, i+block_size))) cout << k << " ";
cout << "}\n";
}
}