简体   繁体   English

使用二进制搜索将字符串插入到已排序的字符串数组中

[英]Insert string into sorted array of strings with binary search

I have the following alphabetically sorted array of strings:我有以下按字母顺序排序的字符串数组:

let collection = ["ABC", "BCD", "CAB", "FGH", "JKL", "ZKL"];

I want to insert the string "CQW" inside the collection whilst preserving the sorted order but without having to sort the whole array all over again.我想在集合中插入字符串"CQW" ,同时保留排序顺序,但不必再次对整个数组进行排序。

So I would like to have ["ABC", "BCD", "CAB", "CQW", "FGH", "JKL", "ZKL"];所以我想要["ABC", "BCD", "CAB", "CQW", "FGH", "JKL", "ZKL"]; after the insertion completed in O(log n) time.O(log n)时间内完成插入后。

I figured it would be a good idea to calculate the index at which I need to insert the element using binary search.我认为使用二分搜索计算需要插入元素的索引是个好主意。

I have found the following code for binary search which retrieves the index of a string if it is existent inside a collection:我找到了以下二进制搜索代码,如果字符串存在于集合中,它会检索字符串的索引:

 function binarySearch(items, value) { let startIndex = 0; let stopIndex = items.length - 1; let middle = Math.floor((stopIndex + startIndex) / 2); while (items[middle] != value && startIndex < stopIndex) { //adjust search area if (value < items[middle]) { stopIndex = middle - 1; } else if (value > items[middle]) { startIndex = middle + 1; } //recalculate middle middle = Math.floor((stopIndex + startIndex) / 2); } // Return -1 if element is not in collection return (items[middle] != value) ? -1 : middle; } let collection = ["ABC", "BCD", "CAB", "FGH", "JKL", "ZKL"]; console.log(binarySearch(collection, "CQW"));

However, I have been struggling with modifying it so that it returns the precise index at which the string needs to be inserted.但是,我一直在努力修改它,以便它返回需要插入字符串的精确索引。 How can this be modified so that it works?如何修改它以使其正常工作? Is binary search the most efficient way to do this?二分搜索是最有效的方法吗?

The middle value should tell you where to put it. middle值应该告诉你把它放在哪里。 Modify the function's return value so it tells you if it's already in the collection as well修改函数的返回值,让它告诉你它是否已经在集合中

 function binarySearch(items, value) { console.log('Searching for '+value) let startIndex = 0; let stopIndex = items.length - 1; let middle = Math.floor((stopIndex + startIndex) / 2); while (items[middle] != value && startIndex < stopIndex) { //adjust search area if (value < items[middle]) { stopIndex = middle - 1; } else if (value > items[middle]) { startIndex = middle + 1; } //recalculate middle middle = Math.floor((stopIndex + startIndex) / 2); } // Return -1 if element is not in collection // return (items[middle] != value) ? -1 : middle; return { found: items[middle] == value, middle: middle } } let collection = ["ABC", "BCD", "CAB", "FGH", "JKL", "ZKL"]; let item = "CQW" result= binarySearch(collection, item); console.log(result) if(!result.found){ console.log('Adding '+item+' at index '+result.middle) collection.splice(result.middle, 0, item); } console.log(collection)

Output输出

Searching for CQW
{found: false, middle: 3}
Adding CQW at index 3
["ABC", "BCD", "CAB", "CQW", "FGH", "JKL", "ZKL"]

Since you're inserting into an array you are always going to have a worst case of O(n) in just moving values around "after" the insertion (+ an additional n or log n for finding the place to insert the value at).由于您要插入到数组中,因此您总是会遇到O(n)的最坏情况,只是在插入“之后”移动值(+ 额外的nlog n用于查找插入值的位置) . So i would either just append the value at one end of the array and then sort it with insertion sort (since insertion sort is actually one of the faster algorithms for almost-sorted input data).所以我要么只在数组的一端附加值,然后用插入排序对其进行排序(因为插入排序实际上是几乎排序的输入数据的更快算法之一)。

 const insertionSort = (inputArr) => { const length = inputArr.length; for (let i = 1; i < length; i++) { const key = inputArr[i]; let j = i - 1; while (j >= 0 && inputArr[j] > key) { inputArr[j + 1] = inputArr[j]; j = j - 1; } inputArr[j + 1] = key; } return inputArr; }; let collection = ["ABC", "BCD", "CAB", "FGH", "JKL", "ZKL"]; collection.push("CQW"); console.log(insertionSort(collection));

Or, if you tend to end up with HUGE arrays and need O(n) worst case complexity for insertion;或者,如果您倾向于以巨大的数组结束并且需要O(n)最坏情况下的复杂度进行插入; then i would move to an always sorted doubly-linked list instead.然后我会转向一个总是排序的双向链表。

 const linkedList = (value, next) => ({prev: null, value, next}); const insert = (node, value) => { if (node === null) { return false; } if (node.value < value) { return insert(node.next, value); } const newNode = linkedList(value, node); newNode.prev = node.prev; newNode.prev.next = newNode; node.prev = newNode; return true; } const arrayToList = (arr) => arr.reverse().reduce((next, el) => { const list = linkedList(el, next); if (next) { next.prev = list; } return list; }, null); const printList = (list) => { const arr = []; let node = list; while (node) { arr.push(node.value); node = node.next; } console.log(arr); }; const collection = ["ABC", "BCD", "CAB", "FGH", "JKL", "ZKL"]; const list = arrayToList(collection); insert(list, "CQW"); printList(list); // Some function that arent't used in the example // but are very usefull if you decided to use this solution const get = (list, index) => { let node = list; for (let i = 0; node; i++) { if (i === index) { return node.value; } node = node.next; } return null; } const set = (list, index, value) => { let node = list; for (let i = 0; node; i++) { if (i === index) { node.value = value; return true; } node = node.next; } return false; } const remove = (list, value) => { if (node === null) { return false; } if (node.value === value) { node.prev.next = node.next; node.next.prev = node.prev; return true; } return remove(node.next, value); } const getIndex = (list, value) => { let node = list; for (let i = 0; node; i++) { if (node.value === value) { return i; } node = node.next; } return -1; }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM