SCRIPTING:

Salma Hayek
IN-SORTER BINARY ALGORITHM:
HOW TO INCLUDE AN ENTRY IN A SORTED ARRAY

Given an array which already underwent a sorting process, either with higher value now on top or on bottom of it, this script inserts an additional entry into the array grabbing the right level to place it in the given array, no matter how long.
More or less, can detect it in 20 moves on a 1,000,000 entries array.

December 2001
{ @ }



Preliminary steps
Things you have to be sure of prior to whatever running of this script, and the codes of the two subroutines that accomplish the full insorting process

What must be understood when dealing with a process like an in-sorter (including an entry in the right location in within a sorted array) is that this array has to have undergone a sorting process previous to whatever attempt to include a further entry.
This is critical since otherwise you'd certainly get a bad error. Also, you must be sure that the sorting process has been an appropriate one: if you just sort an array, it won't be sorted right. If you want to know more and get avail of two small snippets that can instruct a javascript sorting process to be performed right, you can click here and grab the highestFirst & highestLast subroutines over there, almost top of page.
On the other hand, this script won't bother you to know whether you've sorted in one order or the other, it will guess it by its own.

Now your code: it is made up of two functions: the first is the insorter, the second is just a re builder which, once the insorter has produced the index level at which the entry should be inserted, uses it to actually insert the array.

Pamela Anderson
Mondrian

function insorter(array, N){
//4 out of boundary exceptions first:
 if(array[0]>=N&&
array[0]<=array[array.length-1]){//sorted 0..x cases:
return -1}
 else if(array[array.length-1]<=N&&
array[0]<=array[array.length-1]){
return array.length-1}
 else if(array[0]<N&&
array[0]>array[array.length-1]){//sorted x..0 cases:
return -1
}
 else if(array[array.length-1]>N&&
array[0]>array[array.length-1]){
return array.length-1
};
//initialize:
var snip=array;
var End=snip.length-1;
var M=parseInt(End/2);
var dir;
var i=0;
//starts algorhitm's core:
 if(array[0]<=array[array.length-1]){//original array: higher was at index [array.length-1]
   while(snip.length>2){
   var prevLength=snip.length;
    if(snip[M]>N){
    snip=snip.slice(0,M+1);
    dir=-1
    }
    else if(snip[M]<N){
    snip=snip.slice(M,End+1);
    dir=1
    };
   End=snip.length-1;
   M=((End/2)<1)?0:parseInt(End/2);//could have been: M=parseInt(End/2);
   i+=(dir<0)?0:(prevLength-snip.length);
    if(snip[M]==N){return i+M}
   }
 }
 else{//original array: higher was at index [0]
   while(snip.length>2){
   var prevLength=snip.length;
    if(snip[M]<N){
    snip=snip.slice(0,M+1);
    dir=-1
    }
    else if(snip[M]>N){
    snip=snip.slice(M,End+1);
    dir=1
    };
   End=snip.length-1;
   M=((End/2)<1)?0:parseInt(End/2);//could have been: M=parseInt(End/2);
   i+=(dir<0)?0:(prevLength-snip.length);
    if(snip[M]==N){return i+M}
   }
 }
return i
/*keep this comment to reuse freely
http://www.unitedscripters.com */}

function allocateEntry(array, entry, position){
/*returns a COPY of array
for javaScript use
requires gen 4 browsers, using built in methods:
push(), unshift(), concat(), slice()
accepts: allocateEntry(array, N, insorter(array, N))
*/
var overall;
//out of boundary exceptions:
if(position<0){//case: -1
overall=array;
overall.unshift(entry);
return overall
}
else if(position>=array.length-1) {//case: too high
overall=array;
overall.push(entry);
return overall;
Pamela Anderson
};
//start:
var first, second;
first=array.slice(0,position+1)
first[(++first.length)-1]=entry
overall=first.concat( array.slice( position+1, array.length))
return overall
/*keep this comment to reuse freely
http://www.unitedscripters.com */}


How the algorithm works
I have tested it in several cases and seems pretty smooth. it combines binary search with insorting.

You may know that a binary search is
Mondrian
a search of an entry in an array which is performed halving more and more the array until the required entry is found: it presumes the array has been sorted, and checks its middle point: if it is higher than the required value we're searching for, it grabs the first half and halves it again and makes the same check until it finds, within a range two entries long, the required instance (or, on the other hand, if middle point is lower that the required value, the algorithm based on a binary approach grabs the second half of the array and halves it again and checks wether the desired entry might be in the first or second half and goes on until either it finds it, or it does not find it and in such case returns a false value).
The great advantage is that such an approach can easily inspect even the longest arrays in a minimal amount of cycles.
This approach could be used also when determining where to insert an entry (insorting process). Normally I saw insorters performed entry by entry, but I think the binary approach can match and fit it perfectly.

