從如今開始個人博客講介紹有關計算機基礎之數據結構的內容,我將會把核心的內容講解出來,但願能給你們帶來幫助。
算法
查找是在集合中尋找知足某種條件的數據元素的過程,分爲查找成功和查找失敗。
用於查找的數據元素集合稱爲查找表,由同一類型的數據元素組成,能夠是數組或者鏈表。能夠根據是否要動態修改查找表才能查找到元素分爲靜態查找表和動態查找表。
關鍵字是數據元素中惟一標識某元素的某個數據項的值,使用基於關鍵字的查找,查找結果是惟一的。
查找效率須要有一個評判標準,最通用的方法是用平均查找長度ASL評判。在查找過程當中,ASL是全部查找過程當中進行關鍵字比較次數的平均值。數學定義爲:
其中,n是查找表的長度,P(i)是查找第i個數據元素的機率,通常認爲每一個元素的P(i)都相等,爲1/n,C(i)是找到第i個數據元素所需進行比較的次數。
數組
順序查找又稱線性查找,主要用線性表進行查找,分爲對通常的無序線性表的順序查找和對按關鍵字有序的順序表的順序查找。
數據結構
這是最簡單的查找方法,基本思想是從線性表的一端開始,逐個檢查關鍵字是否知足給定的條件,查找成功返回在線性表中位置,查找失敗返回查找失敗的信息。
算法結構以下:性能
typedef struct{ ElemType *elem; //元素存儲空間的基址,建表時按實際長度分配,0號位留空放哨兵 int TableLen; //表的長度 }SSTable int Search_Seq(SSTable ST,ElemType Key){ ST.elem[0] = key; //哨兵 for(i = ST.TableLen;ST.elem[i] != key;--i); //從後往前找 return i; //不存在關鍵字爲key的元素,i爲0時退出for循環 }
將ST.elem[0]稱爲"哨兵",目的是使得算法裏循環沒必要判斷數組是否越界。當知足i == 0時能夠直接跳出,避免不須要的判斷語句,提升程序效率。
平均查找長度分析:有n個元素的線性表,當定位到第i個元素時,須要進行n-i+1次關鍵字的比較(從後往前比較),則C(i)=n-i+1。查找成功時,當每一個P(i)都相等,爲1/n時,順序查找的平均查找長度爲:
查找失敗時,與各關鍵字的比價次數是n+1次,則ASL(不成功)=n+1。
由上面的分析能夠知道,順序表的優勢是對數據存儲沒有要求,順序鏈表和鏈式鏈表皆可,對錶中記錄的有序性也沒有要求。缺點是當n比較大時,效率比較慢,ASL比較大。
3d
有序表的順序查找成功查找時和通常順序表的查找同樣,可是查找失敗時,由於在查找以前就知道表是關鍵字有序的,則查找失敗時能夠不用再比較表的另外一端就能返回查找失敗的信息,提升效率,下降ASL。
這裏只分析查找失敗的ASL,查找成功時的ASL和前面的同樣。查找失敗時,查找指針必定走到了某個失敗結點,是咱們虛構的空結點,實際上並不存在。因此查找結點失敗時所查找的長度等於它上面的圓形結點所在的層數,則ASL爲:
(1+2+3+4+..+n+n)÷(n+1) = n/2 + n/n+1
其中q(j)是到達第j個失敗結點的機率,相等查找機率的情形下爲1/(n+1),l(j)是第j個失敗結點所在的層數。
指針
折半查找又稱二分查找,用二分法進行查找,僅適用於有序的順序表,不能用於鏈表。
code
首先用要查找的關鍵字k與中間位置的結點的關鍵字相比較,這個中間結點把線性表分紅了兩個子表,若比較結果相等則查找完成;若不相等,再根據k與該中間結點關鍵字的比較大小肯定下一步查找哪一個子表,這樣遞歸進行下去,直到找到知足條件的結點或者該線性表中沒有這樣的結點。查找成功,返回查找的元素;查找不成功,返回查找失敗的信息。
折半查找有非遞歸和遞歸兩種方法。
blog
int Binary_Search(SeqList L,ElemType key){ int low = 0,high = L.TableLen - 1,mid; while(low <= high){ mid = (low + high) / 2 if(L.elem[mid] == key) return mid; else if(L.elem[mid] > key) high = mid - 1; else low = mid + 1; } return -1; }
int Binary_Search(SeqList L,ElemType key,int low,int high){ mid = (low + high) / 2 if(low <= high){ if(L.elem[mid] == key) return mid; else if(L.elem[mid] > key) return Binary_Search(L,key,low,mid - 1); else return Binary_Search(L,key,mid + 1,high); } return -1; } // di一次傳入的數據,這裏*L指向順序表,也能夠不加*,要具體而定 Binary_Search(*L,key,0,*L.TableLen - 1)
折半查找能夠用一個平衡二叉樹來描述,稱爲斷定樹,以下:
書中的圓形結點表示一個記錄,結點中的值爲該記錄的關鍵字值;樹中最下面的葉節點都是方形的,表示查找不成功的狀況。從中能夠看到,查找成功的長度是從根節點到目的圓結點的路徑上的結點數,而查找不成功時的查找長度爲從根節點到對應失敗結點的父結點的路徑上的結點數。這個二叉樹按中序遍歷元素逐步遞增。若序列有n個元素,則對應的斷定樹有n個圓形的非葉節點和n+1個方形的葉結點。
排序
用折半查找查找到給定值的比較次數不會超過樹的高度,在等機率查找時,查找成功的平均查找長度爲:
其中,h是樹高,而且元素個數爲n時樹高h爲 ,因此折半查找成功的時間複雜度爲 ,通常狀況下比順序查找的效率高。
查找失敗的時候,則計算失敗結點父結點的高度,而後ASL爲:
每一層失敗結點的父結點高度*失敗節點個數之和與失敗結點總數之差。
遞歸
折半查找須要線性表具備隨機存取的特性,則只適用於順序存儲結構,且要求元素按關鍵字有序排列。
分塊查找又稱索引順序查找,分塊查找是折半查找和順序查找的一種改進方法,折半查找雖然具備很好的性能,但其前提條件時線性表順序存儲並且按照關鍵碼排序,這一前提條件在結點樹很大且表元素動態變化時是難以知足的。而順序查找能夠解決表元素動態變化的要求,但查找效率很低。分塊查找吸取了順序查找和折半查找各自的優勢,既有動態結構,又適合於快速查找。
分塊查找要求把一個大的線性表分解成若干塊,每塊內的節點能夠任意存放,但塊與塊之間必須排序。此外,還要創建一個索引表,把每塊內的最大關鍵碼值做爲索引表的關鍵碼值,按塊的順序存放到一個輔助數組中。查找時,首先在索引表中進行查找,肯定要找的節點所在的塊。因爲索引表是排序的,所以,對索引表的查找能夠採用順序查找或折半查找;而後,在相應的塊內採用順序查找,便可找到對應的節點。
分塊查找的平均查找長度是索引查找和塊內查找平均長度之和。若一個查找表長度爲n,均勻分爲b塊,每塊有s個記錄,在等機率狀況下,塊內和索引表中均採用順序查找,則ASL爲:
ASL=(b+1)/2+(s+1)/2
此時,若s=√n,則平均查找長度取最小值√n+1 。
若對索引表進行折半查找時,則平均查找長度爲:
ASL=(s+1)/2+log2(b+1)-1 這裏要注意,log2(b+1)取最大值上限。