Js Code sorting
Call apply bind new mock implementation
/** call a function with a specified value of this Execute function 3. Delete the object property */
Function.prototype.newCall = function(){
if(typeof this! = ='function') throw new Error('no function')
var context = arguments[0] | |window
context.fn = this
var args = []
for(var i = 1; i < arguments.length; i++){
args.push(arguments[i])
}
var result = eval('context.fn(' + args + ') ')
delete context.fn
return result
}
Copy the code
/* Call a function with a specified value of this Execute function 3. Delete the object property */
Function.prototype.newApply = function(){
if(typeof this! = ='function') throw new Error('no function')
var context = arguments[0] | |window
context.fn = this
var args = arguments[1[]] | |var result = eval('context.fn(' + args + ') ')
delete context.fn
return result
}
Copy the code
/* Create a new function, and use the first argument as this to run the new function. F(); F(); F(); F(); F(); F(); Change the return function's prototype to the binding function's prototype so that the instance inherits the binding function's prototype 5. 6. Self.apply (this instanceof F? This: context, arg) 'whether new call ', this instanceof fBound" */
Function.prototype.newBind = function(){
if(typeof this! = ='function') throw new Error('no function')
var context = arguments[0] | |window
var fn = this
var args = []
for(let i = 1; i < arguments.length; i++) args.push(arguments[i])
var bind = function(){
for(let i = 0; i < arguments.length; i++) args.push(arguments[i])
context = this instanceof bind ? this : context
return fn.apply(context, args)
}
var F = function(){}
F.prototype = this.prototype
bind.prototype = new F()
return bind
}
Copy the code
O 2. Construtor is a constructor imported externally 3. O.__proto__ = Construtor.prototype 4 = Construtor. Apply (O, the arguments) use a constructor to obj set properties 5. Ret | | O always returns an object * /
function New(){
var obj = new Object(a);var Constructor = Array.prototype.shift.call(arguments)
obj.__proto__ = Constructor.prototype
let ret =Constructor.apply(obj, arguments)
return typeof ret === 'object' ? ret : obj
}
Copy the code
If the throttle
/* Execute after N seconds, no matter how many times the timer is fired. 3. Within the function, set timer 4. Returns a wrapped function */
function debounce(fn, wait, immediate) {
var timeout, result
var debounced = function(){
var context = this
var args = arguments
// If it exists, cancel and wait for seconds before calling again
if(timeout) clearTimeout(timeout)
if(immediate){
// Trigger immediately
// If it has not been triggered, it is triggered directly
varcaller = ! timeout timeout =setTimeout(function(){
timeout = null
}, wait)
if(caller) result = fn.apply(context, args)
}else{
timeout = setTimeout(function(){
result = fn.apply(context, args)
timeout = null
}, wait)
}
return result
}
/ / cancel
debounced.cancel = function(){
if(timeout) clearTimeout(timeout)
timeout = null
}
return debounced
}
Copy the code
/* Execute only once, no matter how many times in a period of time You can set the current timestamp + time interval to control whether the event */ is triggered
// The timestamp implementation will execute immediately, and there is no way to execute the event after stopping the trigger
function throttle(fn, wait){
var prev = 0
var throttled = function(){
var now = +new Date(a)var context = this
var args = arguments
if(now - prev > wait){
fn.apply(context, args)
prev = now
}
}
return throttled
}
// The timer is executed for the first time after n seconds, and the event is executed again after the trigger is stopped
function throttle(fn, wait){
var timeout
var throttled = function(){
var context = this
var args = arguments
if(! timeout){ timeout =setTimeout(function(){
timeout = null
fn.apply(context, args)
}, wait)
}
}
return throttled
}
/ * * * *@param {function} Fn Execution method *@param {number} Wait Wait time *@param {} configuration Options Leading: Whether to allow immediate execution of trailing: Whether to allow the last execution of *@returns * /
function throttle(fn, wait, options) {
options = options || {}
var result, context, args, timeout
var prev = 0
var later = function(){
prev = options.leading === false ? 0 : +new Date()
timeout = null
result =fn.apply(context, args)
}
var t = function(){
var now = +new Date() prev = ! prev && options.leading ===false ? now : prev
var r = wait - (now - prev)
context = this
args = arguments
if(r > wait || r <= 0) {if(timeout){
clearTimeout(timeout)
timeout = null
}
prev = now
result = fn.apply(context, args)
}else if(! timeout && options.trailing ! = =false){
timeout = setTimeout(later, r)
}
return result
}
t.cancel = function(){
clearTimeout(timeout)
timeout = null
prev = 0
}
return t
}
Copy the code
promise
// Three states
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
// State: the initial state is pending
status = PENDING
/ / value
value = null
/ / reasons
reason = null
// Execute the onFulfilled queue
onFulfilledCallbacks = []
// Execute the onRejected queue
onRejectedCallbacks = []
// The constructor
constructor(executor){
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
resolve = value= > {
// Check whether the state is in the wait state
if(this.status === PENDING){
// Change the state
this.status = FULFILLED
/ / assignment
this.value = value
// Loop call
while(this.onFulfilledCallbacks.length){
this.onFulfilledCallbacks.shift()(this.value)
}
}
}
reject = reason= > {
// Check whether the state is in the wait state
if(this.status === PENDING){
// Change the status
this.status = REJECTED
// Assignment reason
this.reason = reason
// Loop call
while(this.onRejectedCallbacks.length){
this.onRejectedCallbacks.shift()(this.reason)
}
}
}
then(onFulfilled, onRejected){
// This parameter is optional
const realOnFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value= > value
const realOnRejected = typeof onRejected === 'function' ? onRejected : reason= > { throw reason }
const promise1 = new MyPromise((resolve, reject) = > {
// Create a function to complete the microtask
const fulfilledMicrotask = () = > {
queueMicrotask(() = > {
try{
let x = realOnFulfilled(this.value)
resolvePromise(promise1, x, resolve, reject)
}catch (error) {
reject(error)
}
})
}
// Create a microtask to execute the rejected function
const rejectMicrotask = () = > {
queueMicrotask(() = > {
try{
let x = realOnRejected(this.reason)
resolvePromise(promise1, x, resolve, reject)
}catch (error) {
reject(error)
}
})
}
// Execute directly after the status is determined
if(this.status == FULFILLED){
fulfilledMicrotask()
}else if(this.status == REJECTED){
rejectMicrotask()
}else{
// Asynchronously, join the queue
this.onFulfilledCallbacks.push(fulfilledMicrotask)
this.onRejectedCallbacks.push(rejectMicrotask)
}
})
// then returns a new promise
return promise1
}
/ / catch method
catch (onRejected) {
this.then(null, onRejected)
}
// The finally() method is used to specify an action that will be performed regardless of the final state of the Promise object
finally(fn) {
return this.then(value= > {
return MyPromise.resolve(fn()).then(() = > {
return value
})
}, reason= > {
return MyPromise.resolve(fn()).then(() = > {
return reason
})
})
}
Sometimes it is necessary to turn an existing object into a Promise object with the state fulfilled
static resolve(parameter){
// If a promise object is passed, return it directly
if(parameter instanceof MyPromise){
return parameter
}
return new MyPromise(resolve= > {
resolve(parameter)
})
}
// The promise.reject (reason) method also returns a new Promise instance with the state rejected
static reject(reason){
return new MyPromise((resolve, reject) = > {
reject(reason)
})
}
// the all method returns when all is successful
static all(promiseList){
return new MyPromise((resolve, reject) = > {
let count = 0
let length = promiseList.length
let result = []
if(length === 0) return resolve(result)
for(let i = 0; i < length; i++){
MyPromise.resolve(promiseList[i]).then(value= > {
count++
results[i] = value
// All successful
if(count === length) resolve(result)
}, reason= > {
// A failure
reject(reason)
})
}
})
}
// The race method returns after only one success
static race(promiseList){
return new MyPromise((resolve, reject) = > {
let length = promiseList.length
if(length === 0) return resolve()
for (let i = 0; i < length; i++) {
MyPromise.resolve(promiseList[i]).then(value= > {
return resolve(value)
}, reason= > {
return reject(reason)
})
}
})
}
// Take a set of Promise instances as parameters and wrap it into a new Promise instance. Until all of these parameter instances have returned results,
static allSettled(promiseList){
return new MyPromise((resolve, reject) = > {
let count = 0
let length = promiseList.length
let result = []
if(length === 0) return resolve(result)
for (let i = 0; i < length; i++) {
MyPromise.resolve(promiseList[i]).then(value= > {
count++;
result[i] = {
value,
status: FULFILLED
}
if(count === length) resolve(result)
}, reason= > {
count++;
result[i] = {
reason,
status: REJECTED
}
if(count === length) resolve(result)
})
}
})
}
}
function resolvePromise(promise, x, resolve, reject){
if(x === promise){
// Call in a loop and report an error directly
return reject(new TypeError('The promise and the return value are the same'));
}
if(typeof x === 'function' || typeof x === 'object') {// null returns directly
if(x === null) return resolve(x)
let then
try {
then = x.then
} catch (error) {
// There is no direct rejection
return reject(error)
}
// If the object has a THEN method
if(typeof then === 'function') {let called = false
try {
then.call(x, y= > {
// Ignore multiple times
if(called) return
called = true
// Then execute
resolvePromise(promise, y, resolve, reject)
}, r= > {
// Ignore multiple times
if(called) return
called = true
reject(r)
})
} catch (error) {
//
if(called) return
called = true
reject(error)
}
}else{
// Then is not a function
resolve(x)
}
}else{
// If x is not an object or function, execute the promise with x as the argument
resolve(x)
}
}
Copy the code
curry compose pipe partial
// add(1, 2, 3) => add = curry(add) add(1, 2, 3) = add(1)(2)(3) = add(1)(2, 3) = ...
function curry(fn, args){
var length = fn.length
args = args || []
return function(){
var _args = args.slice().concat(Array.prototype.slice.call(arguments))
if(_args.length < length){
return curry.call(this, fn, _args)
}else{
return fn.apply(this, _args)
}
}
}
Copy the code
// a(b(c(d))) => compose(c, b, a)(d)
function compose(){
var args = arguments
var start = args.length
return function(){
var result = args[--start].apply(this.arguments)
while(start--) result = args[start].call(this, result)
return result
}
}
Copy the code
// a(b(c(d))) => pipe(a, b, c)(d)
function pipe(){
var args = arguments
var start = 0
return function(){
var result = args[start++].apply(this.arguments)
while(start < args.length){
result = args[start++].call(this, result)
}
return result
}
}
Copy the code
// partial(func, _, 'b', _, 'd')('a', 'c')
var _ = {}
function partial(){
var fn = arguments[0]
var args = Array.prototype.slice.call(arguments.1)
var bind = function(){
var position = 0
_args = args.slice(0)
var len = _args.length
for(var i = 0; i < len; i++){
_args[i] = _args[i] === _ ? arguments[position++] : _args[i]
}
while(position < arguments.length) _args.push(arguments[position++])
return fn.apply(this, _args)
}
inherit(fn, bind)
return bind
}
function inherit(parent, child){
var F = function(){}
F.prototype = parent.prototype
child.prototype = new F()
}
Copy the code
Publish and subscribe to the EventEmitter & Observer pattern Observer
/* The sender of a one-to-many message (called a publisher) does not send the message directly to a specific receiver (called a subscriber). Instead, the published messages are divided into different categories and sent separately to different subscribers. * /
class EventEmitter{
constructor(){
this.cache = {}
return this
}
on(type, event){
if(!this.cache[type]) this.cache[type] = []
if(this.cache[type].indexOf(event) == -1) {this.cache[type].push(event)
}
return this
}
off(type, event){
if(!this.cache[type]) return this
this.cache[type] = this.cache[type].filter(e= >e ! == event)return this
}
once(type, event){
let _event = function(){
event.apply(this.arguments)
this.off(type, _event)
}
this.on(type, _event)
return this
}
emit(){
let type = arguments[0]
let args = Array.prototype.slice.call(arguments.1)
let list = this.cache[type] || []
for (const event of list) {
event.apply(this, args)
}
return this}}Copy the code
/* Observer mode, which defines a one-to-many relationship in which multiple observer objects listen to a topic object at the same time. When the topic object's state changes, all observer objects are notified so that they can automatically update themselves. There are two main roles in the Observer pattern: Subject and Observer. * /
class Observer {
constructor(name){
this.name = name
}
notify(){
console.log(`The ${this.name} has been notified`)}}class Subject {
observers = []
addObserver(observer){
console.log(observer.name, 'is push')
this.observers.push(observer)
}
deleteObserver(observer){
console.log('remove observer: ', observer.name)
this.observers = this.observers.filter(o= >o ! == observer) }notifyObservers(){
console.log('notify')
this.observers.forEach(o= > o.notify())
}
}
Copy the code
inherit
/** * Prototype === new Parent * child.__proto__.constructor === Parent */
function Parent(){
this.name = 'Parent'
}
Parent.prototype.say = function(){
console.log(this.name)
}
function Child(){
}
Child.prototype = new Parent()
var child = new Child()
console.log(child.__proto__ === Child.prototype) // true
console.log(child.__proto__.constructor === Parent) // true
child.say()
Copy the code
/** * Borrow constructor inheritance * advantages ** avoids the problem of reference types being shared * Child can pass arguments to Parent * disadvantages * Every time an instance is created, the Parent method is created * child-.__proto__ === child-.prototype * child.__proto__.constructor === Child */
function Parent(name){
this.name = name
this.say = function(){
console.log(this.name)
}
}
function Child(){
Parent.apply(this.arguments)}var child = new Child('child')
console.log(child.__proto__ === Child.prototype) // true
console.log(child.__proto__.constructor === Child) // true
child.say() // child
Copy the code
/** * Composite pattern * advantages: * avoids the need for references to be shared * no need to create methods repeatedly * Disadvantages: * Requires more new times */
function Parent(name){
this.name = name
}
Parent.prototype.say = function(){
console.log(this.name)
}
function Child(name){
Parent.apply(this.arguments)
}
Child.prototype = new Parent()
Child.prototype.constructor = Child
var child = new Child('child')
console.log(child.__proto__ === Child.prototype) // true
console.log(child.__proto__.constructor === Child) // true
child.say() // child
Copy the code
/** * Prototype inheritance * Defects * Reference type sharing * child.__proto__ === parent * child.__proto__
function CreateObj(o){
function F(){}
F.prototype = o
return new F()
}
var parent = {
name: 'parent'.say: function(){
console.log(this.name)
}
}
var child = CreateObj(parent)
child.say()
console.log(child.__proto__ === parent)
console.log(child.__proto__.constructor === Object)
Copy the code
/** * Parasitic inheritance * creates a function that only encapsulates the inheritance process, internally making the enhanced object in some form, and finally returning the object. * /
function CreateObj(o){
function F(){}
F.prototype = o
return new F()
}
var parent = {
name: 'parent'.say: function(){
console.log(this.name)
}
}
var Child = function(o, name){
var clone = CreateObj(o)
clone.name = name
return clone
}
var child = Child(parent, 'child')
child.say()
console.log(child.__proto__ === parent)
console.log(child.__proto__.constructor === Object)
Copy the code
/** * Parasitic combinative inheritance * benefits * Calls the constructor of the Parent class only once * avoids creating unnecessary properties on parent-. prototype * the prototype chain remains unchanged; Therefore, instanceof and isPrototypeOf */ can also be used normally
function inherit(Child, Parent){
function F(){}
F.prototype = Parent.prototype
Child.prototype = new F()
Child.prototype.constructor = Child
}
function Parent(name){
this.name = name
}
Parent.prototype.say = function(){
console.log(this.name)
}
function Child(){
Parent.apply(this.arguments)
}
inherit(Child, Parent)
var child = new Child('child')
child.say()
console.log(child.__proto__ === Child.prototype)
console.log(child.__proto__.constructor === Child)
Copy the code
create object
/* The factory function can take arguments to build an object containing the necessary information. It can be called an infinite number of times. While returning one object at a time advantages: batch generation of similar objects disadvantages: objects point to the same prototype, generated objects cannot recognize each method needs to be created once */
function factory(name, age){
var o = new Object()
o.name = name
o.age = age
o.say = function(){
console.log(`name=The ${this.name}, age=The ${this.age}`)}return o
}
var a = factory('a'.20)
var b = factory('b'.10)
a.say()
b.say()
Copy the code
/* The constructor pattern uses constructors to create objects of a particular type to use the new operator advantages: each instance can be identified as a particular type disadvantages: each instance method needs to be created once every time an instance is created */
function create(name, age){
this.name = name
this.age = age
this.say = function(){
console.log(`name=The ${this.name}, age=The ${this.age}`)}}var a = new create('a'.20)
var b = new create('b'.10)
a.say()
b.say()
Copy the code
/* Prototype mode: each function has a prototype. You can use the prototype object to share all instances of the object's property methods. Advantages: Methods are not created repeatedly
function Prototype(){
}
Prototype.prototype = {
constructor: Prototype,
name: 'a'.say:function(){
console.log(this.name)
}
}
var a = new Prototype()
var b = new Prototype()
a.say()
b.say()
Copy the code
/* The combined pattern constructor works with the prototype pattern. The constructor pattern is used to define instance properties, prototype properties to define methods and shared properties. Advantages the share of the share, the private private disadvantage of the lack of encapsulation */
function Create(name, age){
this.name = name;
this.age = age;
}
Create.prototype.say = function(){
console.log(`name=The ${this.name}, age=The ${this.age}`)}var a = new create('a'.20)
var b = new create('b'.10)
a.say()
b.say()
Copy the code
/* Dynamic prototype pattern To solve the problem of separate constructors and prototypes, the dynamic prototype pattern encapsulates information into the constructor and initializes the prototype in the constructor
function CreatePrototype(name, age){
this.name = name
this.age = age
if(typeof this.say ! = ='function'){
CreatePrototype.prototype.say = function(){
console.log(`name=The ${this.name}, age=The ${this.age}`)}}}var a = new CreatePrototype('a'.20)
var b = new CreatePrototype('b'.10)
a.say()
b.say()
Copy the code
/* The parasitic constructor pattern creates a function that merely encapsulates the code that created the object and then returns the newly created object
function NewFactory(name, age){
var o = new Object(a); o.name = name; o.age = age; o.say =function () {
console.log(`name=The ${this.name}, age=The ${this.age}`)};return o;
}
var a = new NewFactory('a'.20)
var b = new NewFactory('b'.10)
a.say()
b.say()
Copy the code
/* Safe function patterns have no public properties and their methods do not reference this
function StaticCreate(name, age){
var o = new Object()
o.say = function () {
console.log(`name=${name}, age=${age}`)}return o
}
var a = new StaticCreate('a'.20)
var b = new StaticCreate('b'.10)
a.say()
b.say()
Copy the code
instanceof
function instanceOf(l, r){
while(true) {if(l === null) return false
if(l.__proto__ === r.prototype) return true
l = l.__proto__
}
}
Copy the code
Equal to the judge
function eq(a, b, aStack, bStack){
if(a === b) returna ! = =0 || 1 / a === 1 / b
if(a === null || b === null) return false
if(a ! == a)returnb ! == bvar type = typeof a
if(type ! = ='object'&& type ! = ='function' && typeofb ! = ='object') return false
return deepEq(a, b, aStack, bStack)
}
function deepEq(a, b, aStack, bStack){
var type = Object.prototype.toString.call(a)
if(type ! = =Object.prototype.toString.call(b)) return false
switch (type) {
case '[object Number]':
if(+a ! == +a)return+b ! == +breturn +a === +b && 1 / a === 1 / b
case '[object String]':
case '[object RegExp]':
return ' ' + a === ' ' + b
case '[object Date]':
case '[object Boolean]':
return +a === +b
case '[object Symbol]':
return Symbol.prototype.valueOf.call(a) === Symbol.prototype.valueOf.call(b)
default:
break;
}
var areArrays = type === '[object Array]';
if(! areArrays){if(typeofa ! = ='object' && typeofb ! = ='object') return false
var aCtor = a.constructor
var bCtor = b.constructor
if(aCtor ! == bCtor && ! (typeof aCtor === 'function' && typeof bCtor === 'function' && aCtor instanceof aCtor && bCtor instanceof bCtor)
&& ('constructor' in a && 'constructor' in b)
) return false
}
aStack = aStack || []
bStack = bStack || []
var length = aStack.length
if(length ! == bStack.length)return false
while(length--) if(aStack[length] === a) return bStack[length] === b
aStack.push(a)
bStack.push(b)
if(areArrays){
length = a.length
if(length ! == b.length)return false
while(length--) if(! eq(a[length], b[length], aStack, bStack))return false
}else{
var keys = Object.keys(a)
length = keys.length
if(length ! = =Object.keys(b).length) return false
while(length--) if(! eq(a[keys[length]], b[keys[length]], aStack, bStack))return false
}
aStack.pop()
bStack.pop()
return true
}
Copy the code
duplicate removal
/** * Delete *@param {} [] Array Array to be deduplicated *@param {Boolean} IsSorted Specifies whether to sort *@param {function} Iteratee comparison function *@param {object} Context scope */
function unique(array, isSorted, iteratee, context){
if(typeofisSorted ! = ='boolean'){
context = iteratee
iteratee = isSorted
isSorted = false
}
if(isSorted == true){
iteratee = function(value){ return value }
}else if(typeofiteratee ! = ='function'){
iteratee = function(value){
value = value instanceof RegExp ? value.toString() : value
var key = (typeof value) + JSON.stringify(value)
if(this[key]) return false
this[key] = true
return true
}
}
iteratee = iteratee.bind(context || {})
var result = []
var last
for(var i = 0; i < array.length; i++){
var value = array[i]
var computed = iteratee(value, i, array)
if(isSorted){
if(! i || last ! == computed) result.push(value) last = value }else{
if(computed) result.push(value)
}
}
return result
}
Copy the code
Bubble sort
/** After each round of the outermost for loop, the maximum value of the remaining digits is moved to the last digit of the current round, and some neighboring digits are exchanged to become ordered. The total number of comparisons is (n-1)+(n-2)+(n-3)+... + 1 (n - 1) + (n - 2) + (n - 3) +... + 1. This is the equivalent of pairwise comparison of adjacent numbers, and states: "The one who is bigger stands on the right." After n-1n-1 rounds, the numbers are sorted from smallest to largest. * /
/** * time :O(n*n) * space :O(1) * stable *@param {[Number]} Arr Array to be sorted *@returns {[Number]}* /
var bubbleSort = (arr) = > {
let n = arr.length
for (let i = 0; i < n - 1; i++) {
for (let j = 0; j < n - 1 - i; j++) {
if(arr[j] > arr[j + 1]){
swap(arr, j, j + 1)}}}return arr
}
// Improved version of bubble sort: if there is no swap, it will jump out early
var bubbleSort = arr= > {
let n = arr.length
let swapped = true
for (let i = 0; i < n - 1; i++) {
if(! swapped)break
swapped = false
for (let j = 0; j < n - i - 1; j++) {
if(arr[j] > arr[j + 1]){
swap(arr, j, j + 1)
swapped = true}}}return arr
}
// Improved version of bubble sort: record the position of the last exchange
var bubbleSort = arr= > {
let lastIndex = arr.length - 1
let swapped = true
let swappedIndex = 0
while (swapped){
swapped = false
for (let i = 0; i < lastIndex; i++) {
if(arr[i] > arr[i + 1]){
swap(arr, i, i + 1)
swapped = true
swappedIndex = i
}
}
lastIndex = swappedIndex
}
return arr
}
Copy the code
Insertion sort
/** * Insert sort: Insert a new number in the process of swapping with the previous number until it finds its proper place. Exchange method * time :O(n*n) * space :O(1) * stable *@param {[Number]} Arr Array to be sorted */
var InsertSort = function(arr){
for (let i = 1; i < arr.length; i++) {
let j = i
while (j >= 1 && arr[j - 1] > arr[j]){
swap(arr, j, j - 1)
j--
}
}
return arr
}
/** * Insert sort: Insert a new number in the process of swapping with the previous number until it finds its proper place. Insert one time method * time :O(n*n) * space :O(1) * stability *@param {[Number]} Arr Array to be sorted */
var InsertSort = function(arr){
for (let i = 1; i < arr.length; i++) {
let x = arr[i]
let j = i - 1
while (j >= 0 && arr[j] > x){
arr[j + 1] = arr[j]
j--
}
arr[j + 1] = x
}
return arr
}
Copy the code
Hill sorting
/** * Hill sort: it is essentially an optimization of insert sort. It takes advantage of the simplicity of insert sort and * overcomes the disadvantage that insert sort only swaps two adjacent elements at a time. The basic idea is: * Divide the array to be sorted into multiple subarrays at certain intervals, and insert sort each group separately. * By interval, we don't mean to take a continuous array, but rather to take a set of values at a certain interval per jump * Narrow the interval for the next round * For the last round, take an interval of 11, which is the same as using insertion sort directly. * Time :O(n)~O(n*n) is generally up to O(1.3*n) * space :O(1) * unstable *@param {[Number]} Arr Array to be sorted */
var ShellSort = arr= > {
let maxGap = 1
let n = arr.length
while (maxGap <= n / 3){
maxGap = maxGap * 3 + 1
}
for (let gap = maxGap; gap > 0; gap = (gap - 1) / 3) {
for (let i = gap; i < n; i++) {
let curr = arr[i]
let preIndex = i - gap
while (preIndex >= 0 && curr < arr[preIndex]){
arr[preIndex + gap] = arr[preIndex]
preIndex -= gap
}
arr[preIndex + gap] = curr
}
}
return arr
}
Copy the code
Selection sort
/** * select sort: double loop through the group, each round of comparison, find the lowest subscript, swap it to the first. * Time :O(n*n) * Space :O(1) * unstable *@param {[Number]} Arr Array to be sorted */
var SelectSort = (arr) = > {
let n = arr.length
let min
for (let i = 0; i < n - 1; i++) {
min = i
for (let j = i + 1; j < n; j++) {
if(arr[j] < arr[min]) {
min = j
}
}
swap(arr, i, min)
}
return arr
}
/** * Select sort improvement: double loop through the group, each round of comparison, find the lowest subscript, swap it to the first. Find the largest coordinate in the last bit * Time :O(n*n) * Space :O(1) * unstable *@param {[Number]} Arr Array to be sorted */
var SelectSort = (arr) = > {
let n = arr.length
let min
let max
for (let i = 0; i < n >> 1; i++) {
min = i
max = i
for (let j = i + 1; j < n - i; j++) {
if(arr[j] < arr[min]) {
min = j
}
if(arr[j] > arr[max]) {
max = j
}
}
if(arr[min] == arr[max]) break
swap(arr, i, min)
Arr [I] and arr[min] have been swapped, so update the value of Max.
if(i == max) max = min
swap(arr, max, n - i - 1)}return arr
}
Copy the code
Merge sort
/** * Merge sort: split an array into N smaller arrays, and then merge the smaller arrays into an ordered array * time: O(N logn) * space: O(N) * stability *@param {*} Arr Array to be sorted */
var MergeSort = function(arr){
if(! arr.length)return
let result = mergeSort(arr, 0 , arr.length - 1)
for (let i = 0; i < arr.length; i++) {
arr[i] = result[i]
}
return arr
}
/** * Binary split array *@param {[Number]} arr
* @param {Number} start
* @param {Number} end
* @returns * /
var mergeSort = function(arr, start, end){
if(start == end) return [arr[start]]
let mid = Math.floor((start + end) / 2)
let left = mergeSort(arr, start, mid)
let right = mergeSort(arr, mid + 1, end)
return merge(left, right)
}
/** * Merge two ordered arrays *@param {[Number]} arr1
* @param {[Number]} arr2
*/
var merge = function(arr1, arr2){
let result = new Array(arr1.length + arr2.length)
let i = 0
let j = 0
while (i < arr1.length && j < arr2.length){
result[i + j] = arr1[i] < arr2[j] ? arr1[i++] : arr2[j++]
}
while(i < arr1.length){
result[i + j] = arr1[i++]
}
while(j < arr2.length){
result[i + j] = arr2[j++]
}
return result
}
/** * Merge sort space optimization version: split an array into N small arrays, and then merge the small arrays one by one into an ordered array * time: O(N logn) * space: O(N) * stable *@param {*} Arr Array to be sorted */
var MergeSort = function(arr){
if(! arr.length)return
let result = new Array(arr.length)
mergeSort(arr, 0 , arr.length - 1, result)
return arr
}
/** * Binary split array *@param {[Number]} arr
* @param {Number} start
* @param {Number} end
* @returns * /
var mergeSort = function(arr, start, end, result){
if(start == end) return
let mid = Math.floor((start + end) / 2)
mergeSort(arr, start, mid, result)
mergeSort(arr, mid + 1, end, result)
merge(arr, start, end, result)
}
/** * Merge two ordered arrays *@param {[Number]} arr1
* @param {[Number]} arr2
*/
var merge = function(arr, start, end, result) {
let end1 = Math.floor((start + end) / 2)
let start2 = end1 + 1
let end2 = end
let index1 = start
let index2 = start2
while(index1 <= end1 && index2 <= end2) {
result[index1 + index2 - start2] = arr[index1] <= arr[index2] ? arr[index1++] : arr[index2++]
}
while(index1 <= end1){
result[index1 + index2 - start2] = arr[index1++]
}
while(index2 <= end2){
result[index1 + index2 - start2] = arr[index2++]
}
while(start <= end){
arr[start] = result[start++]
}
return arr
}
Copy the code
Quick sort
/* * @Author: xiaohuolong * @Date: 2021-03-29 09:05:24 * @LastEditors: xiaohuolong * @LastEditTime: 2021-05-14 20:36:10 * @FilePath: /js-demo/algorithm/Sort/QuickSort.js */
/** * partition function: from the beginning, double pointer partition *@param {*} Array arr *@param {*} P left pointer *@param {*} Q Right pointer *@returns * /
var partition = (arr, p, q) = > {
let x = arr[p]
let i = p
let j = p + 1
for (j; j <= q; j++) {
if(arr[j] < x){
swap(arr, ++i, j)
}
}
swap(arr, i, p)
return i
}
/** * partition function: from the beginning, double pointer partition *@param {*} Array arr *@param {*} P left pointer *@param {*} Q Right pointer *@returns * /
var partition = (arr, p, q) = > {
// Take the first number as the base
let pivot = arr[p]
// Partition from the second number
let i = p + 1
/ / right border
let j = q
// Exit the loop on encounter
while (i < j){
// Find the first position that is greater than the cardinality
// console.log(arr.join(','), i, j);
while (i < j && arr[i] <= pivot) i++
// console.log(i, arr[i], pivot);
if(i ! = j){// Switch to the right partition so that the left partition is less than or equal to the cardinality and the right partition is greater than or equal to the cardinality
swap(arr, i, j)
j--
}
}
// console.log('while-end')
// console.log(arr.join(','))
// If the two Pointers are equal, compare arr[j] pivot separately
if(i == j && arr[j] > pivot) j--
// Swap the base with the middle tree
// console.log(j, p, arr[p], arr[j]);
if(j ! = p) swap(arr, p, j)// console.log(arr.join(','))
// Return the middle index
return j
}
Partition function: partition arr from p to q, leaving the left area smaller than the cardinality, leaving the right area larger than the cardinality, and return the subscript * of the middle value@param {*} Array arr *@param {*} P left pointer *@param {*} Q Right pointer *@returns * /
var partition = (arr, p, q) = > {
// Take the first number as the base
let pivot = arr[p]
// Partition from the second number
let i = p + 1
/ / right border
let j = q
// Exit the loop on encounter
while (i < j){
// Find the first position that is greater than the cardinality
// console.log(arr.join(','), i, j);
while (i < j && arr[i] <= pivot) i++
while (i < j && arr[j] >= pivot) j--
// console.log(i, arr[i], arr[j], pivot);
if(i < j){
// Switch to the right partition so that the left partition is less than or equal to the cardinality and the right partition is greater than or equal to the cardinality
swap(arr, i, j)
i++
j--
}
}
// console.log('while-end')
// console.log(arr.join(','))
// If the two Pointers are equal, compare arr[j] pivot separately
if(i == j && arr[j] > pivot) j--
// Swap the base with the middle tree
swap(arr, p, j)
// console.log(arr.join(','))
// Return the middle index
return j
}
Partition function: partition arr from p to q, leaving the left area smaller than the cardinality, leaving the right area larger than the cardinality, and return the subscript * of the middle value@param {*} Array arr *@param {*} P left pointer *@param {*} Q Right pointer *@returns * /
var partition = (arr, p, q) = > {
let pivot = arr[p]
let i = p + 1
let j = q
while (i < j){
while (i < j && arr[i] <= pivot) i++
while (i < j && arr[j] >= pivot) j--
if(i ! = j){ swap(arr, i, j) i++ j-- } }if(i == j && arr[j] >= pivot) j--
swap(arr, p, j)
return j
}
/** * The basic idea of the quicksort algorithm is: * Take a number from the array and call it the base (pivot) * Go through the array, putting the larger number to its right and the smaller number to its left. After the traversal is complete, the array is divided into two regions * Treat the left and right regions as two arrays and repeat the first two steps until the sorting is complete * Time complexity: O(nlogn ~ n*n) * Space complexity: O(logn ~ n) * Stable: unstable *@param {*} arr
* @param {*} p
* @param {*} q
* @returns * /
var sortArray = function(arr){
shuffle(arr)
return QuickSort(arr, 0, arr.length - 1)}var QuickSort = (arr, p, q) = > {
if(p < q){
// Partition the array and get the index of the intermediate value
const r = partition(arr, p, q)
// Sort the left area quickly
QuickSort(arr, p, r - 1)
// Quicksort the right area
QuickSort(arr, r + 1, q)
}
return arr
}
/** * optimization: shuffle the sorted array using the shuffle algorithm *@return {number[]}* /
var shuffle = function(nums) {
let n = nums.length
A random integer in [n, m]
var randOne = function(n, m) {
return Math.floor(Math.random() * (m - n + 1)) + n;
};
for (let i = 0; i < n; i++) {
let rand = randOne(i, n - 1)
swap(nums, i, rand)
}
return nums
};
/ / exchange
var swap = function(arr, i, j) {
let temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
};
Copy the code
Heap sort
/** * heap: a complete binary tree with one of the following conditions: * The value of the root node ≥ the value of the child nodes, such a heap is called the maximum heap, or large top heap; * If the value of the root node is less than or equal to the value of the child nodes, the heap is called the minimum heap, or the small top heap. * The sorting process is as follows: * Build a large top heap with a sequence of numbers, take the top number of the heap; * Adjust the remaining numbers to create a new big top heap, and take out the top number of the heap again; * Loop to complete the entire sort. * Time: O(nlogn) * Space: O(n) * unstable */
class Heap {
constructor(size, handle){
this.list = new Array(size + 1)
this.list[0] = size
this.handle = handle || this.handle
this.realSize = 0
}
handle(a, b){
return a > b
}
getParentIndex(i){
return Math.floor(i / 2)}getLeftChildIndex(i){
return i * 2
}
getRightChildIndex(i){
return i * 2 + 1
}
swap(i, j){
let temp = this.list[i]
this.list[i] = this.list[j]
this.list[j] = temp
}
heapUp(i){
// 1. Find the parent node of the node and determine whether to switch
let j = this.getParentIndex(i)
while(this.list[i] ! = =undefined && this.handle(this.list[i], this.list[j]) && j >= 1) {this.swap(i, j)
i = j
j = this.getParentIndex(i)
}
}
heapDown(i){
let n = Math.floor(this.realSize / 2)
while(i < this.realSize && i <= n){
let l = this.getLeftChildIndex(i)
let r = this.getRightChildIndex(i)
let left = this.list[l]
let right = this.list[r]
let curr = this.list[i]
let j = i
// console.log(curr, left, right)
if(left === undefined && right === undefined) break
if(right === undefined && this.handle(curr, left)) break
if(this.handle(curr, left) && this.handle(curr, right)) break
if(left === undefined) j = r
else if(right === undefined) j = l
else{
if(this.handle(left, right)){
j = l
}else{
j = r
}
}
this.swap(i, j)
i = j
}
}
add(val){
if(this.realSize >= this.list[0]) {if(this.handle(this.peek(), val)){
this.pop()
}else{
return}}this.realSize++
this.list[this.realSize] = val
// Float up after insertion
this.heapUp(this.realSize)
}
pop(){
let head = this.list[1]
this.list[1] = this.list[this.realSize]
this.list[this.realSize--] = undefined
this.heapDown(1)
return head
}
peek(){
return this.list[1] != undefined ? this.list[1] : -1
}
size(){
return this.realSize
}
heapify(list = [], handle){
let size = list.length
this.list = new Array(size + 1)
this.list[0] = size
this.handle = handle || this.handle
this.realSize = 0
for (let i = 0; i < size; i++) {
this.add(list[i])
}
}
}
class MinHeap extends Heap{
constructor(size, handle){
super(size, handle)
}
handle(a, b){
return a < b
}
}
var sortArray = function(arr){
let n = arr.length
let heap = new MinHeap(n)
heap.heapify(arr)
for (let i = 0; i < n; i++) {
arr[i] = heap.pop()
}
return arr
}
Copy the code
Count sorting
/** * Count sort * The count sort is done n or K times each time, so the count sort time is O(n + k), k is the range size of the data. * The space used is mainly the count array of length K and the result array of length n, so the space complexity is also O(n + k) * stable * count sort is only suitable for scenarios with small data range *@param {*} arr
*/
var CountingSort = (arr) = > {
// Judge null and prevent array from crossing bounds
if (arr == null || arr.length <= 1) return arr;
// Find maximum and minimum
let max = arr[0]
let min = arr[0]
for (let i = 1; i < arr.length; i++) {
max = Math.max(max, arr[i])
min = Math.min(min, arr[i])
}
let range = max - min + 1
// Create a range array with subscripts 0 to 8 corresponding to numbers 1 to 9
let counting = new Array(range).fill(0)
// Iterate over each element in the ARR
for (const x of arr) {
// Count the number of occurrences of each integer to the position of the corresponding index in the count array
counting[x-min] += 1
}
// Record the total number of the previous numbers smaller than oneself
let preCounts = 0
for (let i = 0; i < counting.length; i++) {
// Calculate counting as the starting subscript position of the current number in the result. Position = the total number of smaller numbers in front of you.
preCounts += counting[i]
// The current number is less than the next number, add to the preCounts
counting[i] = preCounts - counting[i]
}
let result = new Array(arr.length)
for (const x of arr) {
// Counting [x-1] Specifies the index of each element in the result array
let index = counting[x - min]
result[index] = x
// Update counting[x-1] to point to the next index of each element
counting[x-min]+=1
}
for (let i = 0; i < arr.length; i++) {
arr[i] = result[i]
}
return arr
}
Copy the code
Radix sort
/** * Base sort * Base sort can be divided into three steps: MaxDigit * Get the cardinality of each number in the array * Walk through the maxDigit array, sorting it by cardinality each round * time complexity O(d(n +k)) * Space complexity O(n+k) * stable *@param {number[]} arr
*/
var radixSort = function(arr){
if(arr.length <= 1) return arr
let max = -Infinity
for (const x of arr) {
max = Math.max(max, Math.abs(x))
}
let maxDigit = 0;
while(max ! =0) {
maxDigit++;
max = Math.floor(max / 10);
}
let counting = new Array(20).fill(0)
let result = new Array(arr.length)
let dev = 1
for (let i = 0; i < maxDigit; i++) {
// console.log(arr)
for (const x of arr) {
let radix = (dev <= Math.abs(x) ? parseInt(x / dev) % 10 : 0) + 9
// console.log(radix, x)
counting[radix]++
}
// console.log(counting)
for (let j = 1; j < counting.length; j++) {
counting[j] += counting[j - 1]}for (let j = arr.length - 1; j >= 0; j--){
let radix = (dev <= Math.abs(arr[j]) ? parseInt(arr[j] / dev) % 10 : 0) + 9
result[--counting[radix]] = arr[j]
}
// console.log(result)
for (let j = 0; j < result.length; j++) {
arr[j] = result[j];
}
counting.fill(0)
dev *= 10
}
return arr
}
Copy the code
diff
// react
function diff1(prev, next){
let container = prev.slice()
let nextIndex = {}
let prevIndex = {}
let prevLength = prev.length
let nextLength = next.length
let lastIdx = 0
// Generate a mapping table for easy lookup
for(let i = 0; i < prevLength; i++) prevIndex[prev[i].key] = i
for(let i = 0; i < nextLength; i++){
// 1. Iterate next to get nextNode, position I
let nextNode = next[i]
nextIndex[nextNode.key] = i
// 3. If a node is found and its position is j, update the node and determine whether j is less than lastIdx (lastIdx = 0). If not, then lastIdx = j
let j = prevIndex[nextNode.key]
if(j ! = =undefined){
patch(prev[j], nextNode)
// 4. If less than lastIdx, insert the node after next[i-1]
if(j < lastIdx){
container = insertBefore(next[i - 1], nextNode, container, 1)}else{
lastIdx = j
}
}else{
Nextnode.key = nextnode.key; next[i-1] = next[i-1]
container = insertBefore(next[i - 1], nextNode, container, 1)}}// 5. After traversing next, traverse prev. If the node is not in next, delete the node
for(let p of prev){
if(nextIndex[p.key] === undefined){
remove(p, container)
}
}
return container
}
Copy the code
// vue2
function diff2(prev, next){
let container = prev.slice()
// 1. Declare four variables prevStart, prevEnd, nextStart, and nextEnd to take out prevStartNode, prevEndNode, nextStartNode, and nextEndNode
let prevStart = 0
let nextStart = 0
let prevEnd = prev.length - 1
let nextEnd = next.length - 1
let prevStartNode = prev[prevStart]
let prevEndNode = prev[prevEnd]
let nextStartNode = next[nextStart]
let nextEndNode = next[nextEnd]
let prevIndex = {}
for(let i = 0; i < prev.length; i++) prevIndex[prev[i].key] = i
// 2. Loop, condition does not meet prevStart <= prevEnd && nextStart <= nextEnd jump loop
while(prevStart <= prevEnd && nextStart <= nextEnd){
// 3. PrevStartNode or prevEndNode does not exist, prevStart++, prevEnd--, back to 2
if(! prevStartNode){ prevStartNode = prev[++prevStart] }else if(! prevEndNode){ prevEndNode = prev[--prevEnd] }else if(prevStartNode.key === nextStartNode.key){
// 4. Prevstartnode. key == nextstartnode. key, equal to update node, prevStart++ nextStart++, back to 2
patch(prevStartNode, nextStartNode)
prevStartNode = prev[++prevStart]
nextStartNode = next[++nextStart]
}else if(prevEndNode.key === nextEndNode.key){
// 5. Prevendnode. key == NexTendNode. key, equal to update node, prevEnd-- nextEnd --, return to 2
patch(prevEndNode, nextEndNode)
prevEndNode = prev[--prevEnd]
nextEndNode = next[--nextEnd]
}else if(prevStartNode.key === nextEndNode.key){
// 6.prevstartnode. key == nextendnode. key, equals to update node, insert prevStartNode before prevendnode. next, prevStart++ nextEnd--, return to 2
patch(prevStartNode, nextEndNode)
container = insertBefore(prevEndNode, prevStartNode, container, 1)
prevStartNode = prev[++prevStart]
nextEndNode = next[--nextEnd]
}else if(prevEndNode.key === nextStartNode.key){
// 7. Prevendnode. key == nextstartnode. key, update node, insert prevEndNode before prevStartNode, prevEnd-- nextStart++, back to 2
patch(prevEndNode, nextStartNode)
container = insertBefore(prevStartNode, prevEndNode, container)
prevEndNode = prev[--prevEnd]
nextStartNode = next[++nextStart]
}else{
NextStartNode ++, prev[J], prev[J], prev[J], prev[J], prev[J] Back to 2
let j = prevIndex[nextStartNode.key]
if(j ! = =undefined){
patch(prev[j], nextStartNode)
prev[j] = undefined
}
container = insertBefore(prevStartNode, nextStartNode, container)
nextStartNode = next[++nextStart]
}
}
if(prevEnd < prevStart){
// 9. If prevEnd < prevStart proves that a new node has not been processed after the end of the loop, insert the node from nextStart until newEnd, each time before next[newEnd + 1]
let ref = next[nextEnd + 1] | |null
while(nextStart <= nextEnd){
container = insertBefore(ref, next[nextStart++], container)
}
}else if(nextEnd < nextStart){
// 10. If nextEnd < newStart proves that a node has been removed and has not been processed, remove the node from prevStart until prevEnd
while(prevStart <= prevEnd){
remove(prev[prevStart++], container)
}
}
return container
}
Copy the code
// vue3
function diff3(prev, next){
let container = prev.slice()
// 1.j indicates the position of the current match. The initial value is 0
let j = 0
let prevEnd = prev.length - 1
let nextEnd = next.length - 1
let prevNode = prev[j]
let nextNode = next[j]
J / / 2. Start matching the same elements, if prev [j]. Key = = next [j]. The key, the updated j++ if j > prevEnd | | j > nextEnd jump out ahead of time
while(prevNode && nextNode && prevNode.key === nextNode.key){
patch(prevNode, nextNode)
j++
if(j > prevEnd || j > nextEnd) break
prevNode = prev[j]
nextNode = next[j]
}
// 3. J stops at the first difference after matching the previous identical elements
prevNode = prev[prevEnd]
nextNode = next[nextEnd]
PrevEnd and nextEnd / / 4. Start from the back to find the same suffix, updated prevEnd - nextEnd - if j > prevEnd | | j > nextEnd jump out ahead of time
while(prevNode && nextNode && prevNode.key === nextNode.key){
patch(prevNode, nextNode)
prevEnd--
nextEnd--
if(j > prevEnd || j > nextEnd) break
prevNode = prev[prevEnd]
nextNode = next[nextEnd]
}
// console.log(j, prevEnd, nextEnd)
// console.log(container, prev, next)
// 5. At this point, the same prefix and suffix have been updated
if(j > prevEnd && j <= nextEnd){
// if j > prevEnd && j <= nextEnd, next inserts element before [j, nextEnd + 1]
let ref = next[nextEnd + 1] | |null
while(j <= nextEnd){
container = insertBefore(ref, next[j++], container)
}
}else if(j > nextEnd && j <= prevEnd){
// 7. If j > nextEnd && j <= prevEnd, prev is deleted from [j, prevEnd]
while(j <= prevEnd){
remove(prev[j++], container)
}
}else if(j <= nextEnd){
// 8. If neither of the preceding two conditions exists, then there are nodes in the [j, prevEnd] segment with the length of nextLeft = nextEnd -j + 1
let nextLeft = nextEnd - j + 1
// 9. Initialize an auxiliary array source length nextLeft Default value -1, patched = 0, move = false, pos = 0
let source = new Array(nextLeft).fill(-1)
let pos = 0
let patched = 0
let move = false
let keyIndex = {}
// 10. Iterate next, from j to nextEnd, and generate a key-i mapping table keyIndex
for(let i = j; i <= nextEnd; i++) keyIndex[next[i].key] = i
// 11. Iterate over prev from j to prevEnd
for (let i = j; i <= prevEnd; i++) {
let prevNode = prev[i]
// 12. If patched is larger than nextLeft, the same elements are retrieved from prev and the following elements are to be deleted. Delete the elements directly
if(patched < nextLeft){
let k = keyIndex[prevNode.key]
K = keyIndex[prev[I]], if k does not exist, this node does not exist in next, delete it directly
if(k ! = =undefined) {Next [k]. Key == prev[I]. Key, patched++, source[k - j] = I, if k < pos, prev[I] = true, otherwise pos = k
patch(prevNode, next[k])
source[k - j] = i
patched++
if(k < pos){
move = true
}else{
pos = k
}
}else{
remove(prevNode, container)
}
}else{
remove(prevNode, container)
}
}
// console.log(source)
// 15. Check whether move is true
if(move){
// 17. If true, an out-of-order/new situation occurs in this range
Seq = lis(source) j = seq.length-1
let seq = lis(source)
let k = seq.length - 1
for(let i = nextLeft - 1; i >= 0; i--){
if(source[i] === -1|| i ! == seq[k]){Next [pos + 1] next[pos + 1] next[pos + 1] next[pos + 1]
// 20. If I == seq[j], then we need to move the node, pos = j + I, insert next[pos] in prev before next[pos + 1] in prev
let pos = j + i
container = insertBefore(next[pos + 1] | |null, next[pos], container)
}else{
// 21. Other information, J --
k--
}
// console.log(container)}}else{
Next [pos] next[pos + 1] next[pos + 1] next[pos + 1]
for(let i = nextLeft - 1; i >= 0; i--){
if(source[i] === -1) {let pos = j + i
container = insertBefore(next[pos + 1] | |null, next[pos], container)
}
}
}
}
return container
}
function lis(arr) {
const p = arr.slice()
const result = [0]
let i
let j
let u
let v
let c
const len = arr.length
for (i = 0; i < len; i++) {
const arrI = arr[i]
if(arrI ! = =0) {
j = result[result.length - 1]
if (arr[j] < arrI) {
p[i] = j
result.push(i)
continue
}
u = 0
v = result.length - 1
while (u < v) {
c = ((u + v) / 2) | 0
if (arr[result[c]] < arrI) {
u = c + 1
} else {
v = c
}
}
if (arrI < arr[result[u]]) {
if (u > 0) {
p[i] = result[u - 1]
}
result[u] = i
}
}
}
u = result.length
v = result[u - 1]
while (u-- > 0) {
result[u] = v
v = p[v]
}
return result
}
Copy the code