索引堆插入的问题
来源:4-8 索引堆(Index Heap)
拖车板牙爵士
2017-02-24
如果给索引堆插入新值的时候,如果插入的索引有误,是个固定值,这样就不能形成一个堆了,这种插入相同索引的问题应该怎么解决
maxheap.insert(6,Math.floor(Math.random()*100));
class ImdexMaxHeap { constructor(){ this.data = []; this.index = []; this.reverse = [0]; this.count = 0; } size() { return this.count; } isEmpty() { return this.count === 0; } insert(i,item) {//插入元素,传入的i对用户而言,是从0索引的 if(i+1 >=1){ i+=1 } this.data[this.count+1] = item; this.index[this.count+1] = i; this.reverse[i] = this.count+1 this.count++; this.shiftUp(this.count); } shiftUp(k) { while (k > 1 && this.data[Math.floor(this.index[k]/2)] < this.data[this.index[k]]){ [this.index[Math.floor(k/2)],this.index[k]] = [this.index[k],this.index[Math.floor(k/2)]] this.reverse[this.index[Math.floor(k/2)]] = Math.floor(k/2) this.reverse[this.index[k]] = k k = Math.floor(k / 2); } } shiftDown(k){ while (2*k <= this.count){ let j = 2*k; if(j+1 <= this.count && this.data[this.index[j+1]] > this.data[this.index[j]]){ j = j+1 } if(this.data[this.index[k]] >= this.data[this.index[j]]){ break } [this.index[k],this.index[j]] = [this.index[j],this.index[k]] this.reverse[this.index[k]] = k; this.reverse[this.index[j]] = j; k = j; } } extractMax(){ if(this.count > 0){ let ret = this.data[this.index[1]] //console.log(this.data[1]+"----------------------------"+this.data[this.count]) if([this.index[1],this.index[this.count]] = [this.index[this.count],this.index[1]]){ this.reverse[this.index[1]] = 1; this.reverse[this.index[this.count]] = 0; this.index = this.index.slice(0,this.count) this.count-- } this.shiftDown(1) return ret; } } extractMaxIndex(){ if(this.count > 0){ let ret = this.index[1]-1; //console.log(this.data[1]+"----------------------------"+this.data[this.count]) if([this.index[1],this.index[this.count]] = [this.index[this.count],this.index[1]]){ this.reverse[this.index[1]] = 1; this.reverse[this.index[this.count]] = 0; this.index = this.index.slice(0,this.count) this.count-- } this.shiftDown(1) return ret; } } getItem(i) { this.contain(i) return this.data[i+1] } contain(i){ if(i+1 >=1 && i+1 <= this.data.length){ return this.reverse[i+1] !=0; } } change(i,item) { this.contain(i) i += 1; this.data[i] = item for(let j = 1; j<= this.count;j++){ if(this.index[j] ===i){ this.shiftUp(j); this.shiftDown(j) return } } } change2(i,item) { this.contain(i) i += 1; this.data[i] = item let j = this.reverse[i] this.shiftUp(j); this.shiftDown(j) } } function main() { let maxheap = new ImdexMaxHeap(); for (let i = 0; i < 20;i++){ maxheap.insert(i,Math.floor(Math.random()*100)); } console.log(maxheap.data+"---------"+maxheap.index+"---------"+maxheap.reverse); maxheap.extractMax() console.log(maxheap.data+"---------"+maxheap.index+"------------"+maxheap.reverse); } main()
写回答
1回答
-
我不确定我是否正确理解了你的问题。但是对于我们设计的这个结构,用户在调用insert(i,e)前,是需要自行判断一下 contain(i)的,如果返回false,才可以调用insert(i,e),否则的话,只能使用change(i,e)。当然,为了安全起见,我们在insert里做这样的一个assert更严谨:
assert( !contain(i) );
这样,如果用户没有进行contain判断的话,插入重复索引,会抛出错误,就好像数组越界一样,是用户使用不当。当然,在实际的生产环境中,错误处理应该抛出异常一类的。
感谢你的提醒,现在我将github上的insert代码增加了这个assert,最终是这个样子:
// 传入的i对用户而言,是从0索引的 void insert(int i, Item item){ assert( count + 1 <= capacity ); assert( i + 1 >= 1 && i + 1 <= capacity ); // 再插入一个新元素前,还需要保证索引i所在的位置是没有元素的。 assert( !contain(i) ); i += 1; data[i] = item; indexes[count+1] = i; reverse[i] = count+1; count++; shiftUp(count); }
不过,我们也可以将接口设计成,如果insert的索引i是已经存在的话,就相应的调用change逻辑。如果我们要在IndexHeap中重载[]这个运算符的话,这是一个好的设计。换句话说,如果调用myIndexHeap[6] = 42,先查看6这个索引在我们的索引堆中是否存在,若存在,则修改其对应元素为42(调用change);否则,将索引6的元素42插入我们的索引堆(调用insert)。
希望解决了你的问题:)
522017-02-24
相似问题