随笔 - 117  文章 - 72  trackbacks - 0

声明:原创作品(标有[原]字样)转载时请注明出处,谢谢。

常用链接

常用设置
常用软件
常用命令
 

订阅

订阅

留言簿(7)

随笔分类(130)

随笔档案(123)

搜索

  •  

积分与排名

  • 积分 - 154340
  • 排名 - 389

最新评论

一、主元素问题
    设T[0..n-1]n个元素的数组。对任一元素x,设S(x)={i|T[i]=x}。当|S(x)|>n/2时,称xT的主元素。
1) 如果T中元素存在序关系,按分治策略设计并实现一个线性时间算法,确定T[0..n-1]是否有一个主元素。
2) T中元素不存在序关系,只能测试任意两个元素是否相等,试设计并实现一个O(nlogn)有效算法,确定T是否有一个主元素。进一步,能找到一个线性时间算法吗?
注:实现的算法要求列出足够的实验结果。
 
1)  基于分治法的线性时间求主元素算法
   算法思想
中位数:数列排序后位于最中间的那个数。如果一个数列有主元素,那么必然是其中位数。求一个数列有没有主元素,只要看中位数是不是主元素。
找中位数的方法:选择一个元素作为划分起点,然后用快速排序的方法将小于它的移动到左边,大于它的移动到右边。这样就将元素划分为两个部分。此时,划分元素所在位置为k。如果k>n/2,那么继续用同样的方法在左边部分找;如果k<n/2就在右边部分找;k=n/2就找到了中位元素。
根据快速排序的思想,可以在平均时间复杂度为O(n)的时间内找出一个数列的中位数。然后再用O(n)的时间检查它是否是主元素。
   算法实现
对应的Java程序在MajorElement.java
----------------------------------------------------------------------------------------
判断是否是主元素的伪代码:
master(A):
      len length[A]
      median randomizedSelect(A , 0 , n - 1 , n/2); 求中位数
      cnt 0
      计算中位数出现次数
      for i 0 to len – 1
        do if A[i] = median
               then cnt cnt + 1
      if cnt > n/2
        then print "主元素:" +median + "出现次数:" + cnt
        else print "无主元素"
----------------------------------------------------------------------------------------
找一个序列中第k大的数伪代码
randomizedSelect(A , p , q , k):
      r randomizedPartition (p , q)  找出划分元素r
      if r = k
        then return A[r]
        else if r > k
                   then randomizedSelect(A , p , r – 1, k)
                   else randomizedSelect(A , r + 1 , q , k)
----------------------------------------------------------------------------------------
实现随机划分的伪代码:
randomizedPartition(A , p , q ):
      rand
random(p , q)
      exchange A[rand] A[q]
      return partition(p , q)
----------------------------------------------------------------------------------------
基于快速排序思想的划分伪代码:
partition(A , p , q ):
      pivot A[q]
      i p – 1
      for j p to q – 1
           do if A[j] <= pivot
                then i i + 1
                            exchange A[i] A[j]
      exchange A[i + 1] A[q]
      return i + 1
----------------------------------------------------------------------------------------
   时间复杂度分析
master()中求中位数可以在平均时间复杂度为O(n)的时间内完成,检查中位数是否是主元素耗时O(n),所以时间复杂度为O(n)
 
2) 无序关系时求主元素的O(nlgn)的算法
   算法思想
    中存在主元素,则将分为两部分后,的主元素也必为两部分中至少一部分的主元素,因此可用分治法。
将元素划分为两部分,递归地检查两部分有无主元素。算法如下:
a. 只含一个元素,则此元素就是主元素,返回此数。
      b. 分为两部分T1 T2(二者元素个数相等或只差一个),分别递归调用此方法求其主元素m1 m2
      c. m1 m2 都存在且相等,则这个数就是的主元素,返回此数。
d. m1 m2 都存在且不等,则分别检查这两个数是否为的主元素,若有则返回此数,若无则返回空值。
e. m1 m2 只有一个存在,则检查这个数是否为的主元素,若是则返回此数,若否就返回空值。
f. m1 m2 都不存在,则无主元素,返回空值。
   算法实现
相应的Java程序在MasterElement.java
-----------------------------------------------------------------------------------------
O(nlgn)的算法伪代码:
▹求T[p..q]中的主元素。返回主元素及其出现次数或空(表示无主元素)
CheckMaster(T , p , q):
      if p ← q
           then return T[p] and 1
      len ← q – p + 1
      r ← p + len / 2
      a and numa ← CheckMaster(T , p , r – 1)
      b and numb ← CheckMaster(T , r , q)
     
      if a = NIL and b = NIL
           then return NIL
      if a = NIL and b NIL
           then return CheckAnotherPart(T , len , p , r – 1 , b , numb)
      if a NIL and b = NIL
           then return CheckAnotherPart(T , len , r , q , a , numa)
      if a NIL and b NIL
then if a = b
           then numa ← numa + numb
                  return a and numa
                      else re ← CheckAnotherPart(T , len , p , r – 1 , b ,numb)
                             if re NIL
                                 then return re
                                  else return CheckAnotherPart(T, len, r, q, a, numa)
-----------------------------------------------------------------------------------------
▹检查候选主元素是否是主元素
CheckAnotherPart(T , len , p , q , c , numc):
      numc ← CheckNum(T , p , q , c) + numc
      if num > len/2
           then return c and numc
           else return NIL
-----------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------
▹计算T[p..q]element出现的次数
CheckNum( T , p , q , element):
      cnt ← 0
      for i ← p to q
           do if T[i] = element
                      then cnt ← cnt + 1
      return cnt
----------------------------------------------------------------------------------------
   时间复杂度分析
T(n)=2T(n/2)+n  
所以时间复杂度为O(nlgn)
 
 
3)无序关系时求主元素的O(n)算法
   算法思想
在一个集合中,删除两个不同的数,则集合的主元素保持不变。根据这个原理,可以很快求出主元素。
   算法实现
-------------------------------------------------------------------------------------
相应的Java程序在MainElement.java
master(A):
      n ← length[A]
      count ← 1
      seed ← A[0]
      找候选主元素
      for i ← 1 to n – 1
           do if A[i] = seed
                   then count ← count + 1
                   else if count > 0
                              then count ← count – 1
                              else seed ← A[i]
      查找候选主元素是否是主元素
      count ← 0
      for i ← 0 to n – 1
        do if A[i] = seed
               then count ← count + 1
      if count > n/2
        then return seed and count
        else return NIL
-------------------------------------------------------------------------------------
   时间复杂度分析
时间复杂度为O(n)
 
 
4)算法测试
对前面三个求主元素算法,使用测试数据进行测试:
测试数组
结果
0,0,1,1,0,8,1,1,1
主元素:1出现次数:5
13,17,26,3,5,2,17,3
无主元素
1,2,3,4,5,6,7,8
无主元素
1,0,0,1,0,2,0
主元素:0 出现次数:4
1,3,4,1,2,1,1,4,0,1,1,1
主元素:1 出现次数:7
0,1,1
主元素:1 出现次数:2
13,17,26,3,5,2,17,3,3,3,3,3,3
主元素:3 出现次数:7
100,58
无主元素
597
主元素:597 出现次数:1
6,1,2,2,2,3,5
无主元素
7,7,7,7,7,7
主元素7  出现次数:6
5,9,45,96,77,28,13
无主元素

文章来源:http://wintys.blog.51cto.com/425414/100688
主元素.zip
posted on 2009-03-18 12:02 天堂露珠 阅读(591) 评论(0)  编辑  收藏 所属分类: Algorithm

只有注册用户登录后才能发表评论。


网站导航: