JavaScript 數組的 uniq 方法

來源:互聯網
上載者:User

給Array本機物件增加一個原型方法,它的用途是刪除數組條目中重複的條目(可能有多個),傳回值是一個包含被刪除的重複條目的新數組。

形式化描述:
input
Array(size=N)
output
Array1=Array的無重複保序的子集,
無重複是指,對任意a,b屬於Array1,a!=b
保序是指,若a在Array的下標小於b在Array的下標,則a在Array1中的下標也小於b在Array的下標
Array2=Array-Array1,保序
realazy給出了一個新解,思路非常清晰:順序遍曆訪問每個元素,如果這個元素的值已經訪問過了,則加入Array2,否則加入Array1。判斷當前元素的值是否已經訪問過所採用的方法是順序遍曆已經訪問過的所有元素。
易見該演算法複雜度約O(N^2)。

我在他的演算法架構下稍微做了一些改進,關鍵在於遍曆過程中如何判斷當前元素的值是否已經訪問過。在原數組範圍為正整數且極差(range=max value-min value)不太大的條件下,可以採用簡單的"桶"演算法。
準備一個長度為range的boolean數組b,初始化全為false。對於原數組中每個值value,如果b[value]=true,則表明這個值訪問過,放入Array2,否則放入Array1同時令b[value]=true。
這顯然是O(N)的演算法,代價是額外的空間複雜度range,而且要求原數組範圍為正整數。
不難推廣到範圍為整數的情形,事實上只需考察桶號value-min(Array)即可轉化為正整數的情形。

為了避免range太大造成的空間的浪費,在"桶"演算法基礎上改進為散列演算法,具體說來是線性同餘開散列法。目的是將範圍壓縮映射到一個可控的小的連續正整數子集中,同時保證不同的原象對應的相同的象的機率要儘可能小,也就是說桶與桶之間要盡量負載平衡。
例如這是一個範圍為實數的散列函數:
key=hashFun(value)=Math.floor(value)*37%91
這仍然是O(N)的演算法,(顯然O(N)是所有uniq演算法的複雜度下界),好處是可以控制空間的開銷,而且可以適應非整數範圍,只需要設計相應的散列函數即可。

下面是桶(bucket)演算法的實現:
var resultArr = [],
returnArr = [],
origLen = this.length,
resultLen;
var maxv=this[0],minv=this[0];
for (var i=1; i<origLen; ++i){
if(this[i]>maxv)maxv=this[i];
else if(this[i]<minv)minv=this[i];
}
var blen=maxv-minv+1;
var b=new Array(blen);
for(var i=0;i<blen;++i)b[i]=false;
for (var i=0; i<origLen; ++i){
if (b[this[i]-minv]){
returnArr.push(this[i]);
} else {
resultArr.push(this[i]);
b[this[i]-minv]=true;
}
}
resultLen = resultArr.length;
this.length = resultLen;
for (var i=0; i<resultLen; ++i){
this[i] = resultArr[i];
}
return returnArr;
下面是散列(hash)演算法的實現
var shuffler = 37
var beta=0.007;
var origLen=this.length
var bucketSize=Math.ceil(origLen*beta);
var hashSet=new Array(bucketSize);
var hashFun = function(value){
var key = (Math.floor(value)*shuffler)%bucketSize;
return key;
}
//init hashSet
for(var i=0;i<bucketSize;i++)hashSet[i]=new Array();
//
var ret=[],self=[];
var key,value;
var bucket,openLen;
var everConflict;
for(var i=0;i<origLen;i++){
value=this[i];
key=hashFun(value);
bucket = hashSet[key];
openLen=bucket.length;//if(openLen>1)return;
everConflict=false;
for(var j=0;j<openLen;j++){
if(bucket[j]==value){
ret.push(value);
everConflict=true;
break;
}
}
if(!everConflict){
bucket.push(value);
self.push(value);
}
}
selfLen = self.length;
this.length = selfLen;
for (i=0; i<selfLen; ++i){
this[i] = self[i];
}
//compute average bucket size
var lens=[],sum=0;
for(var i=0;i<hashSet.length ;++i){lens.push(hashSet[i].length);sum+=hashSet[i].length};
average=sum/hashSet.length;//watch lens,average
return ret;

用k*10000個0~k*100的隨機整數測試計算時間(ms)
k 1 2 3 4 5
realazy 240 693 1399 2301 3807
bucket 55 101 141 219 293
hash 214 411 654 844 1083
測試架構借鑒了http://realazy.org/lab/uniq.html
測試環境Firefox2.0.0.6/Ubuntu7.10/2.66GHzP4/1024MBDDR

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.