C++ - Circular array with lower/upper bounds? - c++

I want to create something similar to a double linked list (but with arrays) that works with lower/upper bounds.
A typical circular array would probably look like:
next = (current + 1) % count;
previous = (current - 1) % count;
But what's the mathematical arithmetic to incorporate lower/upper bounds properly into this ?
0 (lower bound item 1)
1
2 (upper bound item 1)
3 (lower bound item 2)
4 (upper bound item 2)
So that:
-> next on index 2 for item 1 returns 0
-> previous on index 0 for item 1 returns 2
-> next on index 4 for item 2 returns 3
-> previous on index 3 for item 2 returns 4
Thank you !
NOTE: Can't use external libraries.

In general mathematical terms:
next === current + 1 (mod count)
prev === current - 1 (mod count)
where === is the 'congruent' operator. Converting this to the modulus operator, it would be:
count = upper - lower
next = ((current + 1 - (lower%count) + count) % count) + lower
prev = ((current - 1 - (lower%count) + count) % count) + lower
It would be up to you to find out the upper & lower bounds for each item. You could store this in a binary tree for fast retrieval. Maybe I'm not understanding your question.
(note that this assumes lower < upper, and lower > 0)

+=======+ +=======+ +=======+
| Obj | ---> | Obj | ---> | Obj |
buffer | 1 | <--- | 2 | <--- | 3 |
+=======+ +=======+ +=======+
index 0 1 2 /* our first run */
index 3 4 5 /* second run */
and so on ...
So, you see for a 3 member list, the 1st item is indexed by 0, 3, 6, etc. Similarly, the second item is indexed by 1, 4 (1 + 3), 7 (4 + 3), ...
The general rule is: next <- (next + 1) % size, where size = upper - lower + 1
Using this formula we get:
curr | next
-------+-----------------
0 | (0 + 1) % 3 = 1
-------+-----------------
1 | (1 + 1) % 3 = 2
-------+-----------------
2 | (2 + 1) % 3 = 0
-------+-----------------
Hope that helps

I wrote this article a few years back about a circular STL iterator.
http://noveltheory.com/Iterators/Iterator_N0.htm
It will work on any STL collection (vectors & boost:array, etc)

Boost has a Circular container that I believe you can set bounds on as well.
In fact the Example on that page looks very similar to what you are saying here.
But anyway, you could accomplish the math portion of it easily using a modulus:
So say your max was 3:
int MAX = 3;
someArray[ 0 % MAX ]; // This would return element 0
someArray[ 1 % MAX ]; // This would return element 1
someArray[ 3 % MAX ]; // This would return element 0
someArray[ 4 % MAX ]; // This would return element 1

Related

How do optimize my code to find product of all the contiguous subsequences of an array?

This is my try to count the contiguous subsequences of an array with product mod 4 is not equal to 2:
# include <iostream>
using namespace std;
int main() {
long long int n, i, j, s, t, count = 0;
cin>>n;
long long int arr[n];
count = 0;
for(i = 0; i<n; i++) {
cin>>arr[i];
}
for(i = 0; i<n; i++) {
s = 1;
for(j = i; j<n; j++) {
s = s*arr[j];
if(s%4!=2) {
count++;
}
}
}
cout<<count;
return 0;
}
However, I want to reduce the time taken by my code to execute. I am looking for a way to do it. Any help/hint would be appreciated.
Thank you.
What does this definition of contiguous subsequences mean?
Listing all the subsequences
Suppose we have the sequence:
A B C D E F
First of all, we should recognize that there is one substring for every unique start and end point. Let's use the notation C-F to mean all items from C through F: i.e.: C D E F.
We can list all subsequences in a triangular arrangement like this:
A B C D E F
A-B B-C C-D D-E E-F
A-C B-D C-E D-F
A-D B-E C-F
A-E B-F
A-F
The first row lists all the subsequences of length 1.
The second row lists all the subsequences of length 2.
The third row lists all the subsequences of length 3. Etc.
The last row is the full sequence.
Modular arithmetic
Computing the product MOD 4 of a set of numbers
To figure out the product of a bunch of numbers MOD 4, we just need to look at each element of the set MOD 4. Intuitively, this is because when you multiply a bunch of numbers, the last digit of the result is determined entirely by the last digit of each factor. In this case "the last digit base 4" is the number mod 4.
The identity we are using is:
(A * B) MOD N == ((A MOD N) * (B MOD N)) MOD N
The table of products
Now we also have to look at the matrix of possible multiplications that might happen. It's a fairly small table and the interesting entries are given here:
2 * 2 = 4 4 MOD 4 = 0
2 * 3 = 6 6 MOD 4 = 2
3 * 3 = 9 9 MOD 4 = 1
So the results of multiplying any 2 numbers MOD 4 are given by this table:
+--------+---+---+---+---+
| Factor | 0 | 1 | 2 | 3 |
+--------+---+---+---+---+
| 0 | 0 | / | / | / |
| 1 | 0 | 1 | / | / |
| 2 | 0 | 2 | 0 | / |
| 3 | 0 | 3 | 2 | 1 |
+--------+---+---+---+---+
The /'s are omitted because of the symmetry of multiplication (A * B = B * A)
An example sequence
Now for each subsequence, let's compute the product MOD 4 of its elements.
Consider the following list of numbers
242 497 681 685 410 795
The first thing we do is take all these numbers MOD 4 and list them as the first row of our list of all subsequences triangle.
2 0 1 1 2 3
The second row is just the product of the pairs above it.
2 0 1 1 2 3
0 0 1 2 3
In general, the Nth element of each row is the product, MOD 4, of:
the number just to its left in the row above left times and
the element in the first row that is diagonally to its right
For example C = A * B
* * * * B *
* * * / *
* A / *
* C *
* *
*
Again,
A is immediately up and left of C
B is diagonally right all the way to the top row from C
Now we can complete our triangle
2 0 1 1 2 3
0 0 1 2 3
0 0 2 3
0 0 2
0 0
0
This can be computed easily in O(n^2) time.
Optimization
These optimizations do not improve the time complexity of the algorithm in its worse case, but can cause an early exit in the computation, and should therefore be included if time is to be reduced and the input is unknown.
Contageous 0's
Furthermore, as a matter of optimization, notice how contagious the 0's are. Anything times 0 is 0, so you can skip computing products of cells below a 0. In your case those sequences will not equal 2 MOD 4 once the product of one of its subsequences is determined to be equal to 0 MOD 4.
* * * 0 * * // <-- this zero infects all cells below it
* * 0 0 *
* 0 0 0
0 0 0
0 0
0
Need a 2 to make a 2.
Look back at the table of factors and products. Notice that the only way to get a product that is equal to 2 MOD 4 is to have one of the factors be equal to 2 MOD 4. What that means is that there can only be a 2 below another 2. So we are only interested in following computing entries in the table that are below a 2. Other entries in rows below can never become a 2.
You don't have to store more than the whole rows.
You only need O(n) storage to implement this. Working line by line, you can compute the values in a row entirely from the values in the first row and values in the row above.
Reading the answers from the table
Now you can look at the rows of the triangle list as you generate them and read off which subsequences are to be included.
Entries with a 2 are to be excluded. All others are to be included.
2 0 1 1 3 2
0 0 1 3 2
0 0 3 2
0 0 2
0 0
0
The excluded subsequences for the example (which I will list only because there are fewer of them in my example) are:
A
F
E-F
D-F
C-F
Which remember, according to our convention refer to the elements:
A
F
E F
D E F
C D E F
Which are:
242
795
410 795
685 410 795
681 685 410 795
Hopefully it's obvious how to display the "included" sequences, rather than the "excluded" sequences, as I have shown above.
Displaying all the elements makes it take much longer.
Sadly, actually displaying all of the elements of such subsequences is still an O(N^3) operation in the worst case. (Imagine a sequence of all zeros.)
Summary
For me, I feel like an average developer could take the magic bullet observation made in the diagram below and write an implementation that has optimal time complexity.
C = A * B
* * * * B *
* * * / *
* A / *
* C *
* *
*

how can we find the nth 3 word combination from a word corpus of 3000 words