Here is how this algorithm works, and if you find it is uncorrected, please email me (email gif at top of page):

  1. Insorter: gets two arguments:
    1. the array argument to check for inserting the object, and which has to be already and appropriately sorted
    2. the N argument which has to be either a string or a number, and is the object which we have to insert in the array.
  2. We first deal with the possible out of boundaries exceptions: those cases when the N argument immediately exceeds the limits of the array:
    1. Is the array sorted with smaller at top [0]?
      • If position [0] is already bigger (or equal) than N, means that also all the subsequent entries are: we return -1 to flag that the position of this N object should be even before the [0] entry. Correct, convincing?
      • If the position at the other side of the array is, on the other hand, smaller than N, means that all the entries of the array are smaller than N, so we return the length of the array less one, to flag the N object should go after this position: you can already understand that all our returns are shaped in order to mean: include N in the slot AFTER this number.
    2. Is the array sorted with the higher at top [0]?
      • If what is at [0] is smaller than N, means that all subsequent entries are smaller than N, since the higher is at [0] in this array: so we return -1 to flag this should go before everything.
      • You can easily deduce the last case on your own!
  3. WE now initialize objects: snip will hold the decreasing halves of the array while
    Mondrian
    the algorithm's core starts being engaged; End will determine the last entry of the snip which will play the role of ending entry of the subsequent snip, and at the first stage this length is the length of the array itself, its last entry that is (length-1); M will get the middle, with a parseInt to avoid decimal values; dir will help to determine what the value of i should be; i will keep track of the level we're at translating it into the corresponding level of the original array: in fact when we want to determine where we have to insert something in an array, and we half it little by little, we have to store somewhere a variable that will deduce from the current segment (snip) we're dealing with, its corresponding position in the original array: we chose to keep track of the beginning of the snip (that is: if, say, the current snip[0] value is 435, we store in i the position in the original array where 435 occurred: all this is critical to return a value that has a meaning for the original array, and not just an index of a fragment which would mean nothing for the original array).
  4. WE now split the algorithm, in two conditional statement and two different while loops: one, the first, for arrays where the smallest value is at position [0], and another different loop for those cases when the first value at index [0] in the array is the higher.
  5. Now starts the loop: the while loop will stop when the snip length will be equal to two, since this would mean we've found the last two entries the first of which is higher than N and the subsequent of which, close to the first, was lower than N.
  6. Inner proceedings of the while cycle:
    1. prevLength stores the length of the current snip (at first run, is the length of the array itself)
    2. Now we check if the middle (M) position of snip is higher than N: if so we should grab the first half of the divided array, since if M>N, then means that somewhere at --M must be a possible position for N. So, we change the inspected snip to a subsection of the current one, which will have its starting point at [0] and its tail at M (we say M+1 since the slice() method in javaScript excludes the second parameter, but we want to include it).
      We set variable dir to -1 to flag we're moving backward.
    3. On the other hand, we check if the middle (M) position of snip is lower than N: if so we must fetch the second half of the divided array, since if M<N, then means that somewhere at ++M must be a possible position for N. So, we change the inspected snip to a subsection of the current one, which will have its starting point at [M] and its tail at the length of the snip itself which is stored in End (we say End+1 since the slice() method in javaScript excludes the second parameter, but we want to include it).
      We set variable dir to 1 to flag we're moving backward
    4. Once we have shortened the segment (snip) we have to update all the variables: End is now the End of this new segment and M has to be recalculated on this new segment too, ok? I hope it is convincing. To may eyes it was.
    5. We now have to keep track of what the current position [0] in the current segment would be in the original array: I found that it is an issue only if we move upward and not backward: if you move backward (in the first half) what is a position, say, [5] is still what is at position 5 in the original array: but if you move upward (second half) what is now at position [0] of the newly yielded segment (snip) is not at all what is at pos[0] in the original array, but it is what is at the current value of i (zero, at first) plus the length of the segment we've just excluded, cut off to produce the halves: thus the correct position in the original array would be the length of the previous segment less the length of the current segment: we have to add this value to i at all times the algorithm picks the upward half. I hope it is convincing. To my eyes it was.
    6. Finally, if by chance the M point is right equal to the N object, we return i taking care of adding M (and here I am a bit less persuaded: on my tests worked smoothly, and I am convinced, but maybe I am just not self-confident enough)
    7. The second while for the second case is simply the inverse of the first.
    8. I won't bother too much commenting the second subroutine: it is just what uses the index which insorter produces to dispatch it into the relative slot in the original array. A possible invocation could be contextual for the two subroutines:
      var myArray=new Array(1,2,3,4,5,6,7,8,9,11,12)
      /*suppose you want to insert 8 (already there, I know: suppose you want to add one. Also, note 10 is missing, for your test below)*/
      allocateEntry(myArray, 8, insorter(myArray, 8))

Insert in array above the desired value: