折衷演算法
㈠ 巨鹿之戰,項羽擊敗秦軍三十萬是真實存在的嗎有什麼記載
歷史上,項羽在巨鹿之戰中面對秦晚期著名將軍章邯的精彩表現,史學家和民眾們興高采烈。 以前章邯多次勝利,被稱為不敗神話,項羽在巨鹿之戰中打敗了章邯,在洞里殺了20萬秦軍。 堪比戰國時代的長平之戰。 這件事記載在司馬遷的《史記》中。 例如《史記·項羽本紀》:於是楚軍晚上擊退了秦國20多萬名新城南。 (《史記·黥布列傳》)項籍引兵自西赴新安,亦布等夜擊阬章邯鄲秦卒二十數萬人。
一個是保守的估計,如果二戰中十分之一死亡,陣亡的秦軍約6萬人,秦軍應該是26萬人。 二是根據沖突的估計,如果取得十分之三的戰死,戰死的秦軍約為9萬人,秦軍約為29萬人的數量,應該約為30萬人。 如果採用折衷演算法,應該是27萬左右。 秦王朝末期的起義軍在項羽的領導下推翻了秦王朝的統治。 項羽從小就有遠大的志向。 他曾經讀過書,但看不懂,練劍也練不出來。 雖然他喜歡看兵書,但並不怎麼求解。 有一次,他去看秦始皇巡視天下。 秦始皇之行隊伍氣勢磅礴,令人羨慕,我反而脫口而出。 受驚的叔叔馬上在旁邊捂住了他的嘴。
㈡ zip 的壓縮原理與實現
文件壓縮原理
我們使用計算機所做的事情大多都是對文件進行處理。每個文件都會佔用一定的磁碟空間,我們希望一些文件,尤其是暫時不用但又比較重要不能刪除的文件(如備份文件,有點像雞肋呀),盡可能少的佔用磁碟空間。但是,許多文件的存儲格式是比較鬆散的,這樣就浪費了一些寶貴的計算機存儲資源。這時,我們可以藉助壓縮工具解決這個問題,通過對原來的文件進行壓縮處理,使之用更少的磁碟空間保存起來,當需要使用時再進行解壓縮操作,這樣就大大節省了磁碟空間。當你要拷貝許多小文件時,通過壓縮處理可以提高執行效率。如果小文件很多,操作系統要執行頻繁的文件定位操作,需要花費很多的時間。如果先把這些小文件壓縮,變成一個壓縮文件後,再拷貝時就很方便了。由於計算機處理的信息是以二進制數的形式表示的,因此壓縮軟體就是把二進制信息中相同的字元串以特殊字元標記來達到壓縮的目的。為了有助於理解文件壓縮,請您在腦海里想像一幅藍天白雲的圖片。對於成千上萬單調重復的藍色像點而言,與其一個一個定義「藍、藍、藍……」長長的一串顏色,還不如告訴電腦:「從這個位置開始存儲1117個藍色像點」來得簡潔,而且還能大大節約存儲空間。這是一個非常簡單的圖像壓縮的例子。其實,所有的計算機文件歸根結底都是以「1」和「0」的形式存儲的,和藍色像點一樣,只要通過合理的數學計算公式,文件的體積都能夠被大大壓縮以達到「數據無損稠密」的效果。總的來說,壓縮可以分為有損和無損壓縮兩種。如果丟失個別的數據不會造成太大的影響,這時忽略它們是個好主意,這就是有損壓縮。有損壓縮廣泛應用於動畫、聲音和圖像文件中,典型的代表就是影碟文件格式mpeg、音樂文件格式mp3和圖像文件格式jpg。但是更多情況下壓縮數據必須准確無誤,人們便設計出了無損壓縮格式,比如常見的zip、rar等。壓縮軟體(compression software)自然就是利用壓縮原理壓縮數據的工具,壓縮後所生成的文件稱為壓縮包(archive),體積只有原來的幾分之一甚至更小。當然,壓縮包已經是另一種文件格式了,如果你想使用其中的數據,首先得用壓縮軟體把數據還原,這個過程稱作解壓縮。常見的壓縮軟體有winzip、winrar等
㈢ 巨鹿之戰中項羽坑殺了20萬秦軍,這是真的嗎
歷史上,項羽在巨鹿之戰中面對秦朝末期著名將領章邯的精彩表現為史學家和民眾們所津津樂道。先前章邯屢戰屢勝,堪稱不敗神話,但項羽卻能巨鹿之戰章邯,並坑殺了20萬的秦軍,堪比戰國時期的長平之戰。這事情記載於司馬遷的《史記》中有多處記載,比如《史記·項羽本紀》:於是楚軍夜擊阬秦卒二十餘萬人新安城南。又有:《史記·黥布列傳》:項籍之引兵西至新安, 又使布等夜擊阬章邯秦卒二十餘萬人。那麼巨鹿之戰的真實情況是怎麼樣呢?項羽真的坑殺了20萬的秦軍嗎?
四、結語
巨鹿之戰的坑殺秦軍20萬,無論從雙方兵力數量估算看、還是從投降後的問題處理情況看,又或者從坑殺所需要的時間看,都不大可能發生。因此,很大程度上,項羽坑殺秦軍20萬多半是司馬遷先生為表現項羽濫殺的一面而所為的誇大之語。
㈣ 數據結構 折中查找演算法/選擇排序 起泡排序演算法
折半查找法也稱為二分查找法,它充分利用了元素間的次序關系,採用分治策略,可在最壞的情況下用O(log n)完成搜索任務。它的基本思想是,將n個元素分成個數大致相同的兩半,取a[n/2]與欲查找的x作比較,如果x=a[n/2]則找到x,演算法終止。如果x<a[n/2],則我們只要在數組a的左半部繼續搜索x(這里假設數組元素呈升序排列)。如果x>a[n/2],則我們只要在數組a的右半部繼續搜索x。二分搜索法的應用極其廣泛,而且它的思想易於理解,但是要寫一個正確的二分搜索演算法也不是一件簡單的事。第一個二分搜索演算法早在1946年就出現了,但是第一個完全正確的二分搜索演算法直到1962年才出現。Bentley在他的著作《Writing Correct Programs》中寫道,90%的計算機專家不能在2小時內寫出完全正確的二分搜索演算法。問題的關鍵在於准確地制定各次查找范圍的邊界以及終止條件的確定,正確地歸納奇偶數的各種情況,其實整理後可以發現它的具體演算法是很直觀的,我們可用C++描述如下:
template<class Type>
int BinarySearch(Type a[],const Type& x,int n)
{
int left=0;
int right=n-1;
while(left<=right){
int middle=(left+right)/2;
if (x==a[middle]) return middle;
if (x>a[middle]) left=middle+1;
else right=middle-1;
}
return -1;
}
模板函數BinarySearch在a[0]<=a[1]<=...<=a[n-1]共n個升序排列的元素中搜索x,找到x時返回其在數組中的位置,否則返回-1。容易看出,每執行一次while循環,待搜索數組的大小減少一半,因此整個演算法在最壞情況下的時間復雜度為O(log n)。在數據量很大的時候,它的線性查找在時間復雜度上的優劣一目瞭然。
選擇排序
基本思想是:每次選出第i小的記錄,放在第i個位置(i的起點是0,按此說法,第0小的記錄實際上就是最小的,有點別扭,不管這么多了)。當i=N-1時就排完了。
直接選擇排序
直選排序簡單的再現了選擇排序的基本思想,第一次尋找最小元素的代價是O(n),如果不做某種特殊處理,每次都使用最簡單的尋找方法,自然的整個排序的時間復雜度就是O(n2)了。
冒泡法
為了在a[1]中得到最大值,我們將a[1]與它後面的元素a[2],a[3],...,a[10]進行比較。首先比較a[1]與a[2],如果a[1]<a[2],則將a[1]與a[2]交換,否則不交換。這樣在a[1]中得到的是a[1]與a[2]中的大數。然後將a[1]與a[3]比較,如果a[1]<a[3],則將a[1]與a[3]交換,否則不交換。這樣在a[1]中得到的是a[1],a[2],a[3]中的最大值,...。如此繼續,最後a[1]與a[10]比較,如果a[1]<a[10],則將a[1]與a[10]交換,否則不交換。這樣在a[1]中得到的數就是數組a的最大值(一共進行了9次比較)。
為了在a[2]中得到次大值,應將a[2]與它後面的元素a[3],a[4],...,a[10]進行比較。這樣經過8次比較,在a[2]是將得到次大值。
如此繼續,直到最後a[9]與a[10]比較,將大數放於a[9],小數放於a[10],全部排序到此結束。
從上面可以看出,對於10個數,需進行9趟比較,每一趟的比較次數是不一樣的。第一趟需比較9次,第二趟比較8次,...,最後一趟比較1次。
以上數組元素的排序,用二重循環實現,外循環變數設為i,內循環變數設為j。外循環重復9次,內循環依次重復9,8,...,1次。每次進行比較的兩個元素,第一個元素與外循環i有關的,用a[i]標識,第二個元素是與內循環j有關的,用a[j]標識,i的值依次為1,2,...,9,對於每一個i, j的值依次為i+1,i+2,...。
㈤ 用C語言實現冒泡排序對數排序後利用折中演算法查找輸入
#include<bits/stdc++.h>
usingnamespacestd;
intn,a[233],T;
intmain(){
scanf("%d",&n);
for(inti=1;i<=n;i++)scanf("%d",&a[i]);
for(inti=1;i<n;i++)
for(intj=n;j>i;j--)
if(a[j]<a[i])
swap(a[i],a[j]);
for(inti=1;i<=n;i++)printf("%d",a[i]);printf(" ");
scanf("%d",&T);
intl=1,r=n;
while(l<r){
intmid=(l+r+1)>>1;
if(a[mid]<=T)l=mid;elser=mid-1;
}
if(a[l]==T)printf("%d ",l);elseprintf("-1 ");
}
㈥ audition中的FFT大小到底啥意思
FFT是離散傅氏變換的快速演算法,它是根據離散傅氏變換的奇、偶、虛、實等特性,對離散傅立葉變換的演算法進行改進獲得的。它對傅氏變換的理論並沒有新的發現,但是對於在計算機系統或者說數字系統中應用離散傅立葉變換。
此後,在這思想基礎上又開發了高基和分裂基等快速演算法,隨著數字技術的高速發展,1976年出現建立在數論和多項式理論基礎上的維諾格勒傅里葉變換演算法(WFTA)和素因子傅里葉變換演算法。它們的共同特點是,當N是素數時,可以將DFT算轉化為求循環卷積,從而更進一步減少乘法次數,提高速度。
(6)折衷演算法擴展閱讀:
在這些演算法中,基2演算法用得最普遍。通常按序列在時域或在頻域分解過程的不同,又可分為兩種:一種是時間抽取FFT演算法(DIT),將N點DFT輸入序列x(n)、在時域分解成2個N/2點序列而x1(n)和x2(n)。前者是從原序列中按偶數序號抽取而成,而後者則按奇數序號抽取而成。DIT就是這樣有規律地按奇、偶次序逐次進行分解所構成的一種快速演算法。
分裂基演算法(RSFFT) 1984年由P.杜哈美爾和H.赫爾曼等導出的一種比庫利圖基演算法更加有效的改進演算法,其基本思想是在變換式的偶部採用基2演算法,在變換式的奇部採用基4演算法。優點是具有相對簡單的結構,非常適用於實對稱數據,對長度N=2能獲得最少的運算量(乘法和加法),所以是選用固定基演算法中的一種最佳折衷演算法。
㈦ 呵呵,今天咋不見電腦高手呢
winrar的rar文件和winzip的zip文件壓縮演算法基本相同
zip 的壓縮原理與實現
作者: NCS 時間: 2005-01-05 文檔類型: 轉載 來自: 藍色理想
瀏覽統計: total: 563 year: 563 quarter: 329 month: 141 week: 23 today: 5
第 1 頁 zip 的壓縮原理與實現
第 2 頁 編碼式壓縮的要求及方法
第 3 頁 霍夫曼演算法
第 4 頁 lz77 演算法壓縮
無損數據壓縮是一件奇妙的事情,想一想,一串任意的數據能夠根據一定的規則轉換成只有原來 1/2 - 1/5 長度的數據,並且能夠按照相應的規則還原到原來的樣子,聽起來真是很酷。
半年前,苦熬過初學 vc 時那段艱難的學習曲線的我,對 MFC、SDK 開始失望和不滿,這些雖然不算易學,但和 DHTML 沒有實質上的區別,都是調用微軟提供的各種各樣的函數,不需要你自己去創建一個窗口,多線程編程時,也不需要你自己去分配 CPU 時間。我也做過驅動,同樣,有DDK(微軟碟機動開發包),當然,也有 DDK 的「參考手冊」,連一個最簡單的數據結構都不需要你自己做,一切都是函數、函數……
微軟的高級程序員編寫了函數讓我們這些搞應用的去調用,我不想在這里貶低搞應用的人,正是這些應用工程師連接起了科學和社會之間的橋梁,將來可以做銷售,做管理,用自己逐漸積累起來的智慧和經驗在社會上打拚。
但是,在技術上來說,誠實地說,這並不高深,不是嗎?第一流的公司如微軟、Sybase、Oracle 等總是面向社會大眾的,這樣才能有巨大的市場。但是他們往往也是站在社會的最頂層的:操作系統、編譯器、資料庫都值得一代代的專家去不斷研究。這些帝國般的企業之所以偉大,恐怕不是「有經驗」、「能吃苦」這些中國特色的概念所能涵蓋的,艱深的技術體系、現代的管理哲學、強大的市場能力都是缺一不可的吧。我們既然有志於技術,並且正在起步階段,何必急不可耐地要轉去做「管理」,做「青年才俊」,那些所謂的「成功人士」的根底能有幾何,這樣子浮躁,胸中的規模和格局能有多大?
在我發現vc只是一個用途廣泛的編程工具,並不能代表「知識」、「技術」的時候,我有些失落,無所不能的不是我,而是 MFC、SDK、DDK,是微軟的工程師,他們做的,正是我想做的,或者說,我也想成為那種層次的人,現在我知道了,他們是專家,但這不會是一個夢,有一天我會做到的,為什麼不能說出我的想法呢。那時公司做的系統里有一個壓縮模塊,領導找了一個 zlib 庫,不讓我自己做壓縮演算法,站在公司的立場上,我很理解,真的很理解,自己做演算法要多久啊。但那時自己心中隱藏的一份倔強驅使我去尋找壓縮原理的資料,我完全沒有意識到,我即將打開一扇大門,進入一個神奇的「數據結構」的世界。「計算機藝術」的第一線陽光,居然也照到了我這樣一個平凡的人的身上。
上面說到「計算機藝術」,或者進一步細化說「計算機編程藝術」,聽起來很深奧,很高雅,但是在將要進入專業的壓縮演算法的研究時,我要請大家做的第一件事情是:忘掉自己的年齡、學歷,忘掉自己的社會身份,忘掉編程語言,忘掉「面向對象」、「三層架構」等一切術語。把自己當作一個小孩,有一雙求知的眼睛,對世界充滿不倦的、單純的好奇,唯一的前提是一個正常的具有人類理性思維能力的大腦。
下面就讓我們開始一段神奇的壓縮演算法之旅吧:
1. 原理部分:
有兩種形式的重復存在於計算機數據中,zip 就是對這兩種重復進行了壓縮。
一種是短語形式的重復,即三個位元組以上的重復,對於這種重復,zip用兩個數字:1.重復位置距當前壓縮位置的距離;2.重復的長度,來表示這個重復,假設這兩個數字各佔一個位元組,於是數據便得到了壓縮,這很容易理解。
一個位元組有 0 - 255 共 256 種可能的取值,三個位元組有 256 * 256 * 256 共一千六百多萬種可能的情況,更長的短語取值的可能情況以指數方式增長,出現重復的概率似乎極低,實則不然,各種類型的數據都有出現重復的傾向,一篇論文中,為數不多的術語傾向於重復出現;一篇小說,人名和地名會重復出現;一張上下漸變的背景圖片,水平方向上的像素會重復出現;程序的源文件中,語法關鍵字會重復出現(我們寫程序時,多少次前後、paste?),以幾十 K 為單位的非壓縮格式的數據中,傾向於大量出現短語式的重復。經過上面提到的方式進行壓縮後,短語式重復的傾向被完全破壞,所以在壓縮的結果上進行第二次短語式壓縮一般是沒有效果的。
第二種重復為單位元組的重復,一個位元組只有256種可能的取值,所以這種重復是必然的。其中,某些位元組出現次數可能較多,另一些則較少,在統計上有分布不均勻的傾向,這是容易理解的,比如一個 ASCII 文本文件中,某些符號可能很少用到,而字母和數字則使用較多,各字母的使用頻率也是不一樣的,據說字母 e 的使用概率最高;許多圖片呈現深色調或淺色調,深色(或淺色)的像素使用較多(這里順便提一下:png 圖片格式是一種無損壓縮,其核心演算法就是 zip 演算法,它和 zip 格式的文件的主要區別在於:作為一種圖片格式,它在文件頭處存放了圖片的大小、使用的顏色數等信息);上面提到的短語式壓縮的結果也有這種傾向:重復傾向於出現在離當前壓縮位置較近的地方,重復長度傾向於比較短(20位元組以內)。這樣,就有了壓縮的可能:給 256 種位元組取值重新編碼,使出現較多的位元組使用較短的編碼,出現較少的位元組使用較長的編碼,這樣一來,變短的位元組相對於變長的位元組更多,文件的總長度就會減少,並且,位元組使用比例越不均勻,壓縮比例就越大。
在進一步討論編碼的要求以及辦法前,先提一下:編碼式壓縮必須在短語式壓縮之後進行,因為編碼式壓縮後,原先八位二進制值的位元組就被破壞了,這樣文件中短語式重復的傾向也會被破壞(除非先進行解碼)。另外,短語式壓縮後的結果:那些剩下的未被匹配的單、雙位元組和得到匹配的距離、長度值仍然具有取值分布不均勻性,因此,兩種壓縮方式的順序不能變。
在編碼式壓縮後,以連續的八位作為一個位元組,原先未壓縮文件中所具有的位元組取值不均勻的傾向被徹底破壞,成為隨機性取值,根據統計學知識,隨機性取值具有均勻性的傾向(比如拋硬幣試驗,拋一千次,正反面朝上的次數都接近於 500 次)。因此,編碼式壓縮後的結果無法再進行編碼式壓縮。
短語式壓縮和編碼式壓縮是目前計算機科學界研究出的僅有的兩種無損壓縮方法,它們都無法重復進行,所以,壓縮文件無法再次壓縮(實際上,能反復進行的壓縮演算法是不可想像的,因為最終會壓縮到 0 位元組)。
短語式重復的傾向和位元組取值分布不均勻的傾向是可以壓縮的基礎,兩種壓縮的順序不能互換的原因也說了,下面我們來看編碼式壓縮的要求及方法:
首先,為了使用不定長的編碼表示單個字元,編碼必須符合「前綴編碼」的要求,即較短的編碼決不能是較長編碼的前綴,反過來說就是,任何一個字元的編碼,都不是由另一個字元的編碼加上若干位 0 或 1 組成,否則解壓縮程序將無法解碼。
看一下前綴編碼的一個最簡單的例子:
符號 編碼
A 0
B 10
C 110
D 1110
E 11110
有了上面的碼表,你一定可以輕松地從下面這串二進制流中分辨出真正的信息內容了:
1110010101110110111100010 - DABBDCEAAB
要構造符合這一要求的二進制編碼體系,二叉樹是最理想的選擇。考察下面這棵二叉樹:
根(root)
0| 1
+-------+--------+
0 |1 0 | 1
+-----+------++----+----+
||| |
a |d e
0|1
+-----+-----+
| |
b c
要編碼的字元總是出現在樹葉上,假定從根向樹葉行走的過程中,左轉為0,右轉為1,則一個字元的編碼就是從根走到該字元所在樹葉的路徑。正因為字元只能出現在樹葉上,任何一個字元的路徑都不會是另一字元路徑的前綴路徑,符合要求的前綴編碼也就構造成功了:
a - 00 b - 010 c - 011 d - 10 e - 11
接下來來看編碼式壓縮的過程:
為了簡化問題,假定一個文件中只出現了 a,b,c,d ,e四種字元,它們的出現次數分別是
a : 6次
b : 15次
c : 2次
d : 9次
e : 1次
如果用定長的編碼方式為這四種字元編碼: a : 000 b : 001 c : 010 d : 011 e : 100
那麼整個文件的長度是 3*6 + 3*15 + 3*2 + 3*9 + 3*1 = 99
用二叉樹表示這四種編碼(其中葉子節點上的數字是其使用次數,非葉子節點上的數字是其左右孩子使用次數之和):
根
|
+---------33---------+
| |
+----32---+ +----1---+
|| | |
+-21-+ +-11-+ +--1--+
| | | | | |
6 15 29 1
(如果某個節點只有一個子節點,可以去掉這個子節點。)
根
|
+------33------+
||
+-----32----+ 1
| |
+--21--+ +--11--+
|| ||
6 152 9
現在的編碼是: a : 000 b : 001 c : 010 d : 011 e : 1 仍然符合「前綴編碼」的要求。
第一步:如果發現下層節點的數字大於上層節點的數字,就交換它們的位置,並重新計算非葉子節點的值。
先交換11和1,由於11個位元組縮短了一位,1個位元組增長了一位,總文件縮短了10位。
根
|
+----------33---------+
||
+-----22----++----11----+
| || |
+--21--+ 1 2 9
| |
6 15
再交換15和1、6和2,最終得到這樣的樹:
根
|
+----------33---------+
||
+-----18----+ +----15----+
| | | |
+--3--+ 156 9
| |
2 1
這時所有上層節點的數值都大於下層節點的數值,似乎無法再進一步壓縮了。但是我們把每一層的最小的兩個節點結合起來,常會發現仍有壓縮餘地。
第二步:把每一層的最小的兩個節點結合起來,重新計算相關節點的值。
在上面的樹中,第一、二、四三層都只有一或二個節點,無法重新組合,但第三層上有四個節點,我們把最小的3和6結合起來,並重新計算相關節點的值,成為下面這棵樹。
根
|
+----------33---------+
| |
+------9-----+ +----24----+
| | | |
+--3--+ 6159
| |
21
然後,再重復做第一步。
這時第二層的9小於第三層的15,於是可以互換,有9個位元組增長了一位,15個位元組縮短了一位,文件總長度又縮短了6位。然後重新計算相關節點的值。
根
|
+----------33---------+
||
15 +----18----+
||
+------9-----+ 9
| |
+--3--+6
| |
21
這時發現所有的上層節點都大於下層節點,每一層上最小的兩個節點被並在了一起,也不可能再產生比同層其他節點更小的父節點了。
這時整個文件的長度是 3*6 + 1*15 + 4*2 + 2*9 + 4*1 = 63
這時可以看出編碼式壓縮的一個基本前提:各節點之間的值要相差比較懸殊,以使某兩個節點的和小於同層或下層的另一個節點,這樣,交換節點才有利益。
所以歸根結底,原始文件中的位元組使用頻率必須相差較大,否則將沒有兩個節點的頻率之和小於同層或下層其他節點的頻率,也就無法壓縮。反之,相差得越懸殊,兩個節點的頻率之和比同層或下層節點的頻率小得越多,交換節點之後的利益也越大。
在這個例子中,經過上面兩步不斷重復,得到了最優的二叉樹,但不能保證在所有情況下,都能通過這兩步的重復得到最優二叉樹,下面來看另一個例子:
根
|
+---------19--------+
||
+------12------+7
||
+---5---++---7---+
||||
+-2-++-3-++-3-++-4-+
||||||||
11121222
這個例子中,所有上層節點都大於等於下層節點,每一層最小的兩個節點結合在了一起,但仍然可以進一步優化:
根
|
+---------19--------+
||
+------12------+7
||
+---4---++---8---+
||||
+-2-++-2-++-4-++-4-+
||||||||
11112222
通過最低一層的第4第5個節點對換,第3層的8大於第2層的7。
到這里,我們得出這樣一個結論:一棵最優二叉編碼樹(所有上層節點都無法和下層節點交換),必須符合這樣兩個條件:
1.所有上層節點都大於等於下層節點。
2.某節點,設其較大的子節點為m,較小的子節點為n,m下的任一層的所有節點都應大於等於n下的該層的所有節點。
當符合這兩個條件時,任一層都無法產生更小的節點去和下層節點交換,也無法產生更大的節點去和上層節點交換。
上面的兩個例子是比較簡單的,實際的文件中,一個位元組有256種可能的取值,所以二叉樹的葉子節點多達256個,需要不斷的調整樹形,最終的樹形可能非常復雜,有一種非常精巧的演算法可以快速地建起一棵最優二叉樹,這種演算法由D.Huffman(戴·霍夫曼)提出,下面我們先來介紹霍夫曼演算法的步驟,然後再來證明通過這么簡單的步驟得出的樹形確實是一棵最優二叉樹。
霍夫曼演算法的步驟是這樣的:
·從各個節點中找出最小的兩個節點,給它們建一個父節點,值為這兩個節點之和。
·然後從節點序列中去除這兩個節點,加入它們的父節點到序列中。
重復上面兩個步驟,直到節點序列中只剩下唯一一個節點。這時一棵最優二叉樹就已經建成了,它的根就是剩下的這個節點。
仍以上面的例子來看霍夫曼樹的建立過程。
最初的節點序列是這樣的:
a(6) b(15) c(2) d(9) e(1)
把最小的c和e結合起來
| (3)
a(6) b(15) d(9)+------+------+
| |
ce
不斷重復,最終得到的樹是這樣的:
根
|
+-----33-----+
||
15 +----18----+
| |
9 +------9-----+
| |
6 +--3--+
| |
21
這時各個字元的編碼長度和前面我們說過的方法得到的編碼長度是相同的,因而文件的總長度也是相同的: 3*6 + 1*15 + 4*2 + 2*9 + 4*1 = 63
考察霍夫曼樹的建立過程中的每一步的節點序列的變化:
6 15291
6 1593
159 9
1518
33
下面我們用逆推法來證明對於各種不同的節點序列,用霍夫曼演算法建立起來的樹總是一棵最優二叉樹:
對霍夫曼樹的建立過程運用逆推法:
當這個過程中的節點序列只有兩個節點時(比如前例中的15和18),肯定是一棵最優二叉樹,一個編碼為0,另一個編碼為1,無法再進一步優化。
然後往前步進,節點序列中不斷地減少一個節點,增加兩個節點,在步進過程中將始終保持是一棵最優二叉樹,這是因為:
1.按照霍夫曼樹的建立過程,新增的兩個節點是當前節點序列中最小的兩個,其他的任何兩個節點的父節點都大於(或等於)這兩個節點的父節點,只要前一步是最優二叉樹,其他的任何兩個節點的父節點就一定都處在它們的父節點的上層或同層,所以這兩個節點一定處在當前二叉樹的最低一層。
2.這兩個新增的節點是最小的,所以無法和其他上層節點對換。符合我們前面說的最優二叉樹的第一個條件。
3.只要前一步是最優二叉樹,由於這兩個新增的節點是最小的,即使同層有其他節點,也無法和同層其他節點重新結合,產生比它們的父節點更小的上層節點來和同層的其他節點對換。它們的父節點小於其他節點的父節點,它們又小於其他所有節點,只要前一步符合最優二叉樹的第二個條件,到這一步仍將符合。
這樣一步步逆推下去,在這個過程中霍夫曼樹每一步都始終保持著是一棵最優二叉樹。
由於每一步都從節點序列中刪除兩個節點,新增一個節點,霍夫曼樹的建立過程共需 (原始節點數 - 1) 步,所以霍夫曼演算法不失為一種精巧的編碼式壓縮演算法。
附:對於 huffman 樹,《計算機程序設計藝術》中有完全不同的證明,大意是這樣的:
1.二叉編碼樹的內部節點(非葉子節點)數等於外部節點(葉子節點)數減1。
2.二叉編碼樹的外部節點的加權路徑長度(值乘以路徑長度)之和,等於所有內部節點值之和。(這兩條都可以通過對節點數運用數學歸納法來證明,留給大家做練習。)
3.對 huffman 樹的建立過程運用逆推,當只有一個內部節點時,肯定是一棵最優二叉樹。
4.往前步進,新增兩個最小的外部節點,它們結合在一起產生一個新的內部節點,當且僅當原先的內部節點集合是極小化的,加入這個新的內部節點後仍是極小化的。(因為最小的兩個節點結合在一起,並處於最低層,相對於它們分別和其他同層或上層節點結合在一起,至少不會增加加權路徑長度。)
5.隨著內部節點數逐個增加,內部節點集合總維持極小化。
2.實現部分
如果世界上從沒有一個壓縮程序,我們看了前面的壓縮原理,將有信心一定能作出一個可以壓縮大多數格式、內容的數據的程序,當我們著手要做這樣一個程序的時候,會發現有很多的難題需要我們去一個個解決,下面將逐個描述這些難題,並詳細分析 zip 演算法是如何解決這些難題的,其中很多問題帶有普遍意義,比如查找匹配,比如數組排序等等,這些都是說不盡的話題,讓我們深入其中,做一番思考。
我們前面說過,對於短語式重復,我們用「重復距當前位置的距離」和「重復的長度」這兩個數字來表示這一段重復,以實現壓縮,現在問題來了,一個位元組能表示的數字大小為 0 -255,然而重復出現的位置和重復的長度都可能超過 255,事實上,二進制數的位數確定下來後,所能表示的數字大小的范圍是有限的,n位的二進制數能表示的最大值是2的n次方減1,如果位數取得太大,對於大量的短匹配,可能不但起不到壓縮作用,反而增大了最終的結果。針對這種情況,有兩種不同的演算法來解決這個問題,它們是兩種不同的思路。一種稱為 lz77 演算法,這是一種很自然的思路:限制這兩個數字的大小,以取得折衷的壓縮效果。例如距離取 15 位,長度取 8 位,這樣,距離的最大取值為 32 k - 1,長度的最大取值為 255,這兩個數字占 23 位,比三個位元組少一位,是符合壓縮的要求的。讓我們在頭腦中想像一下 lz77 演算法壓縮進行時的情況,會出現有意思的模型:
最遠匹配位置->當前處理位置->
———┸—————————————————╂—————————————>壓縮進行方向
已壓縮部分┃未壓縮部分
在最遠匹配位置和當前處理位置之間是可以用來查找匹配的「字典」區域,隨著壓縮的進行,「字典」區域從待壓縮文件的頭部不斷地向後滑動,直到達到文件的尾部,短語式壓縮也就結束了。
解壓縮也非常簡單:
┎————————拷貝————————┒
匹配位置┃當前處理位置┃
┃<——匹配長度——>┃┠—————∨————┨
———┸——————————┸———————╂——————————┸—>解壓進行方向
已解壓部分┃未解壓部分
不斷地從壓縮文件中讀出匹配位置值和匹配長度值,把已解壓部分的匹配內容拷貝到解壓文件尾部,遇到壓縮文件中那些壓縮時未能得到匹配,而是直接保存的單、雙位元組,解壓時只要依次直接拷貝到文件尾部即可,直到整個壓縮文件處理完畢。
lz77演算法模型也被稱為「滑動字典」模型或「滑動窗口」模型,由於它限制匹配的最大長度,對於某些存在大量的極長匹配的文件來說,這種折衷演算法顯出了缺陷。另有一種lzw演算法對待壓縮文件中存在大量極長匹配的情況進行了完全不同的演算法設計,並且只用一個數字來表示一段短語,下面來描述一下lzw的壓縮解壓過程,然後來綜合比較兩者的適用情況。
lzw的壓縮過程:
1) 初始化一個指定大小的字典,把 256 種位元組取值加入字典。
2) 在待壓縮文件的當前處理位置尋找在字典中出現的最長匹配,輸出該匹配在字典中的序號。
3) 如果字典沒有達到最大容量,把該匹配加上它在待壓縮文件中的下一個位元組加入字典。
4) 把當前處理位置移到該匹配後。
5) 重復 2、3、4 直到文件輸出完畢。
lzw 的解壓過程:
1) 初始化一個指定大小的字典,把 256 種位元組取值加入字典。
2) 從壓縮文件中順序讀出一個字典序號,根據該序號,把字典中相應的數據拷貝到解壓文件尾部。
3) 如果字典沒有達到最大容量,把前一個匹配內容加上當前匹配的第一個位元組加入字典。
4) 重復 2、3 兩步直到壓縮文件處理完畢。
從 lzw 的壓縮過程,我們可以歸納出它不同於 lz77 演算法的一些主要特點:
1) 對於一段短語,它只輸出一個數字,即字典中的序號。(這個數字的位數決定了字典的最大容量,當它的位數取得太大時,比如 24 位以上,對於短匹配佔多數的情況,壓縮率可能很低。取得太小時,比如 8 位,字典的容量受到限制。所以同樣需要取捨。)
2) 對於一個短語,比如 abcd ,當它在待壓縮文件中第一次出現時,ab 被加入字典,第二次出現時,abc 被加入字典,第三次出現時,abcd 才會被加入字典,對於一些長匹配,它必須高頻率地出現,並且字典有較大的容量,才會被最終完整地加入字典。相應地,lz77 只要匹配在「字典區域」中存在,馬上就可以直接使用。
3) 一個長匹配被加入字典的過程,是從兩個位元組開始,逐次增長一個位元組,確定了字典的最大容量,也就間接確定了匹配的可能的最大長度。相對於 lz77 用兩個數字來表示一個短語,lzw 只用一個數字來表示一個短語,因此,「字典序號」的位數可以取得多一點(二進制數多一位,意味著數值大一倍),也就是說最長匹配可以比 lz77 更長,當某些超長匹配高頻率地出現,直到被完整地加入字典後,lzw將開始彌補初期的低效,逐漸顯出自己的優勢。
可以看出,在多數情況下,lz77 擁有更高的壓縮率,而在待壓縮文件中占絕大多數的是些超長匹配,並且相同的超長匹配高頻率地反復出現時,lzw 更具優勢,GIF 就是採用了 lzw 演算法來壓縮背景單一、圖形簡單的圖片。zip 是用來壓縮通用文件的,這就是它採用對大多數文件有更高壓縮率的 lz77 演算法的原因。
接下來 zip 演算法將要解決在「字典區域」中如何高速查找最長匹配的問題。
㈧ 導線的時延公式是什麼 一根導線時延100ps,平均分成兩段後每段時延是50ps嗎
是的,因為導線的延時是根據電磁波在導線中傳輸的時間決定的,基本上3cm延遲100ps,延遲時間和長度成正比
㈨ 快速傅里葉變換的演算法類型
FFT演算法很多,根據實現運算過程是否有指數因子WN可分為有、無指數因子的兩類演算法。
有指數因子的演算法
經典庫利-圖基演算法 當輸入序列的長度N不是素數(素數只能被1而它本身整除)而是可以高度分解的復合數,即N=N1N2N3…Nr時,若N1=N2=…=Nr=2,N=2則N點DFT的計算可分解為N=2×N/2,即兩個N/2點DFT計算的組合,而N/2點DFT的計算又可分解為N/2=2×N/4,即兩個N/4點DFT計算的組合。依此類推,使DFT的計算形成有規則的模式,故稱之為以2為基底的FFT演算法。同理,當N=4時,則稱之為以4為基底的FFT演算法。當N=N1·N2時,稱為以N1和N2為基底的混合基演算法。
在這些演算法中,基2演算法用得最普遍。通常按序列在時域或在頻域分解過程的不同,又可分為兩種:一種是時間抽取FFT演算法(DIT),將N點DFT輸入序列x(n)、在時域分解成2個N/2點序列而x1(n)和x2(n)。前者是從原序列中按偶數序號抽取而成,而後者則按奇數序號抽取而成。DIT就是這樣有規律地按奇、偶次序逐次進行分解所構成的一種快速演算法。
分裂基演算法(RSFFT) 1984年由P.杜哈美爾和H.赫爾曼等導出的一種比庫利圖基演算法更加有效的改進演算法,其基本思想是在變換式的偶部採用基2演算法,在變換式的奇部採用基4演算法。優點是具有相對簡單的結構,非常適用於實對稱數據,對長度N=2能獲得最少的運算量(乘法和加法),所以是選用固定基演算法中的一種最佳折衷演算法。