日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

TopN算法与排行榜

發(fā)布時(shí)間:2024/4/11 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TopN算法与排行榜 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

??????在系統(tǒng)中,我們經(jīng)常會(huì)遇到這樣的需求:將大量(比如幾十萬(wàn)、甚至上百萬(wàn))的對(duì)象進(jìn)行排序,然后只需要取出最Top的前N名作為排行榜的數(shù)據(jù),這即是一個(gè)TopN算法。常見(jiàn)的解決方案有三種:

(1)直接使用List的Sort方法進(jìn)行處理。

(2)使用排序二叉樹(shù)進(jìn)行排序,然后取出前N名。

(3)使用最大堆排序,然后取出前N名。

??????第一種方案的性能是最差的,后兩種方案性能會(huì)好一些,但是還是不能滿足我們的需求。最主要的原因在于使用二叉樹(shù)和最大堆排序時(shí),都是對(duì)所有的對(duì)象進(jìn)行排序,而不是將代價(jià)花費(fèi)在我們需要的少數(shù)的TopN上。為此,我自己實(shí)現(xiàn)了TopNOrderedContainer來(lái)解決這個(gè)問(wèn)題。

??????思路是這樣的,使用一個(gè)長(zhǎng)度為N的數(shù)組,來(lái)存放最Top的N個(gè)對(duì)象,越Top的對(duì)象其在數(shù)組中的Index就越小。這樣,每次加入一個(gè)對(duì)象時(shí),就與Index最大的那個(gè)對(duì)象比較,如果比其更Top,則交換兩個(gè)對(duì)象的位置。如果被交換的對(duì)象是數(shù)組中的最后一個(gè)對(duì)象(Index最大),則該對(duì)象會(huì)被拋棄。如此,可以保證容器中始終保持的都是最Top的N個(gè)對(duì)象。

??????接下來(lái)我們看具體的實(shí)現(xiàn)。

??????如果一個(gè)對(duì)象要參與TopN排行榜,則其必須實(shí)現(xiàn)IOrdered接口,表明其可以被Top排序。

??? ///?<summary>
????
///?IOrdered?參與排行榜排序的對(duì)象必須實(shí)現(xiàn)的接口。
????
///?</summary>
????
///?<typeparam?name="TOrderedObj">參與排行榜排序的對(duì)象的類型</typeparam>
????public?interface?IOrdered<TOrderedObj>
????{
????????
bool?IsTopThan(TOrderedObj?other);
????}

??????之所以使用泛型參數(shù)TOrderedObj,是為了避免派生類在實(shí)現(xiàn)IsTopThan方法時(shí),需要將參數(shù)other進(jìn)行向下轉(zhuǎn)換。

??????接下來(lái)是TopNOrderedContainer實(shí)現(xiàn)的源碼:

??? ///?<summary>
????
///?TopNOrderedContainer?用于始終保持排行榜前N名的Object。該實(shí)現(xiàn)是線程安全的。
????
///?zhuweisky?2009.05.23
????
///?</summary>
????
///?<typeparam?name="TID">被排名的對(duì)象的標(biāo)志類型</typeparam>
????
///?<typeparam?name="TObj">被排名的對(duì)象類型</typeparam>
????public?class?TopNOrderedContainer<TObj>?where?TObj?:?IOrdered<TObj>
????{
????????
private?TObj[]?orderedArray?=?null;
????????
private?int?validObjCount?=?0;
????????
private?SmartRWLocker?smartRWLocker?=?new?SmartRWLocker();

????????
#region?TopNumber
????????
private?int?topNumber?=?10;
????????
public?int?TopNumber
????????{
????????????
get?{?return?topNumber;?}
????????????
set?{?topNumber?=?value;?}
????????}?
????????
#endregion

????????
#region?Ctor
????????
public?TopNOrderedContainer()?{?}
????????
public?TopNOrderedContainer(int?_topNumber)
????????{
????????????
this.topNumber?=?_topNumber;
????????}
????????
#endregion

????????
#region?Initialize
????????
public?void?Initialize()
????????{
????????????
if?(this.topNumber?<?1)
????????????{
????????????????
throw?new?Exception("The?value?of?TopNumber?must?greater?than?0?");
????????????}

????????????
this.orderedArray?=?new?TObj[this.topNumber];
????????}?
????????
#endregion

????????
#region?Add?List
????????
public?void?Add(IList<TObj>?list)
????????{
????????????
if?(list?==?null)
????????????{
????????????????
return;
????????????}

????????????
using?(this.smartRWLocker.Lock(AccessMode.Write))
????????????{
????????????????
foreach?(TObj?obj?in?list)
????????????????{
????????????????????
this.DoAdd(obj);
????????????????}
????????????}
????????}?
????????
#endregion

????????
#region?Add
????????
public?void?Add(TObj?obj)
????????{
????????????
using?(this.smartRWLocker.Lock(AccessMode.Write))
????????????{
????????????????
this.DoAdd(obj);
????????????}
????????}?
????????
#endregion????????

????????
#region?GetTopN
????????
public?TObj[]?GetTopN()
????????{
????????????
using?(this.smartRWLocker.Lock(AccessMode.Read))
????????????{
????????????????
return?(TObj[])this.orderedArray.Clone();
????????????}
????????}?
????????
#endregion

????????
#region?Private
????????
#region?DoAdd
????????
private?void?DoAdd(TObj?obj)
????????{
????????????
if?(obj?==?null)
????????????{
????????????????
return;
????????????}

????????????
if?(this.validObjCount?<?this.topNumber)
????????????{
????????????????
this.orderedArray[this.validObjCount]?=?obj;
????????????????
this.Adjust(this.validObjCount);

????????????????
++this.validObjCount;
????????????????
return;
????????????}

????????????
if?(this.orderedArray[this.topNumber?-?1].IsTopThan(obj))
????????????{
????????????????
return;
????????????}

????????????
this.orderedArray[this.topNumber?-?1]?=?obj;
????????????
this.Adjust(this.topNumber?-?1);
????????}
????????
#endregion

????????
#region?Adjust
????????
///?<summary>
????????
///?Adjust?調(diào)整posIndex處的對(duì)象到合適的位置。
????????
///?與相鄰前一個(gè)對(duì)象比較,如果當(dāng)前對(duì)象更加Top,則與前一個(gè)對(duì)象交換位置。
????????
///?</summary>???????
????????private?void?Adjust(int?posIndex)
????????{
????????????TObj?obj?
=?this.orderedArray[posIndex];
????????????
for?(int?index?=?posIndex;?index?>?0;?index--)
????????????{
????????????????
if?(obj.IsTopThan(this.orderedArray[index?-?1]))
????????????????{
????????????????????TObj?temp?
=?this.orderedArray[index?-?1];
????????????????????
this.orderedArray[index?-?1]?=?obj;
????????????????????
this.orderedArray[index]?=?temp;
????????????????}
????????????????
else
????????????????{
????????????????????
break;
????????????????}
????????????}
????????}
????????
#endregion
????????
#endregion
????}

