Why redis command ‘LLEN’ has constant time complexity instead of O(n)? - algorithm

I know that redis list is implemented by linked list under the hood. However when calculating time complexity of length of the list, shouldn’t it be O(n)?

You can find the declaration of the list type at https://github.com/redis/redis/blob/unstable/src/adlist.h. If you look at the section around line 50 you find:
typedef struct list {
listNode *head;
listNode *tail;
void *(*dup)(void *ptr);
void (*free)(void *ptr);
int (*match)(void *ptr, void *key);
unsigned long len;
} list;
Note the unsigned long len that stores the length of the list. That is why it is O(1).

Related

Can I convert a non-const function argument to const and set the size of array?

Arrays require a constant to initialize the size. Hence, int iarr[10]
I thought I could possibly take a non-const argument and convert it to const then use it for an array size
int run(int const& size);
int run(int const& size)
{
const int csize = size;
constexpr int cesize = csize;
std::array<int, cesize> arr;
}
This, unfortunately doesn't work and I thought of using const_cast as
int run(int& size);
int run(int& size)
{
const int val = const_cast<int&>(size);
constexpr int cesize = val;
std::array<int, cesize> arr;
}
and this won't work either. I've read through a few SO posts to see if I can find anything
cannot-convert-argument-from-int-to-const-int
c-function-pass-non-const-argument-to-const-reference-parameter
what-does-a-const-cast-do-differently
Is there a way to ensure the argument is const when used as an initializer for the size of an array?
EDIT: I'm not asking why I can't initialize an array with a non-const. I'm asking how to initialize an array from a non-const function argument. Hence, initialize-array-size-from-another-array-value is not the question I am asking. I already know I can't do this but there may be a way and answer has been provided below.
std::array is a non-resizable container whose size is known at compile-time.
If you know your size values at compile-time, you can pass the value as a non-type template argument:
template <int Size>
int run()
{
std::array<int, Size> arr;
}
It can be used as follows:
run<5>();
Note that Size needs to be a constant expression.
If you do not know your sizes at compile-time, use std::vector instead of std::array:
int run(int size)
{
std::vector<int> arr;
arr.resize(size); // or `reserve`, depending on your needs
}
std::vector is a contiguous container that can be resized at run-time.
I'm asking how to initialize an array from a non-const function argument.
As you saw, it is not possible initialize an array size with an variable, because you need to specify the size or array at compiler time.
To solve your problem you should use std::vector that works like an array but you can resize it at run time. You can handle de vector as if you were handled an array, using the operator [], for example:
class MyClass
{
vector<char> myVector;
public:
MyClass();
void resizeMyArray(int newSize);
char getCharAt(int index);
};
MyClass::MyClass():
myVector(0) //initialize the vector to elements
{
}
void MyClass::resizeMyArray(int newSize)
{
myVector.clear();
myVector.resize(newSize, 0x00);
}
char MyClass::getCharAt(int index)
{
return myVector[index];
}
For more information check this link: http://www.cplusplus.com/reference/vector/vector/
Upgrade: Also, considere that std::array can't be resize, as this links say:
Arrays are fixed-size sequence containers: they hold a specific number of elements ordered in a strict linear sequence.

How do i Pass a set<int> var to a function?

The function dfs() in this program operates upon the set A & array C. The program works fine when set A and int C[MAX] are declared global. But when i try to use this program t number of times, the set A and C are initialized with previous test cases's values, which gives wrong output. How can i make this program to accept new values in A & C for every next case. Note: This program is intended to find if the graph with n number of nodes and m number of edges is bipartite or not.
#include <bits/stdc++.h>
using namespace std;
const int MAX=1000000; // maximum number of vertices
int dfs(int x,const set<int>& A,int C[]){
for(int y:A[x]){
if(C[y]==C[x])return 0;// this means the graph is not bipartite
if(C[y]==0){
if(C[x]==1) C[y]=2;
else C[y]=1;
dfs(y,A,C);
return 1;
}
}
}
int main(){
int t;
scanf("%d",&t);
while(t--)
{
set<int> A[MAX];// Here, i declare set<int> A and Int C[MAX] in local scope
int C[MAX];
// Passing set<int> A and int C[] to dfs()..
int res = dfs(i,A,int C);
}
If i change my code to something like above. I get the following error.
prog.cpp: In function 'int dfs(int, const std::set<int>&, int*)':
prog.cpp:8:16: error: no match for 'operator[]' (operand types are 'const std::set<int>' and 'int')
for(int y:A[x]){
According to the c++ doc, set - C++ Reference there is not such operator[] in std::set<>so your for(int y:A[x]) is wrong. You cannot call A[x].
I'd recommend to use an vector or some other container meeting your requirement instead of a std::set

How to use a set of boost::dynamic_bitsets?

I'm trying to use a set of dynamic_bitset objects, but I'm getting an assertion failure at runtime:
a.out: boost/dynamic_bitset/dynamic_bitset.hpp:1291:
bool boost::operator<(const boost::dynamic_bitset<Block, Allocator>&,
const boost::dynamic_bitset<Block, Allocator>&)
[with Block = long unsigned int,
Allocator = std::allocator<long unsigned int>]:
Assertion `a.size() == b.size()' failed.
Here is the code:
#include <iostream>
#include <set>
#include <boost/dynamic_bitset.hpp>
int main() {
typedef boost::dynamic_bitset<> bitset;
std::set<bitset> myset;
bitset x(2, 0);
bitset y(3, 1);
myset.insert(x);
myset.insert(y);
return 0;
}
I'm wondering why the same size for the inserted dynamic_bitset objects is required. For the operator< to work, couldn't it assume that the most significant bits in the shorter bitset are implicitly filled with zeros?
Is there any way to do get that set of dynamic_bitsets to work?
I've also tried an unordered_set because it doesn't need the operator< but it can't compile because dynamic_bitset doesn't have a hash_value and I'm not sure how to write that without using its to_ulong member function, which would work only for short bitsets.
The reason for the assertion is the way the operator< is implemented:
for (size_type ii = a.num_blocks(); ii > 0; --ii)
Only the block count of the first operand is used to iterate through the bitsets.
If the size of the first bitset is larger, it would access the second bitset out of bounds.
You can define and use your own comperator with std::set and handle the comparison of different sized bitsets as you see fit:
struct my_less {
bool operator()(const boost::dynamic_bitset<>& lhs,
const boost::dynamic_bitset<>& rhs) const
{
//TODO: implement custom comparison for lhs < rhs
return false;
}
};
typedef boost::dynamic_bitset<> bitset;
std::set<bitset,my_less> myset;
myset.insert( bitset(2, 0) );
myset.insert( bitset(3, 1) );

Best sorting algorithm [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
What is the best algorithm to sort out unique words from a list of more than 10 million words? we need the best technique in the terms of execution time.
There are two simple approaches I remember using:
Add all the items to a data structure that folds duplicates (generally a hash, but you can also try a balanced tree or a trie).
Sort the list, then run over it copying out all elements that are non-equal to the previous element.
Roughly speaking, and subject to the usual fudges, the hash table and the trie give you expected O(n), the balanced tree and the sort give you expected O(n log n). It is not necessarily true that the O(n) solutions are faster than the O(n log n) solutions for your particular data.
All the options in (1) may have the disadvantage of doing a lot of small memory allocations for nodes in a data structure, which can be slow unless you use a special-purpose allocator. So in my experience it's worth testing the sort on the size of data you actually care about, before embarking on anything that requires you to write significant code.
Depending what language you're using, some of these approaches might be easier to test than others. For example in Python if you have a list of strings then the hashtable approach is just set(my_strings). In C, there is no standard hashtable, so you're either writing one or looking for a library.
Of course ease of writing has no direct effect on execution time, so if (as you claim) your programmer time is immaterial and all that matters is execution speed, then you should have no problems spending a few weeks getting familiar with the best available literature on sorting and hash tables. You'd be far better able to answer the question than I am.
Just add them to a hash. Constant time insert. I don't believe you can do better than order n. Red black trees can be faster on small data sets (faster to traverse the tree than to compute the hash), but your data set is large.
Spoiler:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct somehash {
struct somehash *next;
unsigned hash;
char *mem;
};
#define THE_SIZE (10*1000*1000)
struct somehash *table[THE_SIZE] = { NULL,};
struct somehash **some_find(char *str, unsigned len);
static unsigned some_hash(char *str, unsigned len);
int main (void)
{
char buffer[100];
struct somehash **pp;
size_t len;
while (fgets(buffer, sizeof buffer, stdin)) {
len = strlen(buffer);
pp = some_find(buffer, len);
if (*pp) { /* found */
fprintf(stderr, "Duplicate:%s", buffer);
}
else { /* not found: create one */
fprintf(stdout, "%s", buffer);
*pp = malloc(sizeof **pp);
(*pp)->next = NULL;
(*pp)->hash = some_hash(buffer,len);
(*pp)->mem = malloc(1+len);
memcpy((*pp)->mem , buffer, 1+len);
}
}
return 0;
}struct somehash **some_find(char *str, unsigned len)
{
unsigned hash;
unsigned short slot;
struct somehash **hnd;
hash = some_hash(str,len);
slot = hash % THE_SIZE;
for (hnd = &table[slot]; *hnd ; hnd = &(*hnd)->next ) {
if ( (*hnd)->hash != hash) continue;
if ( strcmp((*hnd)->mem , str) ) continue;
break;
}
return hnd;
}
static unsigned some_hash(char *str, unsigned len)
{
unsigned val;
unsigned idx;
if (!len) len = strlen(str);
val = 0;
for(idx=0; idx < len; idx++ ) {
val ^= (val >> 2) ^ (val << 5) ^ (val << 13) ^ str[idx] ^ 0x80001801;
}
return val;
}

Divide a sequence into continuous sets of size at most K

Divide a sequence of N numbers into continuous sets of size at-most K such that no two set are neighbour of each other(i.e., there is at least one number in between the two sets) and the sum of all the elements in all the sets gets maximised.
e.g., if sequence is 1,2,3,4,5. We can divide it into sets (1,2) and (4,5) as 3 is in between them but not into sets (2,3) and (4,5).
I have done this O(NK).
Please suggest a better algorithm.
I have already used dynamic programming with back tracing.
My code is :
#include<cstdio>
using namespace std;
long long int max(long long int a,long long int b){
if(a>b) return a;
else return b;
}
int main(){
int n,k;
int p[100000];
long long int v[100001];
scanf("%d %d",&n,&k);
int i,j;
for(i=0;i<n;i++)
scanf("%d",&p[i]);
v[0]=0;
v[1]=p[n-1];
int l=1;
for(i=n-2;i>-1;i--){
long long int temp=v[l];
l=(n-i)>k?k:(n-i);
int m=(k-i)>1?(k-i):1;
for(j=l;j>=m;j--)
v[j]=max(p[i]+v[j-1],temp);
v[0]=temp;
}
printf("%lld\n",v[k]);
return 0;
}
Since it sounds like homework, I will just give you a clue. Use dynamic programming with function: F(x,i,k) where x is the sequence, you are considering first i elements, and k is the number of disjoint sub-sequences.

Resources