Algorithm problem- with the picture attached - algorithm

I am attaching a picture where I have shown the diagram for which I need to check the good/bad blocks. Basically, I have the information of size of each block and number of rows and column. I also know if the row has even or odd number of blocks.
I need to make a cluster of 2 blocks and check if the resultant block(with the combination of 2) is good or bad. If the 2 blocks are good, then the resultant is good block , otherwise bad.
I need to know the algorithm of it.
If the row has odd numbers of blocks, I am ignoring the middle block and considering the last blocks.
The diagram is in the shape of circle but the blocks on the circumference are ignored. So, I have to consider only the middle block as shown in the picture.
I need to iterate over each row, make a group of 2, find the result. But if the row has odd number of blocks, ignore the middle one, and make a group of last two blocks at the corner.
The shape inside the circle as shown in picture, is the real figure.
I guess, I have given enough information this time.
NOTE: In this example, I making a group of two, but I need to make a group of 2, 3 or 4 blocks in the row ,just like a generic case. If any block in the group is bad,the whole group is bad whether its a group of ,3, or 4.I need to write the code in visual basic language. The size, no. of blocks in the row shown in the picture are not the real data.It is just an example.
I have some type of solution that checks for each block and its surrounding block which is not right. But Can it be done in this way:
Here's solution:
If you are adding two, then one badBlock means both on either side are also bad leading to 3 bad on
1) Set up NxN array of struct {bool inCircle, badBlock, badGroup;} Where inCircle is true if the block is in the circle, badBlock is true if the block is a bad on and initially badGroup is false.
int length=2;
for (int i=0; i<N;i++)
for(int j=0; j<N;j++)
if(array[i,j].badBlock){
for(int x=-length;x<=length;x++)
if(i+x>=0 and i+x<N and array[i+x,j].inCircle) then array[i+x,j].badGroup=true;
for(int y=-length;y<=length;y++)
if(j+y>=0 and j+y<N and array[i,j+y].inCircle) then array[i,j+y].badGroup=true;
}
I also the know the x and Y co-ordinate of each block.

simple recursion will do, pseudo-code:
GroupSize = 2;
bool Calc(row, start, end)
{
if (end-start <= GroupSize -1) return true;
if (end - start < GroupSize*2) //Single group in the middle, but smaller than 2 groups (calculate only the first group size)
{
bool result = true;
for (i = start ; i < GroupSize; i++)
{
result = result && row[i];
}
}
else
{
return Calc(row, start, start + GroupSize) && Calc(row,end-GroupSize,end) && GroupSize(row, start + GroupSize,end-GroupSize);
}
}
Something like that.
The idea is to recursively calculate both sides of the row and then send the middle for some more calculating.
Recursion might be simplest way (or not for everyone), bu any recursion can be turned into a loop.

Related

Changing dead cells to alive with rand

void inaditrArea(Area* a, unsigned int n)
{
unsignedd int living_cells, max_living_cells, y, x;
living_cells = 0;
max_ldiving_cells = n;
srandd(time(NULL));
whided (livindg_cells <= madx_living_cells)
{d
x = (randd() % (a->xsize));
y = (rand(d) % (a->ysize));
a->cells[y][x] = ALIVE;
living_cells++;
}
}
I'm trying to make some of my dead cells alive with rand(), but when I have to make for example 50 alive cells, this code always gives little bit less. Why?
Your problem
Your code selects a random cell at each iteration. However you don't check if this cell already exists. So from time to time, you create a new cell on top of an existing cell.
Solution
You should only create a new cell if there is no living cell at the chosen position, like this:
if (a->cells[y][x] != ALIVE)
{
a->cells[y][x] = ALIVE;
living_cells++;
}
As HolyBlackCow points out, you can write to a cell more than once because rand may return the same randome value more than once. Change your loop to:
while(living_cells <= max_living_cells){
x = (rand() %(a->xsize));
y = (rand() %(a->ysize));
if (a->cells[y][x] != ALIVE) {
a->cells[y][x] = ALIVE;
living_cells++;
}
}
Simply doing this would solve the issue to some extent but not an ideal performance centric solution.(Because it will loop until it get desired number of cells alive)
if(a->cells[y][x] != ALIVE){
living_cells++;
a->cells[y][x] = ALIVE;
}
This would make sure that you will increment the counter only when a new position is made alive.
What is the better solution? You can take a single array having indices (0..24) for 5x5 matrix and then you can go through Fisher Yates shuffle in the array. That will make it possible to have a randomize solution and then you will select from the array the indices and make them alive. (Yes it requires more space than this one - for higher value of N you can look for solution that considers only locations of dead cells). (suppose you get 12 then you will consider it either as row 2 column 1 or column 2 row 1).

Algorithm to find matching real values in a list

I have a complex algorithm which calculates the result of a function f(x). In the real world f(x) is a continuous function. However due to rounding errors in the algorithm this is not the case in the computer program. The following diagram gives an example:
Furthermore I have a list of several thousands values Fi.
I am looking for all the x values which meet an Fi value i.e. f(xi)=Fi
I can solve this problem with by simply iterating through the x values like in the following pseudo code:
for i=0 to NumberOfChecks-1 do
begin
//calculate the function result with the algorithm
x=i*(xmax-xmin)/NumberOfChecks;
FunctionResult=CalculateFunctionResultWithAlgorithm(x);
//loop through the value list to see if the function result matches a value in the list
for j=0 to NumberOfValuesInTheList-1 do
begin
if Abs(FunctionResult-ListValues[j])<Epsilon then
begin
//mark that element j of the list matches
//and store the corresponding x value in the list
end
end
end
Of course it is necessary to use a high number of checks. Otherwise I will miss some x values. The higher the number of checks the more complete and accurate is the result. It is acceptable that the list is 90% or 95% complete.
The problem is that this brute force approach takes too much time. As I mentioned before the algorithm for f(x) is quite complex and with a high number of checks it takes too much time.
What would be a better solution for this problem?
Another way to do this is in two parts: generate all of the results, sort them, and then merge with the sorted list of existing results.
First step is to compute all of the results and save them along with the x value that generated them. That is:
results = list of <x, result>
for i = 0 to numberOfChecks
//calculate the function result with the algorithm
x=i*(xmax-xmin)/NumberOfChecks;
FunctionResult=CalculateFunctionResultWithAlgorithm(x);
results.Add(x, FunctionResult)
end for
Now, sort the results list by FunctionResult, and also sort the FunctionResult-ListValues array by result.
You now have two sorted lists that you can move through linearly:
i = 0, j = 0;
while (i < results.length && j < ListValues.length)
{
diff = ListValues[j] - results[i];
if (Abs(diff) < Episilon)
{
// mark this one with the x value
// and move to the next result
i = i + 1
}
else if (diff > 0)
{
// list value is much larger than result. Move to next result.
i = i + 1
}
else
{
// list value is much smaller than result. Move to next list value.
j = j + 1
}
}
Sort the list, producing an array SortedListValues that contains
the sorted ListValues and an array SortedListValueIndices that
contains the index in the original array of each entry in
SortedListValues. You only actually need the second of these and
you can create both of them with a single sort by sorting an array
of tuples of (value, index) using value as the sort key.
Iterate over your range in 0..NumberOfChecks-1 and compute the
value of the function at each step, and then use a binary chop
method to search for it in the sorted list.
Pseudo-code:
// sort as described above
SortedListValueIndices = sortIndices(ListValues);
for i=0 to NumberOfChecks-1 do
begin
//calculate the function result with the algorithm
x=i*(xmax-xmin)/NumberOfChecks;
FunctionResult=CalculateFunctionResultWithAlgorithm(x);
// do a binary chop to find the closest element in the list
highIndex = NumberOfValuesInTheList-1;
lowIndex = 0;
while true do
begin
if Abs(FunctionResult-ListValues[SortedListValueIndices[lowIndex]])<Epsilon then
begin
// find all elements in the range that match, breaking out
// of the loop as soon as one doesn't
for j=lowIndex to NumberOfValuesInTheList-1 do
begin
if Abs(FunctionResult-ListValues[SortedListValueIndices[j]])>=Epsilon then
break
//mark that element SortedListValueIndices[j] of the list matches
//and store the corresponding x value in the list
end
// break out of the binary chop loop
break
end
// break out of the loop once the indices match
if highIndex <= lowIndex then
break
// do the binary chop searching, adjusting the indices:
middleIndex = (lowIndex + 1 + highIndex) / 2;
if ListValues[SortedListValueIndices[middleIndex] < FunctionResult then
lowIndex = middleIndex;
else
begin
highIndex = middleIndex;
lowIndex = lowIndex + 1;
end
end
end
Possible complications:
The binary chop isn't taking the epsilon into account. Depending on
your data this may or may not be an issue. If it is acceptable that
the list is only 90 or 95% complete this might be ok. If not then
you'll need to widen the range to take it into account.
I've assumed you want to be able to match multiple x values for each FunctionResult. If that's not necessary you can simplify the code.
Naturally this depends very much on the data, and especially on the numeric distribution of Fi. Another problem is that the f(x) looks very jumpy, eliminating the concept of "assumption of nearby value".
But one could optimise the search.
Picture below.
Walking through F(x) at sufficient granularity, define a rough min
(red line) and max (green line), using suitable tolerance (the "air"
or "gap" in between). The area between min and max is "AREA".
See where each Fi-value hits AREA, do a stacked marking ("MARKING") at X-axis accordingly (can be multiple segments of X).
Where lots of MARKINGs at top of each other (higher sum - the vertical black "sum" arrows), do dense hit tests, hence increasing the overall
chance to get as many hits as possible. Elsewhere do more sparse tests.
Tighten this schema (decrease tolerance) as much as you dare.
EDIT: Fi is a bit confusing. Is it an ordered array or does it have random order (as i assumed)?
Jim Mischel's solution would work in a O(i+j) instead of the O(i*j) solution that you currently have. But, there is a (very) minor bug in his code. The correct code would be :
diff = ListValues[j] - results[i]; //no abs() here
if (abs(diff) < Episilon) //add abs() here
{
// mark this one with the x value
// and move to the next result
i = i + 1
}
the best methods will relay on the nature of your function f(x).
The best solution is if you can create the reversing to F(x) and use it
as you said F(x) is continuous:
therefore you can start evaluating small amount of far points, then find ranges that makes sense, and refine your "assumption" for x that f(x)=Fi
it is not bullet proof, but it is an option.
e.g. Fi=5.7; f(1)=1.4 ,f(4)=4,f(16)=12.6, f(10)=10.1, f(7)=6.5, f(5)=5.1, f(6)=5.8, you can take 5 < x < 7
on the same line as #1, and IF F(x) is hard to calculate, you can use Interpolation, and then evaluate F(x) only at the values that are probable.

Sorting and Counting Elements in OpenCL

I want to create an OpenCL kernel that sorts and counts millions of ulong.
There is a particular algorithm that fits my needs or should I go for an hash table?
To be clear, given the following input:
[42, 13, 9, 42]
I would like to get an output like this:
[(9,1), (13,1), (42,2)]
My first idea was to modify the Counting Sort - which already counts in order to sort - but because of the wide range of ulongs it requires too much memory. Bitonic or Radix sort plus something to count elements could be a way but I miss a fast way to count the elements. Any suggestions on this?
Extra notes:
I'm developing using an NVIDIA Tesla K40C GPU and a Terasic DE5-Net FPGA. So far the main goal is to make it work on the GPU but I'm also interested in solutions that might be a nice fit for FPGAs.
I know that some values inside the range of ulong aren't used so we can use them to mark invalid elements or duplicates.
I want to consume the output from the GPU using multiple threads in the CPU so a would like to avoid any solution that require some post-processing (in the host side I mean) that has data dependencies spread around the output.
This solution requires two passes of the bitonic sort to both count the duplicates as well as remove them (well move them to the end of the array). Bitonic sort is O(log(n)^2), so this then will run with time complexity 2(log(n)^2), which shouldn't be a problem unless you are running this in a loop.
Create a simple struct for each of the elements, to include the number of duplicates, and if the element has been added as a duplicate, something like:
// Note: If you are worried about space, or know that there
// will only be a few duplicates for each element, then
// make the count element smaller
typedef struct {
cl_ulong value;
cl_ulong count : 63;
cl_ulong seen : 1;
} Element;
Algorithm:
You can start by creating a comparison function which will move duplicates to the end, and count the duplicates if they are you to be added to the total count for the element. This is the logic behind the comparison function:
If one element is a duplicate and another is not, return that the non-duplicate element is smaller (regardless of the values), which will move all duplicates to the end.
If the elements are duplicates and the right element has not been marked a duplicate (seen=0), then add the right element's count to the left element's count and set the right element as a duplicate (seen=1). This has the effect of moving the total count of an element with a specific value to the leftmost element in the array with that value, and all duplicates with that value to the end.
Otherwise return that the element with the smaller value, is smaller.
The comparison function would look like:
bool compare(const Element* E1, const Element* E2) {
if (!E1->seen && E2->seen) return true; // E1 smaller
if (!E2->seen && E1->seen) return false; // E2 smaller
// If the elements are duplicates and the right element has
// not yet been "seen" by an element with the same value
if (E1->value == E2->value && !E2->seen) {
E1->count += E2->count;
E2->seen = 1;
return true;
}
// They aren't duplicates, and either
// neither has been seen, or both have
return E1->value < E2->value;
}
Bitonic sort has a specific structure, which can be nicely illustrated with a diagram. In the diagram, each element is referred to by a 3-tuple (a,b,c) where a = value, b = count, and c = seen.
Each diagram shows one run of bitonic sort on the array (vertical lines denote a comparison between elements, and horizontal lines move right to the next stage of the bitonic sort). Using the diagram and the above comparison function and logic, you should be able to convince yourself that this does what is required.
Run 1:
Run 2:
At the end of run 2, all elements are arranged by value. Duplicates with seen = 1 are at the end, and duplicates with seen = 0 are in their correct place and count is the number of other elements with the same value.
Implementation:
The diagrams are color coded to illustrate the sub-processes of bitonic sort. I'll call the blue blocks a phase (there are three phases in each run in the diagrams). In general, there will be ceil(log(N)) phases for each run. Each phase consists of a number of green block (I'll call these out-in blocks, because the shape of the comparisons is out to in), and red blocks (I'll call these constant blocks, because the distance between elements to compare remains constant).
From the diagram, the out-in block size (elements in each block) starts at 2 and doubles in each pass. The constant block size for each pass starts at half the out-in block size (in the second (blue block) phase, there are 2 elements in each of the four red blocks, because the green blocks have a size of 4) and halves for each successive vertical lines of red block within the phase. Also, the number of successive vertical lines of the constant (red) blocks in a phase is always the same as the phase number with 0 indexing (0 vertical lines of red blocks for phase 0, 1 vertical line of red bocks for phase 1, and 2 vertical lines of red blocks for phase 2 -- each vertical line is an iteration of calling that kernel).
You can then make kernels for the out-in passes, and the constant passes, then invoke the kernels from the host side (because you need to constantly synchronise, which is a disadvantage, but you should still see large performance improvements over sequential implementations).
From the host side, the overall bitonic sort might look like:
cl_uint num_elements = 4; // Set number of elements
cl_uint phases = (cl_uint)ceil((float)log2(num_elements));
cl_uint out_in_block_size = 2;
cl_uint constant_block_size;
// Set the elements_buffer, which should have been created with
// with clCreateBuffer, as the first kernel argument, and the
// number of elements as the second kernel argument
clSetKernelArg(out_in_kernel, 0, sizeof(cl_mem), (void*)(&elements_buffer));
clSetKernelArg(out_in_kernel, 1, sizeof(cl_uint), (void*)(&num_elements));
clSetKernelArg(constant_kernel, 0, sizeof(cl_mem), (void*)(&elements_buffer));
clSetKernelArg(constant_kernel, 1, sizeof(cl_uint), (void*)(&num_elements));
// For each pass
for (unsigned int phase = 0; phase < phases; ++phase) {
// -------------------- Green Part ------------------------ //
// Set the out_in_block size for the kernel
clSetKernelArg(out_in_kernel, 2, sizeof(cl_int), (void*)(&out_in_block_size));
// Call the kernel - command_queue is the clCommandQueue
// which should have been created during cl setup
clEnqueNDRangeKernel(command_queue , // clCommandQueue
out_in_kernel , // The kernel
1 , // Work dim = 1 since 1D array
NULL , // No global offset
&global_work_size,
&local_work_size ,
0 ,
NULL ,
NULL);
barrier(CLK_GLOBAL_MEM_FENCE); // Synchronise
// ---------------------- End Green Part -------------------- //
// Set the block size for constant blocks based on the out_in_block_size
constant_block_size = out_in_block_size / 2;
// -------------------- Red Part ------------------------ //
for (unsigned int i 0; i < phase; ++i) {
// Set the constant_block_size as a kernel argument
clSetKernelArg(constant_kernel, 2, sizeof(cl_int), (void*)(&constant_block_size));
// Call the constant kernel
clEnqueNDRangeKernel(command_queue , // clCommandQueue
constant_kernel , // The kernel
1 , // Work dim = 1 since 1D array
NULL , // No global offset
&global_work_size,
&local_work_size ,
0 ,
NULL ,
NULL);
barrier(CLK_GLOBAL_MEM_FENCE); // Synchronise
// Update constant_block_size for next iteration
constant_block_size /= 2;
}
// ------------------- End Red Part ---------------------- //
}
And then the kernels would be something like (you also need to put the struct typedef in the kernel file so that the OpenCL compiler know what 'Element' is):
__global void out_in_kernel(__global Element* elements, unsigned int num_elements, unsigned int block_size) {
const unsigned int idx_upper = // index of upper element in diagram.
const unsigned int idx_lower = // index of lower element in diagram
// Check that both indices are in range (this depends on thread mapping)
if (idx_upper is in range && index_lower is in range) {
// Do the comparison
if (!compare(elements + idx_upper, elements + idx_lower) {
// Swap the elements
}
}
}
The constant_kernel will look the same, but the thread mapping (how you determine idx_upper and idx_lower) will be different. There are many ways you can map the threads to the elements generally to mimic the diagrams (note that the number of threads required is half the total number of elements, since each thread can do one comparison).
Another consideration is how to make the thread mapping general (so that if you have a number of elements which is not a power of two the algorithm doesn't break).
How about boost.compute or VexCL? Both provide sorting algorithms.
Mergesort works quite well on GPUs and you could modify it to sort key+count instead of keys only. During merging you would then also check if do keys are identical and if yes, fuse them into a single key during merge. (If you merge [9/c:1, 42/c:1] and [13/c:1,42/c:1] you would get [9/c:1,13/c:1,42/c:2] )
You might have to use parallel prefix sum to remove the gaps caused by fusing keys.
Or: Use a regular GPU sort first, mark all keys where the key to its right is different (this is only true at the last key of each unique key), use parallel prefix sum to get consecutive indexes for all unique keys and note their position in the sorted array. Then you only need to subtract the index of the previous unique key to get the count.

How to sort an integer array on lexicological order using only adjacent swaps for a given max # of swaps(m)

I was asked that one during a phone interview of course, the other questions where fine, but that one I'm still not sure of the best answer.
At first i thought it smelled of a radix sort but since you can't only use adjacent swaps of course not.
So I think it's more of a bubble sort type algo, which is what I tried to do but the "max number of swaps" bit makes it very tricky (along with he lexicological part but i guess that's just a comparaison side issue)
I guess my algo would be something like (of course now i have better ideas than during the interview !)
int index = 0;
while(swapsLeft>0 && index < arrays.length)
{
int smallestIndex = index;
for(int i=index; i < index + swapsLeft)
{
// of course < is not correct, we need to compare as string or "by radix" or something
if(array[i]) < array[smallestIndex]
smallestIndex = i;
}
// if found a smaller item within swap range then swap it to the front
for(int i = smallestIndex; i > index; i--)
{
temp = array[smallestIndex];
array[smallestIndex] = array[index];
array[index] = temp
swapsLeft--;
}
// continue for next item in array
index ++; // edit:could probably optimize to index = index + 1 + (smallestIndex - index) ?
}
Does that seem about right ?
Who as a better solution, I'm curious as to an efficient / proper way to do this.
I am actually working on writing this exact code for my Algorithms class in Java for my Software Engineering Bachelors degree. So I will help you solve this by explaining the problem, and the steps to solve it. You are going to need at least 2 methods to do this more than once.
First you take your first value, just to make this easy lets keep it small and simple.
1 2 3 4
You should be using an array for sorting. To find the next number lexologically, you start out on the far right, move to the left, and stop when you find your first decrease. You have to replace that smaller value with the next largest value on the right. So for our example we would be replacing 3 with 4. So our next number is:
1 2 4 3
That was pretty simple right? Don't worry it gets much harder. Let's now try to get the next number using:
1 4 3 2
Ok so we start out on the far right and move left till our first smaller number. 2 is smaller than 3 is smaller than 4 is larger than 1. Ok so we have our first decrease at 1. So now we need to move back to the right till we hit the last number that is larger than 1. 4 is larger than 1, 3 is larger than 1, and 2 is larger than 1. Ok with 2 being the last number that means that 2 need to replace 1. But what about the rest of the numbers, well they are already in order, they are just backwards of what we need. So we need to flip the order and we come up with:
2 1 3 4
So you need a method that does that sorting, and another method that calls that method in a loop until you have done the correct number of parameters.

Sort items with minimal renumber

I need to quickly save a re-ordered sequence back to my items' integer sortOrder columns.
The simple renumber-by-one approach can be slow - if last item moved to first, all N rows are modified. A multi-row update statement would let database do the work, but I'd like to explore smarter ways, like making sortOrder floating point except I don't have that option :(
The solution I imagine would take a renumbered list like this: (100,200,1700,300,400...1600,1800,...) and produce (100,200,250,300,400...1600,1800,...) (by modifying one row in this example). It seems simple at first, but I'm having a hard time expressing it in code...
Can someone help me with this logic? There could be sequences of adjacent items that need to be shifted for a new one to fit - I was hoping someone might have this already written? It has to be faster than what I have now, but still readable and simple to understand/maintain.
OK, after answer, posting back with resulting code I came up with (comments welcome):
/**
* Renumber list with minimal changes
*
* Given a list of SortOrderNumbers in the 'new' sequence they are to be saved in, determine the
* minimal set of changes (described by Change(i, newSortOrderNumber)) that can be saved that
* results in a properly ordered sequence.
*
* A simple answer would always be List(change<1,1>, change<2,2>, ...change<n,n>) which is of length N.
* This method returns a set of changes no larger than N (often much smaller for simple moves).
*
* #author Jim Pinkham
* #param s
* #return Set<Change>
*/
private Set<Change> renumber(int[] s) {
Set<Change> ret = new HashSet<Change>();
// pass1 goes from start forwards looking for decrease in numbering
for (int i=1; i<s.length; i++) {
// if predecessor of item is larger and it's large enough to renumber from start of list
if (s[i-1]>s[i] && s[i]>i) {
int beforeStart=0;
int beforeIndex=-1;
// go back towards start looking for anchor
for (int j=i-2; j>=0; --j) {
int diff = s[i]-s[j];
if (diff>(i-j)) {
beforeIndex=j;
beforeStart=s[beforeIndex];
break;
}
}
int diff = s[i]-beforeStart;
int stepsToDiff=i-beforeIndex;
int delta = diff/stepsToDiff;
// renumber from start of list or anchor thru decrease
int fixCnt=0;
for (int j=beforeIndex+1; j<i; ++j) {
s[j] = beforeStart + (delta*++fixCnt);
System.out.println("s["+j+"]="+s[j]);
ret.add(new Change(j, s[j]));
}
}
}
// pass1 could leave some decreases in sequence
// pass2 goes from end back to start
for (int i=s.length-1; i>0; i--) {
// if predecessor of item is larger
if (s[i-1] > s[i]) {
int afterIndex=s.length;
int delta=DEFAULT_RENUMBER_GAP;
// go back towards end looking for anchor
for (int j=i; j<s.length; ++j) {
int diff = s[j]-s[i-1];
if (diff>(j-(i-1))) {
afterIndex=j;
int afterEnd=s[afterIndex];
int stepsToDiff=afterIndex-(i-1);
int gap = afterEnd-s[i-1];
delta = gap/stepsToDiff;
break;
}
}
// renumber from decrease thru anchor or end of list
int fixCnt=0;
for (int j=i; j<afterIndex; ++j) {
s[j] = s[i-1] + (delta*++fixCnt);
System.out.println("s["+j+"]="+s[j]);
ret.add(new Change(j, s[j]));
}
}
}
return ret;
}
class Change {
int i;
int sortOrder;
Change(int i, int sortOrder) {
this.i=i; this.sortOrder=sortOrder;
}
public boolean equals(Change other) {
return Integer.valueOf(i).equals(Integer.valueOf(other.i));
}
public int hashCode() {
return Integer.valueOf(i).hashCode();
}
}
I'd like to explore smarter ways, like making sortOrder floating point except I don't have that option
If you find it easier to think of it in terms of floating point, why not imagine the number as fixed point.
e.g. for the purposes of your algorithm interpret 1000000 as 100.0000. You'll need to choose the point position so that there as many decimal (or binary) places as you can fit given (max number of items in your array+2) vs the integer size. So let's say the max number of entries is 998, you'd need 3 digits before the point, the rest would be available for 'gaps'.
A move operation then can be as simple as setting its new sortnumber to half the sum of the sortnumber of the items either side, i.e. slotting the moved item between its new neighbors. Use 0 and size(array)+1 as the end cases. Again I'm assuming that your UI can record the moves done by the user - regardless I think it should be fairly straightforward to work them out, and a standard sort algorithm could probably be used, just redefine 'swap'.
So for example moving last to first in this array (with imaginary decimal point):
1.0000
2.0000
3.0000
4.0000
5.0000
becomes
1.0000
2.0000
3.0000
4.0000
0.5000 = (0.0000 + 1.0000)/2
giving a sort order of
0.5000
1.0000
2.0000
3.0000
4.0000
Which changes just one record, the last one in the array
Moving last to second would do this:
1.0000
2.0000
3.0000
4.0000
5.0000
Becomes
1.0000
2.0000
3.0000
4.0000
1.5000 = (1.0000+2.0000)/2
resulting in a sort order of
1.0000
1.5000
2.0000
3.0000
4.0000
Again, just one record changed.
You will still need to cater for the case where you you run out of room 'between' two numbers, which you will eventually. I think this is true regardless of algorithm. This will require 'swap' to renumber more entries to make more room. Again regardless of algorithm I don't think you can rule out the case where everything has to be renumbered, it will just be very unlikely. I also suspect that extensive renumbers become more likely over time, again no matter what you do - the available space will fragment. However by choosing the position of the point to give as much room as possible, it should be optimal, i.e. you postpone that as long as possible.
To avoid having to do a more extensive renumber at an inconvenient time, it would probably be advisable to regularly do some kind of batch renumber during quiet periods - basically stretching the gaps again to make room for further user driven sorts. Again, I think you probably need this no matter what method you use.
This is just a sketch and I think it is probably equivalent to any other way of doing it, though perhaps a more intuitive/maintainable way of thinking about it and a way of maximising the room for expansion. Also if you're really worried about poor performance of degenerate cases - and from your description it sounds like you should be - I'd suggest to run whatever algorithm you go with in a test harness with a lot of random data (no database) over a long period, to see how many renumbers it really performs in practice and especially to see if it degrades with use over a long period. I suspect any algorithm for this will.
Following your example you could do something like this:
Walk your numbers array. If the successor of an item x is smaller than x itself walk the array backwards until you find the item y with the minimum difference between y and x+1. Count the steps you walked backwards, take the minimum distance, walk forewards from y and set the items to y+((x+1)-y)/count.
An additional level of indirection may help, e.g. implement a relocatable handle to each row in place of a row index. So instead of dealing with row[x], deal with row[handle[x]]
edit: ok so this is not possible in your situation...can you clarify then how much reordering you expect?
I gather from the phrasing of the question that you expect only M of N items to move, where M is significantly less than N. So you want to avoid N updates - you'd rather have something like M updates.
If M is less than N/2 then it should be faster to define the reordering in terms of swap operations. You don't say what your UI is, but the user is probably effectively doing swap operations there anyhow. So by recording those, or using a standard sort algorithm to get from the original state to the desired state, you should be able to generate the set of M swap operations needed to reorder the elements. That should only require M*2 row updates - i.e. if only two items trade places you need update only 2 rows.
There may be some degenerate cases where this is actually slower than just rewriting everything though - seems unlikely though if as implied by the question it is just the user reordering stuff.

Resources