我有一个由“数组”构成的JavaScript“表”,其中“行”表示对象共享相似的结构(成员属性类似于“列”形式,其值为“单元格”)。
该表已按照级联方式使用一个或多个列进行排序,其中mergesort以相反的顺序应用,并且可以是20到20,000行的任何位置。
用于在正确的位置将新行插入表中的最佳算法是什么,而无需对整个表进行重新排序(或者更确切地说,以查找新行的插入索引 )?
这方面的一个例子是:
Sort Order = name, id
id name description
0 a blah
1 b foo
2 d blah
3 d blah 2
...
19 d blah 18
Insert:
id name description
20 c bar
To Yield:
id name description
0 a blah
1 b foo
20 c bar
2 d blah
3 d blah 2
...
19 d blah 18
(对所有引用的定义感到抱歉,当我第一次尝试提出这个问题时,人们认为“表格”被称为SQL数据库表或类似表格时会出现很多混淆)
答案 0 :(得分:0)
对于任何感兴趣的人解决此问题如下:
var table = [
{i: 0, id: 0, id2: 0, id3: 0},
{i: 1, id: 0, id2: 1, id3: 0},
{i: 2, id: 1, id2: 0, id3: 0},
{i: 3, id: 1, id2: 2, id3: 0},
{i: 4, id: 1, id2: 3, id3: 0},
{i: 5, id: 2, id2: 0, id3: 1},
{i: 6, id: 2, id2: 0, id3: 2},
{i: 7, id: 2, id2: 1, id3: 0},
{i: 8, id: 2, id2: 1, id3: 1},
{i: 9, id: 2, id2: 2, id3: 0}
];
var sort = ['id', 'id2'];
function InsertionIndex(table, sort, row) {
var state = {
_compare: function (left, right) {
if (left < right) { return (1); }
else if (left > right) { return (-1); }
return (0);
},
column: '',
max: table.length,
min: 0,
row: row,
_search: function (state) {
var minc = this._compare(this.table[this.min][this.column], state.row[this.column]);
var maxc = this._compare(this.table[this.max - 1][this.column], this.row[this.column]);
if (state.table[state.min][state.column] == state.table[state.max - 1][state.column]) { return; }
if (minc < 0) { state.max = state.min; return; }
if (maxc > 0) { state.min = state.max; return; }
if ((state.max - state.min) > 2) {
var mid = Math.ceil((state.min + state.max) / 2);
var midc = state._compare(state.table[mid][state.column], state.row[state.column]);
if (midc < 0) {
state.max = mid;
state._search(state);
return;
} else if (midc > 0) {
state.min = mid;
state._search(state);
return;
} else {
for (var i = mid - 1; i >= state.min; i--) { if (state._compare(state.table[i][state.column], state.row[state.column]) != 0) { state.min = i + 1; break; } }
for (var i = mid + 1; i < state.max; i++) { if (state._compare(state.table[i][state.column], state.row[state.column]) != 0) { state.max = i; break; } }
return;
}
} else {
if (maxc < 0) {
if (minc > 0) { state.min = state.max - 1; state.max = state.max - 1; return; }
else { state.max = state.max - 1; return; }
} else if (minc > 0) {
state.min = state.max - 1; return;
}
}
return;
},
table: table
};
for (var i = 0; i < sort.length; i++) {
state.column = sort[i];
state._search(state);
if (state.min >= state.max) { break; }
}
return ({ max: state.max, min: state.min });
}
for (var i = 0; i < table.length; i++) {
document.write(table[i].i + ' ' + table[i].id+ ' ' + table[i].id2 + ' ' + table[i].id3 + '<BR />');
}
var insertion = {i: 3, id: 0, id2: 1, id3: 1};
document.write(InsertionIndex(table, sort, insertion).min + ' ' + InsertionIndex(table, sort, insertion).max + ' 1 2<BR />');
insertion = {i: 3, id: 1, id2: 1, id3: 1};
document.write(InsertionIndex(table, sort, insertion).min + ' ' + InsertionIndex(table, sort, insertion).max + ' 3 3<BR />');
insertion = {i: 3, id: 2, id2: 1, id3: 1};
document.write(InsertionIndex(table, sort, insertion).min + ' ' + InsertionIndex(table, sort, insertion).max + ' 7 9<BR />');
insertion = {i: 3, id: 3, id2: 1, id3: 1};
document.write(InsertionIndex(table, sort, insertion).min + ' ' + InsertionIndex(table, sort, insertion).max + ' 10 10<BR />');