??????源碼面前毫無(wú)秘密。

??????但是有幾點(diǎn)我還是需要說(shuō)明一下:

(1)ESBasic.ObjectManagement.TopNOrderedContainer位于我的ESBasic.dll類庫(kù)中,其實(shí)現(xiàn)時(shí)用到的SmartRWLocker是一個(gè)讀寫鎖,也是ESBasic.dll類庫(kù)中的一員。你可以從這里下載ESBasic.dll直接試用。

(2)為何不將TopN排序直接實(shí)現(xiàn)為一個(gè)靜態(tài)方法,如:

??????public?static?TObj[]?GetTopN<TObj>(IList<TObj>?list)?where?TObj?:?IOrdered<TObj>

??????如果要是這樣實(shí)現(xiàn),那我們就沒(méi)有辦法繼續(xù)動(dòng)態(tài)的Add新的TObj對(duì)象進(jìn)來(lái),如果要達(dá)到這樣的目的,就只有構(gòu)造新的list,再次調(diào)用static GetTopN方法,如此會(huì)重復(fù)做一些工作。

??????最后,我們來(lái)測(cè)試一下TopNOrderedContainer與List.Sort方法的性能比較,測(cè)試的對(duì)象數(shù)目為500000個(gè),取出Top20。測(cè)試代碼如下:??

????public?class?UserData?:?IOrdered<UserData>
????{
????????
#region?UserID
????????
private?string?userID;
????????
public?string?UserID
????????{
????????????
get?{?return?userID;?}
????????????
set?{?userID?=?value;?}
????????}?
????????
#endregion

????????
#region?Score
????????
private?int?score;
????????
public?int?Score
????????{
????????????
get?{?return?score;?}
????????????
set?{?score?=?value;?}
????????}?
????????
#endregion

????????
public?UserData(string?_userID,?int?_score)
????????{
????????????
this.userID?=?_userID;
????????????
this.score?=?_score;
????????}

????????
#region?IOrdered<string>?成員???????

????????
public?bool?IsTopThan(UserData?other)
????????{
????????????
return?this.Score?>?other.Score;
????????}

????????
public?override?string?ToString()
????????{
????????????
return?this.score.ToString();
????????}
????????
#endregion
????}

?

??????? private?void?button4_Click(object?sender,?EventArgs?e)
????????{
????????????List
<UserData>?list?=?new?List<UserData>();
????????????
for?(int?i?=?0;?i?<?500000;?i++)
????????????{
????????????????list.Add(
new?UserData("User"?+?i.ToString(),?i?*?i?*?i?-?3?*?i?*?i?+?4?*?i?+?8));
????????????}

????????????List
<UserData>?list2?=?new?List<UserData>();
????????????
for?(int?i?=?0;?i?<?500000;?i++)
????????????{
????????????????list2.Add(
new?UserData("User"?+?i.ToString(),?i?*?i?*?i?-?3?*?i?*?i?+?4?*?i?+?8));
????????????}

????????????Stopwatch?stopwatch?
=?new?Stopwatch();
????????????stopwatch.Start();
????????????list.Sort(
this);
????????????stopwatch.Stop();
????????????
long?ms1?=?stopwatch.ElapsedMilliseconds;

????????????stopwatch.Reset();
????????????stopwatch.Start();
????????????TopNOrderedContainer
<UserData>?container?=?new?TopNOrderedContainer<UserData>(20);
????????????container.Initialize();
????????????container.Add(list2);
????????????UserData[]?res?
=?container.GetTopN();
????????????stopwatch.Stop();
????????????
long?ms2?=?stopwatch.ElapsedMilliseconds;
????????}???????

????????
#region?IComparer<UserData>?成員
????????
public?int?Compare(UserData?x,?UserData?y)
????????{
????????????
return?(y.Score?-?x.Score);
????????}
????????
#endregion

??????測(cè)試的結(jié)果顯示,使用List.Sort方法需要1287ms,而TopNOrderedContainer只花了78ms。

?

?

?

總結(jié)

以上是生活随笔為你收集整理的TopN算法与排行榜的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。