Examples of common typical javascript algorithms and javascript instances
This example describes common javascript algorithms. We will share this with you for your reference. The details are as follows:
Entry-level algorithms-Linear search-Time complexity O (n)-equivalent to HelloWorld in the algorithm world
// Linear search (Getting Started HelloWorld) // A is an array, and x is the function linearSearch (A, x) {for (var I = 0; I <. length; I ++) {if (A [I] = x) {return I ;}} return-1 ;}
Binary Search(Also called semi-query)-applicable to linear structures with sorted orders-time complexity O (logN)
// Binary Search // A is an array sorted in ascending order, and x is the element to be queried // returns the subscript function binarySearch (A, x) of the target element) {var low = 0, high =. length-1; while (low <= high) {var mid = Math. floor (low + high)/2); // take the following integer if (x = A [mid]) {return mid;} if (x <A [mid]) {high = mid-1 ;}else {low = mid + 1 ;}} return-1 ;}
Bubble Sorting-- Time complexity O (n ^ 2)
// Bubble Sorting function bubbleSort (A) {for (var I = 0; I <. length; I ++) {var sorted = true; // note: the inner loop is inverted for (var j =. length-1; j> I; j --) {if (A [j] <A [j-1]) {swap (A, j, j-1 ); sorted = false ;}} if (sorted) {return ;}}}
Select sort-- Time complexity O (n ^ 2)
// Select sorting // train of thought: locate the bottom mark of the minimum value, and then switch function selectionSort (A) {for (var I = 0; I <. length-1; I ++) {var k = I; for (var j = I + 1; j <. length; j ++) {if (A [j] <A [k]) {k = j ;}} if (k! = I) {var t = A [k]; A [k] = A [I]; A [I] = t; println (A) ;}} return ;}
Insert sort-- Time complexity O (n ^ 2)
// Insert sorting // assuming that the elements before the current element have already sorted out their order, first empty their positions, // then move the elements that are later than themselves in turn, until A "pit" is empty, // Insert the target element into the "pit" function insertSort (A) {for (var I = 1; I <. length; I ++) {var x = A [I]; for (var j = I-1; j> = 0 & A [j]> x; j --) {A [j + 1] = A [j];} if (A [j + 1]! = X) {A [j + 1] = x; println (A) ;}} return ;}
String Inversion-- Time complexity O (logN)
// String inversion (for example, ABC-> CBA) function inverse (s) {var arr = s. split (''); var I = 0, j = arr. length-1; while (I <j) {var t = arr [I]; arr [I] = arr [j]; arr [j] = t; I ++; j --;} return arr. join ('');}
AboutStable sortingConclusion:
A simple Sorting Algorithm Based on comparison, that is, a sorting algorithm with a time complexity of O (N ^ 2), can generally be considered as a stable sorting algorithm.
Other advanced sorting algorithms, such as Merge Sorting, heap sorting, and bucket sorting (the time complexity of these algorithms can be optimized to n * LogN). Generally, they can be considered as unstable sorting.
Single-chain tableImplementation
<Script type = "text/javascript"> function print (msg) {document. write (msg);} function println (msg) {print (msg + "<br/>");} // Node class var Node = function (v) {this. data = v; // node value this. next = null; // successor node} // single-chain table var SingleLink = function () {this. head = new Node (null); // indicates that the header Node only occupies space and does not store the value. // Insert the Node this. insert = function (v) {var p = this. head; while (p. next! = Null) {p = p. next;} p. next = new Node (v);} // Delete the Node at the specified position this. removeAt = function (n) {if (n <= 0) {return;} var preNode = this. getNodeByIndex (n-1); preNode. next = preNode. next. next;} // obtain the nth node (the agreed header node is 0th) // when N is greater than the number of linked list elements, return the last element this. getNodeByIndex = function (n) {var p = this. head; var I = 0; while (p. next! = Null & I <n) {p = p. next; I ++;} return p;} // The node whose query value is V. // If there are multiple nodes with the same value in the linked list, // return the first found this. getNodeByValue = function (v) {var p = this. head; while (p. next! = Null) {p = p. next; if (p. data = v) {return p ;}} return null ;}// print the output of all nodes this. print = function () {var p = this. head; while (p. next! = Null) {p = p. next; print (p. data + "") ;}println ("") ;}// test whether duplicate element function hasSameValueNode (singleLink) {var I = singleLink exists in the single-chain table L. head; while (I. next! = Null) {I = I. next; var j = I; while (j. next! = Null) {j = j. next; if (I. data = j. data) {return true ;}}return false;} // function reverseSingleLink (singleLink) {var arr = new Array (); var p = singleLink. head; // run it again first and put all nodes into the array while (p. next! = Null) {p = p. next; arr. push (p. data);} var newLink = new SingleLink (); // traverse the array from the back to the front and add the new linked list for (var I = arr. length-1; I> = 0; I --) {newLink. insert (arr [I]);} return newLink;} var linkTest = new SingleLink (); linkTest. insert ('A'); linkTest. insert ('B'); linkTest. insert ('C'); linkTest. insert ('D'); linkTest. print (); // a B C D var newLink = reverseSingleLink (linkTest); newLink. print (); // d c B A </script>
AboutJoining matrix and joining tableSelect:
The basic storage methods of the adjacent matrix and the adjacent table are as follows,
Sparse chartIn this case (when the remote data is smaller than the vertex data), it is more suitable to store the data in an adjacent table (compared with N * N in a matrix, the adjacent table only stores the edge and vertex with values, and does not store null values, higher storage efficiency)
Dense GraphIn this case (in the case of remote vertices on the Earth), it is more suitable to use the adjacent matrix storage (in the case of a large amount of data, we need to traverse the larger, if you use the linked list storage, frequent jump and low efficiency)
Heap:
Almost Complete Binary Tree: Except one or several Binary Trees that may be missing leaves at the rightmost position. In physical storage, Arrays can be used for storage. If the vertex of A [j] has left and right subnodes, the left node is A [2j], the right node is A [2j + 1], and the parent vertex of A [j] is stored in A [j/2 ].
Heap:It is an almost complete binary tree, and the value of the parent node is not smaller than that of the child node. Application Scenario: priority queue, finding the maximum or maximum number of times, and inserting a new element into the priority queue.
Note: For all the following heap discussions, it is agreed that the element at index 0 only occupies space, and the valid element starts from subscript 1.
According to the definition of heap, you can use the following code to test whether an array is heap:
// Test whether array H is a heap. // (the agreed effective element starts from subscript 1) // time complexity O (n) function isHeap (H) {if (H. length <= 1) {return false;} var half = Math. floor (H. length/2); // according to the heap nature, the upper limit of the loop is only half enough for (var I = 1; I <= half; I ++) {// if the parent node is smaller than any other child node, if (H [I] <H [2 * I] | H [I] <H [2 * I + 1]) {return false ;}} return true ;}
Adjust siftUp from node to Node
In some cases, if the value of an element in the heap changes (for example, 10, 8, 9, 7 to 10, 8, 9, 20, and 20 need to be adjusted upwards), the heap definition is no longer met and needs to be adjusted upwards, use the following code to implement
// Move the node in the heap up // (the valid element starts from subscript 1) function siftUp (H, I) {if (I <= 1) {return ;} for (var j = I; j> 1; j = Math. floor (j/2) {var k = Math. floor (j/2); // finds that the child node is larger than the parent node, and exchanges the location with the parent node if (H [j]> H [k]) {var t = H [j]; H [j] = H [k]; H [k] = t;} else {// indicates that the heap definition has been met and the adjustment is complete, exit return ;}}}
Adjust the siftDown node downward (since there is an upward adjustment, naturally there are downward adjustments)
// Move down the node in the heap // (the effective element starts from subscript 1) // time complexity O (logN) function siftDown (H, I) {if (2 * I> H. length) {// leaf node, you do not need to move the return;} for (var j = 2 * I; j <H. length; j = 2 * j) {// locate j to the big one in the two subnodes (clever Practice) if (H [j + 1]> H [j]) {j ++;} var k = Math. floor (j/2); if (H [k] <H [j]) {var t = H [k]; H [k] = H [j]; H [j] = t;} else {return ;}}}
Add new elements to the heap
// Add element x to heap H // time complexity O (logN) function insert (H, x) {// train of thought: add the target element x H at the end of the array. push (x); // then push siftUp (H, H. length-1 );}
Delete element from heap
// Delete the element at the specified position I in heap H // time complexity O (logN) function remove (H, I) {// train of thought: first swap the element n at the position I with the element n at the last position // then reduce the Data Length by 1 (in this way, the element at the position I is killed, but the entire heap is destroyed) // you need to make a decision: whether the last element n needs to be adjusted upwards or downward. // basis: for example, if the element n is larger than the original one, it needs to be adjusted upwards, otherwise, adjust var x = H [I]. // first protect the elements in the original I position // put the last element in the I position // Delete the last element at the same time (the superiority of js language is reflected !) H [I] = H. pop (); var n = H. length-1; if (I = n + 1) {// if the removed element is exactly one of the last two elements, // No need to adjust return ;} if (H [I]> x) {siftUp (H, I) ;}else {siftDown (H, I );}} // Delete the shard entry from the heap // return the maximum value // O (logN) function deleteMax (H) {var x = H [1]; remove (H, 1 ); return x ;}
Heap sorting:
This is a clever sorting algorithm. The essence is to make full use of the characteristics of the "Heap" data structure itself (the first element must be the largest), and move up and down each element, the time retest is relatively low. It is only for O (logN), and there is no need to use additional storage space, just swap elements in the array itself.
Ideas:
1. First adjust the first element (I .e. the largest element) to the last element-the purpose is to sink the maximum value to the bottom, and the next round will no longer care about it.
2. After 1, the remaining elements are no longer a heap. At this time, as long as the new first element is lowered with siftDown, after the adjustment, the new maximum element naturally rises to the position of the first element.
3. Repeat steps 1 and 2. The large elements sink one by one, and the entire array is sorted.
Time Complexity analysis: the cost of O (n) is required to create a heap. The cost of siftDown is O (logN). A maximum of N-1 elements can be adjusted. Therefore, the total cost is O (N) + (N-1) O (logN), the final time complexity is O (NLogN)
// Move down the node in the heap // (the effective element starts from subscript 1) // I is the element index to be adjusted // n is the upper limit of the range of valid element subscript to be processed // time complexity O (logN) function siftDown (H, I, n) {if (n> = H. length) {n = H. length;} if (2 * I> n) {// leaf node, you do not need to move the return;} for (var j = 2 * I; j <n; j = 2 * j) {// locate j to the big one in the two subnodes (clever Practice) if (H [j + 1]> H [j]) {j ++;} var k = Math. floor (j/2); if (H [k] <H [j]) {var t = H [k]; H [k] = H [j]; H [j] = t;} else {return ;}}// create A heap for the first n elements of the array. function makeHeap (A, n) {if (n> =. length) {n =. length;} for (var I = Math. floor (n/2); I> = 1; I --) {siftDown (A, I, n) ;}// heap sorting (non-descending order) // time complexity O (nlogN) function heapSort (H) {// create a heap makeHeap (H, H. length); for (var j = H. length-1; j> = 2; j --) {// The first element must be the largest. // swap the largest element with the last element. // sink the largest element, in the next round, we will not consider var x = H [1]; H [1] = H [j]; H [j] = x; // After interchange, the remaining elements no longer meet the heap definition. // lower the new first element (to maintain the "shape" of the heap) // After adjustment, the maximum value of the remaining elements must be first. // enter the next round of siftDown (H, 1, j-1);} return H ;}
If you understand the principles of heap building, you can reverse the thinking.
function makeHeap2(A, n) { if (n >= A.length) { n = A.length; } for (var i = Math.floor(n / 2); i <= n; i++) { siftUp(A, i); }}
Search and merge non-intersecting sets
// Define the Node class var Node = function (v, p) {this. value = v; // node value this. parent = p; // The parent node of the node this. rank = 0; // rank of the node (0 by default)} // search for the root node var find = function (x) {var y = x; while (y. parent! = Null) {y = y. parent;} var root = y; y = x; // compress the path from x to the root while (y. parent! = Null) {// Save the parent node first. Otherwise, after the next line is adjusted, var w = y is lost. parent; // mount the target node to the root node y. parent = root; // restore the working pointer to the original parent node of the target node. // continue to compress layer-by-layer y = w} return root ;} // merge nodes x and y corresponding to two trees // time complexity O (m)-m is the number of child sets to be merged var union = function (x, y) {// first find the root var u = find (x) of the x collection; // then find the root var v = find (y) of the y collection ); // mount a small set of rank to a large set of rank if (u. rank <= v. rank) {u. parent = v; if (u. rank = v. rank) {// the rank of the two sets. // The rank value is equal to the limit. // The rank value is + 1 v. rank + = 1 ;}} else {v. parent = u ;}}
Induction:
First, let's look at the Recursive Implementation of the two orders.
// Recursive Implementation of sorting selection // call example: selectionSort ([3, 2, 1], 0) function selectionSortRec (A, I) {var n =. length-1; if (I <n) {var k = I; for (var j = I + 1; j <= n; j ++) {if (A [j] <A [k]) {k = j} if (k! = I) {var t = A [k]; A [k] = A [I]; A [I] = t;} selectionSortRec (, I + 1) ;}/// Recursive Implementation of insert sorting // call example: insertSortRec ([,], 3); function insertSortRec (A, I) {if (I> 0) {var x = A [I]; insertSortRec (A, I-1); var j = I-1; while (j> = 0 & A [j]> x) {A [j + 1] = A [j]; j --;} A [j + 1] = x ;}}
Recursive Programs are usually easy to understand and implement code. Let's look at two small examples:
Find the maximum value from the array
// Find the maximum value (Recursive Implementation) in the Array function findMax (A, I) {if (I = 0) {return A [0];} var y = findMax (A, I-1); var x = A [I-1]; return y> x? Y: x;} var A = [1, 3, 4, 5, 6, 7, 8, 9]; var test = findMax (A,. length); alert (test); // return 9
There is an array that has been sorted in ascending order. check whether there are two numbers in the array. Their positive number is x?
// 5.33 Recursive Implementation // A is [1 .. n] The sorted array // x is the sum of the two numbers to be tested and // returns true if the sum is x; otherwise, returns falsefunction sumX (A, I, j, x) {if (I> = j) {return false;} if (A [I] + A [j] = x) {return true ;} else if (A [I] + A [j] <x) {// I move return sumX (A, I + 1, j, x );} else {// j forward return sumX (A, I, j-1, x) ;}} var A = [1, 2, 3, 4, 5, 6, 7, 8]; var test1 = sumX (A, 0,. length-1, 9); alert (test1); // return true
Although recursive Programs have clear ideas, they are generally inefficient. Generally, recursive implementations can be rewritten to non-recursive implementations. The above code can also be written as follows:
// 5.33 non-recursive function sumX2 (A, x) {var I = 0, j =. length-1; while (I <j) {if (A [I] + A [j] = x) {return true ;} else if (A [I] + A [j] <x) {// I move back I ++;} else {// j move forward j -- ;}} return false ;} var A = [1, 2, 3, 4, 5, 6, 7, 8]; var test2 = sumX2 (A, 9); alert (test2); // return true
Recursion does not always mean inefficiency. In some scenarios, recursion is more efficient. For example, to calculate the m power of x, a conventional algorithm requires m multiplication. The following algorithm, however, the time complexity is reduced to O (logn)
// Calculate the m power of x (Recursive Implementation) // time complexity O (logn) function expRec (x, m) {if (m = 0) {return 1 ;} var y = expRec (x, Math. floor (m/2); y = y * y; if (m % 2! = 0) {y = x * y} return y ;}
Of course, this is not just the credit of recursion, but its efficiency improvement mainly depends on a mathematical knowledge: x ^ m = [x ^ (m/2)] ^ 2, there is also a unique non-recursive solution that cleverly utilizes the binary features.
// Convert the decimal number to the binary function toBin (dec) {var bits = []; var dividend = dec; var remainder = 0; while (dividend> = 2) {remainder = dividend % 2; bits. push (remainder); dividend = (dividend-remainder)/2;} bits. push (dividend); bits. reverse (); return bits. join ("");} // calculate the m power of x (non-Recursive Implementation) // a unique solution function exp (x, m) {var y = 1; var bin = toBin (m ). split (''); // first convert m to a binary form for (var j = 0; j <bin. length; j ++) {y = y * 2; // If the j-digit of the binary system is 1, then * x if (bin [j] = "1") {y = x * y} return y;} // println (expRec (2, 5 )); // println (exp (2, 5 ));
Let's take a look at the classicPolynomial EvaluationProblem:
Given a string of real numbers An, An-1,..., A1, A0 and a real number X, calculate the value of the polynomial Pn (x ).
The famous Horner formula:
How to calculate:
Apparently there are:
In this way, only N multiplication + N addition are required.
// Polynomial evaluate // N times of multiplication + N times of addition, great improvement! Function horner (A, x) {var n =. length-1 var p = A [n]; for (var j = 0; j <n; j ++) {p = x * p + A [n-j-1];} return p;} // calculation: y (2) = 3x ^ 3 + 2x ^ 2 + x-1; var A = [-1, 1, 2, 3]; var y = horner (A, 2 ); alert (y); // 33
Most problems:
An array with n as the number of elements, and you want to quickly find the elements with more than the number of occurrences> n/2 (this element is also called a majority element ). It is usually used in the ballot paper system to quickly determine whether a candidate has more than half of the votes. The optimal algorithm is as follows:
// Find out the function candidate (A, m) {var count = 1, c = A [m], n =. length-1; while (m <n & count> 0) {m ++; if (A [m] = c) {count ++ ;} else {count -- ;}}if (m = n) {return c;} else {return candidate (A, m + 1 );}} // search for most elements // time complexity O (n) function majority (A) {var c = candidate (A, 0); var count = 0; // find c, it may be A majority of elements, or it may not, // it must be repeated to ensure that the result is correct for (var I = 0; I <. length; I ++) {if (A [I] = c) {count ++ ;}// if it is more than half, the element if (count> Math. floor (. length/2) {return c;} return null;} var m = majority ([3, 2, 3, 3, 4, 3]); alert (m );
The above algorithm is based on the conclusion that after two different elements are removed from the original sequence, the majority of elements in the original sequence are still the majority of elements in the new sequence.
The proof is as follows:
If the number of elements in the original sequence is n and the number of most elements is x, then x/n> 1/2
After removing two different elements,
A) if the removed element does not include a majority of elements, then in the new sequence, the original majority of elements/total number of new sequence elements = x/(n-2 ), because x/n> 1/2, So x/(n-2) also inevitably> 1/2
B) if the removed element contains a majority of elements, then in the new sequence, the original majority of elements/total number of new sequence elements = (x-1)/(n-2 ), because x/n> 1/2 =, x> n/2 is substituted into (x-1)/(n-2,
Available (x-1)/(n-2)> (n/2-1)/(n-2) = 2 (n-2)/(n-2) = 1/2
Next question:Full Arrangement
Function swap (A, I, j) {var t = A [I]; A [I] = A [j]; A [j] = t ;} function println (msg) {document. write (msg + "<br/>");} // function perm (P, m) {var n = P. length-1; if (m = n) {// output println (P); return ;}for (var j = m; j <= n; j ++) {// swap (P, j, m) is exchanged between the starting element and each element following it ); // based on the preceding m elements, // Add another element to arrange the perm (P, m + 1); // replace j and m, restore the "field" before recursive calling. // otherwise, swap has destroyed the original sequence before recursive calling. // duplicate swap (P, j, m) ;}} perm ([1, 2, 3], 0); //, 3/, 2/, 3/2, 1 // 3, 2, 1 // 3, 1, 2
Divide and conquer Law:
Key point: when dividing a problem into two sub-problems, try to make the sub-problems roughly the same scale. In this way, we can maximize the advantages of dividing the problem into two parts and reducing the problem scale by a logarithm.
// Print the output (for debugging) function println (msg) {document. write (msg + "<br/>");} // element exchange at the position of I and j in the array (Auxiliary function) function swap (A, I, j) {var t = A [I]; A [I] = A [j]; A [j] = t ;} // find the maximum and minimum values in array A (implemented by Division and Control) function findMinMaxDiv (A, low, high) {// minimum scale subproblem solution if (high-low = 1) {if (A [low] <A [high]) {return [A [low], A [high];} else {return [A [high], A [low];} var mid = Math. floor (low + high)/2); // find the subproblem solution in the first half of the elements var r1 = f IndMinMaxDiv (A, low, mid); // find the subproblem solution in the last half of the element var r2 = findMinMaxDiv (A, mid + 1, high ); // merge the two parts. var x = r1 [0]> r2 [0]? R2 [0]: r1 [0]; var y = r1 [1]> r2 [1]? R1 [1]: r2 [1]; return [x, y];} var r = findMinMaxDiv ([1, 2, 3, 4, 5, 6, 7, 8], 0, 7); println (r); // binary search (implemented by the Division and Control Law) // input: A is an array that has been arranged in non-descending order. // x is the value to be searched. // low is the index range starting from and ending from the high search. // return: if it is found, the subscript is returned, otherwise, the-1 function binarySearchDiv (A, x, low, high) {if (low> high) {return-1;} var mid = Math. floor (low + high)/2); if (x = A [mid]) {return mid;} else if (x <A [mid]) {return binarySearchDiv (A, x, low, mid-1);} e Lse {return binarySearchDiv (A, x, mid + 1, high) ;}}var f = binarySearchDiv ([1, 2, 3, 4, 5, 6, 7], 4, 0, 6); println (f); // 3 // set array A to the bounded element at the low position, divided into the front and back half // n is the upper limit of the index range to be processed function split (A, low, n) {if (n> =. length-1) {n =. length-1 ;}var I = low; var x = A [low]; // two pointers are followed by one pointer ", // The pointer at the beginning finds that there is an element hour than the dividing element, and changes it to the first half. // the pointer at the end is followed up, and the "Fu Changfu with you" goes all the way to the header for (var j = low + 1; j <= n; j ++) {if (A [j] <= x) {I ++; if (I! = J) {swap (A, I, j) ;}}// after the above tossing, except for the low element, all other elements are in place. // finally, we need to exchange low with the last element smaller than low. // we can place low at the watershed position. swap (A, low, i); return [A, I];} var A = [5, 1, 2, 6, 3]; var B = split (A, 0,. length-1); println (B [0]); //, 6 // quick sort function quickSort (A, low, high) {var w = high; if (low
Application of the split Algorithm:
Set A [1 .. n] is an integer set. An algorithm is given to rearrange the elements in array A so that all negative integers are placed on the left of all non-negative integers. The running time of your algorithm should be round (n)
function sort1(A) { var i = 0, j = A.length - 1; while (i < j) { if (A[i] >= 0 && A[j] >= 0) { j--; } else if (A[i] < 0 && A[j] < 0) { i++; } else if (A[i] > 0 && A[j] < 0) { swap(A, i, j); i++; j--; } else { i++; j--; } }}function sort2(A) { if (A.length <= 1) { return; } var i = 0; for (var j = i + 1; j < A.length; j++) { if (A[j] < 0 && A[i] >= 0) { swap(A, i, j); i++; } }}var a = [1, -2, 3, -4, 5, -6, 0];sort1(a);println(a);//-6,-2,-4,3,5,1,0var b = [1, -2, 3, -4, 5, -6, 0];sort2(b);println(b);//-2,-4,-6,1,5,3,0
I hope this article will help you design JavaScript programs.