I have a word corpus of say 3000 words such as [hello, who, this ..].
I want to find the nth 3 word combination from this corpus.I am fine with any order as long as the algorithm gives consistent output.
What would be the time complexity of the algorithm.
I have seen this answer but was looking for something simple.
(Note that I will be using 1-based indexes and ranks throughout this answer.)
To generate all combinations of 3 elements from a list of n elements, we'd take all elements from 1 to n-2 as the first element, then for each of these we'd take all elements after the first element up to n-1 as the second element, then for each of these we'd take all elements after the second element up to n as the third element. This gives us a fixed order, and a direct relation between the rank and a specific combination.
If we take element i as the first element, there are (n-i choose 2) possibilities for the second and third element, and thus (n-i choose 2) combinations with i as the first element. If we then take element j as the second element, there are (n-j choose 1) = n-j possibilities for the third element, and thus n-j combinations with i and j as the first two elements.
Linear search in tables of binomial coefficients
With tables of these binomial coefficients, we can quickly find a specific combination, given its rank. Let's look at a simplified example with a list of 10 elements; these are the number of combinations with element i as the first element:
i
1 C(9,2) = 36
2 C(8,2) = 28
3 C(7,2) = 21
4 C(6,2) = 15
5 C(5,2) = 10
6 C(4,2) = 6
7 C(3,2) = 3
8 C(2,2) = 1
---
120 = C(10,3)
And these are the number of combinations with element j as the second element:
j
2 C(8,1) = 8
3 C(7,1) = 7
4 C(6,1) = 6
5 C(5,1) = 5
6 C(4,1) = 4
7 C(3,1) = 3
8 C(2,1) = 2
9 C(1,1) = 1
So if we're looking for the combination with e.g. rank 96, we look at the number of combinations for each choice of first element i, until we find which group of combinations the combination ranked 96 is in:
i
1 36 96 > 36 96 - 36 = 60
2 28 60 > 28 60 - 28 = 32
3 21 32 > 21 32 - 21 = 11
4 15 11 <= 15
So we know that the first element i is 4, and that within the 15 combinations with i=4, we're looking for the eleventh combination. Now we look at the number of combinations for each choice of second element j, starting after 4:
j
5 5 11 > 5 11 - 5 = 6
6 4 6 > 4 6 - 4 = 2
7 3 2 <= 3
So we know that the second element j is 7, and that the third element is the second combination with j=7, which is k=9. So the combination with rank 96 contains the elements 4, 7 and 9.
Binary search in tables of running total of binomial coefficients
Instead of creating a table of the binomial coefficients and then performing a linear search, it is of course more efficient to create a table of the running total of the binomial coefficient, and then perform a binary search on it. This will improve the time complexity from O(N) to O(logN); in the case of N=3000, the two look-ups can be done in log2(3000) = 12 steps.
So we'd store:
i
1 36
2 64
3 85
4 100
5 110
6 116
7 119
8 120
and:
j
2 8
3 15
4 21
5 26
6 30
7 33
8 35
9 36
Note that when finding j in the second table, you have to subtract the sum corresponding with i from the sums. Let's walk through the example of rank 96 and combination [4,7,9] again; we find the first value that is greater than or equal to the rank:
3 85 96 > 85
4 100 96 <= 100
So we know that i=4; we then subtract the previous sum next to i-1, to get:
96 - 85 = 11
Now we look at the table for j, but we start after j=4, and subtract the sum corresponding to 4, which is 21, from the sums. then again, we find the first value that is greater than or equal to the rank we're looking for (which is now 11):
6 30 - 21 = 9 11 > 9
7 33 - 21 = 12 11 <= 12
So we know that j=7; we subtract the previous sum corresponding to j-1, to get:
11 - 9 = 2
So we know that the second element j is 7, and that the third element is the second combination with j=7, which is k=9. So the combination with rank 96 contains the elements 4, 7 and 9.
Hard-coding the look-up tables
It is of course unnecessary to generate these look-up tables again every time we want to perform a look-up. We only need to generate them once, and then hard-code them into the rank-to-combination algorithm; this should take only 2998 * 64-bit + 2998 * 32-bit = 35kB of space, and make the algorithm incredibly fast.
Inverse algorithm
The inverse algorithm, to find the rank given a combination of elements [i,j,k] then means:
Finding the index of the elements in the list; if the list is sorted (e.g. words sorted alphabetically) this can be done with a binary search in O(logN).
Find the sum in the table for i that corresponds with i-1.
Add to that the sum in the table for j that corresponds with j-1, minus the sum that corresponds with i.
Add to that k-j.
Let's look again at the same example with the combination of elements [4,7,9]:
i=4 -> table_i[3] = 85
j=7 -> table_j[6] - table_j[4] = 30 - 21 = 9
k=9 -> k-j = 2
rank = 85 + 9 + 2 = 96
Look-up tables for N=3000
This snippet generates the look-up table with the running total of the binomial coefficients for i = 1 to 2998:
function C(n, k) { // binomial coefficient (Pascal's triangle)
if (k < 0 || k > n) return 0;
if (k > n - k) k = n - k;
if (! C.t) C.t = [[1]];
while (C.t.length <= n) {
C.t.push([1]);
var l = C.t.length - 1;
for (var i = 1; i < l / 2; i++)
C.t[l].push(C.t[l - 1][i - 1] + C.t[l - 1][i]);
if (l % 2 == 0)
C.t[l].push(2 * C.t[l - 1][(l - 2) / 2]);
}
return C.t[n][k];
}
for (var total = 0, x = 2999; x > 1; x--) {
total += C(x, 2);
document.write(total + ", ");
}
This snippet generates the look-up table with the running total of the binomial coefficients for j = 2 to 2999:
for (var total = 0, x = 2998; x > 0; x--) {
total += x;
document.write(total + ", ");
}
Code example
Here's a quick code example, unfortunately without the full hardcoded look-up tables, because of the size restriction on answers on SO. Run the snippets above and paste the results into the arrays iTable and jTable (after the leading zeros) to get the faster version with hard-coded look-up tables.
function combinationToRank(i, j, k) {
return iTable[i - 1] + jTable[j - 1] - jTable[i] + k - j;
}
function rankToCombination(rank) {
var i = binarySearch(iTable, rank, 1);
rank -= iTable[i - 1];
rank += jTable[i];
var j = binarySearch(jTable, rank, i + 1);
rank -= jTable[j - 1];
var k = j + rank;
return [i, j, k];
function binarySearch(array, value, first) {
var last = array.length - 1;
while (first < last - 1) {
var middle = Math.floor((last + first) / 2);
if (value > array[middle]) first = middle;
else last = middle;
}
return (value <= array[first]) ? first : last;
}
}
var iTable = [0]; // append look-up table values here
var jTable = [0, 0]; // and here
// remove this part when using hard-coded look-up tables
function C(n,k){if(k<0||k>n)return 0;if(k>n-k)k=n-k;if(!C.t)C.t=[[1]];while(C.t.length<=n){C.t.push([1]);var l=C.t.length-1;for(var i=1;i<l/2;i++)C.t[l].push(C.t[l-1][i-1]+C.t[l-1][i]);if(l%2==0)C.t[l].push(2*C.t[l-1][(l-2)/2])}return C.t[n][k]}
for (var iTotal = 0, jTotal = 0, x = 2999; x > 1; x--) {
iTable.push(iTotal += C(x, 2));
jTable.push(jTotal += x - 1);
}
document.write(combinationToRank(500, 1500, 2500) + "<br>");
document.write(rankToCombination(1893333750) + "<br>");

Ordering an array based on 2D array of relations (higher, lower, doesn't matter)

I have been stuck with this problem for two days and I still can't get it right.
Basically, I have a 2D array with relations between certain numbers (in given range):
0 = the order doesn't matter
1 = the first number (number in left column) should be first
2 = the second number (number in upper row) should be first
So, I have some 2D array, for example this:
0 1 2 3 4 5 6
0 0 0 1 0 0 0 2
1 0 0 2 0 0 0 0
2 2 1 0 0 1 0 0
3 0 0 0 0 0 0 0
4 0 0 2 0 0 0 0
5 0 0 0 0 0 0 0
6 1 0 0 0 0 0 0
And my goal is to create a new array of given numbers (0 - 6) in such a way that it is following the rules from the 2D array (e.g. 0 is before 2 but it is after 6). I probably also have to check if such array exists and then create the array. And get something like this:
6 0 2 1 4 5
My Code
(It doesn't really matter, but I prefer c++)
So far I tried to start with ordered array 0123456 and then swap elements according to the table (but that obviously can't work). I also tried inserting the number in front of the other number according to the table, but it doesn't seem to work either.
// My code example
// I have:
// relArr[n][n] - array of relations
// resArr = {1, 2, ... , n} - result array
for (int i = 0; i < n; i++) {
for (int x = 0; x < n; x++) {
if (relArr[i][x] == 1) {
// Finding indexes of first (i) and second (x) number
int iI = 0;
int iX = 0;
while (resArr[iX] != x)
iX++;
while (resArr[iI] != i)
iI++;
// Placing the (i) before (x) and shifting array
int tmp, insert = iX+1;
if (iX < iI) {
tmp = resArr[iX];
resArr[iX] = resArr[iI];
while (insert < iI+1) {
int tt = resArr[insert];
resArr[insert] = tmp;
tmp = tt;
insert++;
}
}
} else if (relArr[i][x] == 2) {
int iI = 0;
int iX = 0;
while (resArr[iX] != x)
iX++;
while (resArr[iI] != i)
iI++;
int tmp, insert = iX-1;
if (iX > iI) {
tmp = resArr[iX];
resArr[iX] = resArr[iI];
while (insert > iI-1) {
int tt = resArr[insert];
resArr[insert] = tmp;
tmp = tt;
insert--;
}
}
}
}
}
I probably miss correct way how to check whether or not it is possible to create the array. Feel free to use vectors if you prefer them.
Thanks in advance for your help.
You seem to be re-ordering the output at the same time as you're reading the input. I think you should parse the input into a set of rules, process the rules a bit, then re-order the output at the end.
What are the constraints of the problem? If the input says that 0 goes before 1:
| 0 1
--+----
0 | 1
1 |
does it also guarantee that it will say that 1 comes after 0?
| 0 1
--+----
0 |
1 | 2
If so you can forget about the 2s and look only at the 1s:
| 0 1 2 3 4 5 6
--+--------------
0 | 1
1 |
2 | 1 1
3 |
4 |
5 |
6 | 1
From reading the input I would store a list of rules. I'd use std::vector<std::pair<int,int>> for this. It has the nice feature that yourPair.first comes before yourPair.second :)
0 before 2
2 before 1
2 before 4
6 before 0
You can discard any rules where the second value is never the first value of a different rule.
0 before 2
6 before 0
This list would then need to be sorted so that "... before x" and "x before ..." are guaranteed to be in that order.
6 before 0
0 before 2
Then move 6, 0, and 2 to the front of the list 0123456, giving you 6021345.
Does that help?
Thanks for the suggestion.
As suggested, only ones 1 are important in 2D array. I used them to create vector of directed edges and then I implemented Topological Sort. I decide to use this Topological Sorting Algorithm. It is basically Topological Sort, but it also checks for the cycle.
This successfully solved my problem.

How to return item index from list SML?

I have go a problem with function in SML. This function should return list index of number which will not be summed, but was taken to sum.
A call of a function: index(10, [1,2,3,4,5,6,7])
Result should be 3
(10 is a sum of numbers, we seek an index from the list which gives us 10, e.g:
1+2+3=6, 1+2+3+4=10, and return previuos one)
fun index (sum : int, numbers : int list) =
if null numbers
then 0
else if hd(numbers) > sum
then 0
else 1 + index(sum, (hd(numbers)+(hd(tl numbers)))::(tl numbers))
It seems to work, but result is wrong.
Function increments the result every two calling even if it should not.
Can anybody tell me how to fix this?
You're almost there. While I agree with #koodawg that adding a counter and a running total is another solution for this problem, having those in your code will complicate it more than it needs to be.
First, I have a few comments about your code. You must remove the unnecessary parens. hd(numbers) is same as hd numbers and (hd(tl numbers)) is equal to hd(tl numbers). So your (hd(numbers)+(hd(tl numbers))) could be simplified to (hd numbers + hd(tl numbers)). Also, you can combine if null numbers and if hd(numbers) > sum in a single condition for code brevity since they yield the same result: 0.
I'll try to explain how code works and I hope you'll get the idea where you have to amend your code.
Using your example, index(10, [1,2,3,4,5,6,7]), your code execution will be like this:
1)
fun index(10, [1,2,3,4,5,6,7]) =
if 1 > 10
then 0
else 1 + (10, [1 + 2] append to [2,3,4,5,6,7])
new list: [3,2,3,4,5,6,7]
result: 1
2)
fun index(10, [3,2,3,4,5,6,7]) =
if 3 > 10
then 0
else 1 + (10, [3 + 2] append to [2,3,4,5,6,7])
new list: [5,2,3,4,5,6,7]
result: 1
3)
fun index(10, [5,2,3,4,5,6,7]) =
if 5 > 10
then 0
else 1 + (10, [5 + 2] append to [2,3,4,5,6,7])
new list: [7,2,3,4,5,6,7]
result: 1
4)
fun index(10, [7,2,3,4,5,6,7]) =
if 7 > 10
then 0
else 1 + (10, [7 + 2] append to [2,3,4,5,6,7])
new list: [9,2,3,4,5,6,7]
result: 1
5)
fun index(10, [9,2,3,4,5,6,7]) =
if 9 > 10
then 0
else 1 + (10, [9 + 2] append to [2,3,4,5,6,7])
new list: [11,2,3,4,5,6,7]
result: 1
6)
fun index(10, [11,2,3,4,5,6,7]) =
if 11 > 10
then 0
result: 0
To sum all results: 1 + 1 + 1 + 1 + 1 + 0 = 5 (just like what you said that your function adds 2 to the expected result)
The correct code must behave like this:
1)
fun index(10, [1,2,3,4,5,6,7]) =
if 1 > 10
then 0
else 1 + (10, [1 + 2] append to [3,4,5,6,7])
new list: [3,3,4,5,6,7]
result: 1
2)
fun index(10, [3,3,4,5,6,7]) =
if 3 > 10
then 0
else 1 + (10, [3 + 3] append to [4,5,6,7])
new list: [6,4,5,6,7]
result: 1
3)
fun index(10, [6,4,5,6,7]) =
if 6 > 10
then 0
else 1 + (10, [6 + 4] append to [5,6,7])
new list: [10,5,6,7]
result: 1
4)
fun index(10, [10,5,6,7]) =
if 10 > 10
then 0
result: 0
To sum all results: 1 + 1 + 1 + 0 = 3 which is the expected answer.
HINT: You always make sure that the new list your function is processing must be smaller than the previous list/original list.
I hope I explained clearly why your code isn't working. I didn't include the code because I know this is a homework for an online class.
You need to keep a counter and total. Counter that increments with every recursive call, total equal to sum of each hd(numbers) as you go, then return the counter when your total > sum.
Something like this;
if (total + hd numbers) >= sum
then counter
else recursivecall(total + hd numbers, tl numbers, counter + 1)

Partitioning arrays by index

I am fairly new to C++, and am struggling through a problem that seems to have a solid solution but I just can't seem to find it. I have a contiguous array of ints starting at zero:
int i[6] = { 0, 1, 2, 3, 4, 5 }; // this is actually from an iterator
I would like to partition the array into groups of three. The design is to have two methods, j and k, such that given an i they will return the other two elements from the same group of three. For example:
i j(i) k(i)
0 1 2
1 0 2
2 0 1
3 4 5
4 3 5
5 3 4
The solution seems to involve summing the i with its value mod three and either plus or minus one, but I can't quite seem to work out the logic.
This should work:
int d = i % 3;
int j = i - d + ( d == 0 );
int k = i - d + 2 - ( d == 2 );
or following statement for k could be more readable:
int k = i - d + ( d == 2 ? 1 : 2 );
This should do it:
int j(int i)
{
int div = i / 3;
if (i%3 != 0)
return 3*div;
else
return 3*div+1;
}
int k(int i)
{
int div = i / 3;
if (i%3 != 2)
return 3*div+2;
else
return 3*div+1;
}
Test.
If you want shorter functions:
int j(int i)
{
return i/3*3 + (i%3 ? 0 : 1);
}
int k(int i)
{
return i/3*3 + (i%3-2 ? 2 : 1);
}
Well, first, notice that
j(i) == j(3+i) == j(6+i) == j(9+i) == ...
k(i) == k(3+i) == k(6+i) == k(9+i) == ...
In other words, you only need to find a formula for
j(i), i = 0, 1, 2
k(i), i = 0, 1, 2
and then for the rest of the cases simply plug in i mod 3.
From there, you'll have trouble finding a simple formula because your "rotation" isn't standard. Instead of
i j(i) k(i)
0 1 2
1 2 0
2 0 1
for which the formula would have been
j(i) = (i + 1) % 3
k(i) = (i + 2) % 3
you have
i j(i) k(i)
0 1 2
1 0 1
2 0 2
for which the only formula I can think of at the moment is
j(i) = (i == 0 ? 1 : 0)
k(i) = (i == 1 ? 1 : 2)
If the values of your array (let's call it arr, not i in order to avoid confusion with the index i) do not coincide with their respective index, you have to perform a reverse lookup to figure out their index first. I propose using an std::map<int,size_t> or an std::unordered_map<int,size_t>.
That structure reflects the inverse of arr and you can extra the index for a particular value with its subscript operator or the at member function. From then, you can operate purely on the indices, and use modulo (%) to access the previous and the next element as suggested in the other answers.