在上節的算法設計課堂上,我們學習了尋找多數元素的算法,這個算法相對於我們以前學習的算法比較不好理解,今天就讓我們來看看這個算法
1.思路解析
1.1多數元素定義
多數元素表示在一個數組中出現次數最多,並且出現次數 > 數組總長度的一半的元素。例如數組a = {1,7,5,5,5,5,5,4},數組總長度為8,5在其中出現了5次,大於8/2=4次,因此5是多數元素。
而在數組b = {1,2,5,5,5,9,7,6,4},數組總長度為9,5雖然同樣是出現次數最多的元素,但他的出現次數只有3次,因而不能算作多數元素。、
1.2遍歷計數法
遍歷計數法可謂是最簡單粗暴的方法,其思路是對數組中出現的每一個元素,都遍歷一遍求出其出現次數,再從中找出多數元素,這種算法的優點在於容易想到,但這種算法的計算量實在太大,因此不推薦
1.3排序取中項法
排序取中項法相對於前一個方法來說進步了一些,其使用的原理是:
- 在一個排好序的數組中,其最中間的元素必定是多數元素(如果有的話)
但這種算法也有其劣勢,就是它要求數組進行排序,在數組長度較大的時候,其計算代價也是較大的
1.4剔除元素法(推薦方法)
因此我們使用推薦的算法,這個算法基於的原理是:
- 在原序列中去除兩個不同的元素后,原序列中的多數元素在新序列中還是多數元素。
那么問題就簡單了,我們只需要將數組中不相同的元素兩兩剔除,那么剩下的數就自然是多數元素。
我們可以將數組的第一個元素設置為多數元素候選c,以及計數器count = 1,將數組后面的數與c比較,若相等count+1,不相等count-1,若count減到0,便表示該元素出現次數太少,將其和后面一個不相等的元素剔除,再次重置c和count,繼續此操作,直到比較到最后count都不為0,則c就為多數元素。
這種算法將復雜過程簡化成了兩數的比較,大大提升了計算效率。
2.算法偽碼
該算法的偽碼如下:
MAJORITY(n):
- c←candidate(1)
- count←0
- for j←1 to n
- if a[j] = c then count←count+1
- end for
- if count > n/2(取下線) then return c
- else return none
candidate(m):
- j←m; c←a[m]; count←1
- while j<n and count>0
- j←j+1
- if a[j] = c then count←count+1
- else count←count-1
- end while
- if j=n then return c
- else return candidate(j+1)
3.具體代碼
算法部分如下:
1 //尋找多數元素算法練習 2 public class Marjority { 3 private int a[] = new int[50]; //定義存放數據的數組 4 public int length; //定義數組長度 5 public Marjority(int length,int a[]) 6 { 7 for(int i=1;i<=length;i++) 8 this.a[i] = a[i-1]; //轉存數組 9 /*需要注意的是,我們的算法中數組下標從1開始 10 * 但java存儲時的數組下標從0開始,所以轉存時下標需-1*/ 11 this.length = length; 12 } 13 //尋找多數元素,若存在則輸出,不存在返回-99999 14 public int Mar() 15 { 16 int c = candidate(1); 17 //進行多數元素查詢 18 int count = 0; 19 for(int j=1;j<=length;j++) 20 if(a[j] == c) 21 count++; //計算該元素在數組中出現的次數 22 if(count > length/2) //判斷出現次數是否大於長度的一半 23 return c; //大於則有多數元素,返回其值 24 else return -9999; //不大於則沒有多數元素,返回-9999 25 } 26 public int candidate(int n) 27 { 28 int j = n, c = a[n], count = 1; 29 //聲明數組索引,當前元素值,計數器 30 while(j<length && count>0) 31 { 32 j++; //指針向后移動一位 33 if(a[j] == c) //若下一位與當前元素相同,計數器增加 34 count++; 35 else count--; //否則計數器減少 36 /*這里不太好理解的是計數器的作用, 37 * 實際上計數器是一個篩選作用, 38 * 當當前元素重復出現的次數太少時, 39 * 將這個元素剔除出候選*/ 40 } 41 if(j == length) 42 return c; /*當指針指向最后一個元素時, 43 表示當前元素出現次數足夠多, 44 返回其值*/ 45 else return candidate(j+1); //否則繼續向后遍歷 46 } 47 }
測試部分如下:
public class TestMarjority { public static void main(String args[]) { int a[] = {1, 2, 5, 5, 5, 5, 5, 1, 3}; //含有多數元素的數組 int b[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; //不含有多數元素的數組 Marjority m1 = new Marjority(a.length, a); Marjority m2 = new Marjority(b.length, b); System.out.println(m1.Mar()); System.out.println(m2.Mar()); } }
輸出結果如下: