-
查找的基本概念
-
列表: 有同一類型的數據元素組成的集合
-
關鍵碼: 數據元素中的某個數據項, 可以標識列表中的一個或一組數據元素
-
鍵值: 關鍵碼的值
-
主關鍵碼: 可以唯一標識一個記錄的關鍵碼
-
次關鍵碼: 不能唯一標識一個記錄的關鍵碼
-
查找: 在具有相同數據類型的記錄構成的集合中找出滿足給定條件的記錄
-
查找的結果: 若在查找集合中找到了與給定值相匹配的記錄, 則查找成功; 否則查找失敗
-
動態查找: 不涉及插入和刪除操作的查找
-
靜態查找: 涉及插入和刪除操作的查找
-
查找結構: 面向查找操作的數據結構, 即 基於查找的數據結構
-
線性表: 適用於靜態查找, 主要採用順序查找技術, 折半查找技術
-
樹表: 適用於動態查找, 主要採用二叉排序樹的查找技術
-
散列表: 靜態查找和動態查找均適用, 主要採用散列技術
-
線性表的查找技術:
-
順序查找:
-
基本思想: 從線性表的一端向另一端逐個將關鍵碼與給定值進行比較, 若相等, 則查找成功, 給出該記錄在表中的位置
-
若整個表檢測完仍未找到與給定值相等的關鍵碼, 則查找失敗, 給出失敗信息
-
順序查找的優點: 算法簡單而且應用面廣
-
對錶中記錄的存儲結構及沒有任何要求, 順序存儲和鏈式存儲均可
-
對錶中記錄的有序性也沒有要求, 無論記錄是否按關鍵碼有序均可
-
順序查找的缺點: 平均查找長度較大, 特別是當代查找集合元素較多時, 查找效率較低
-
普通的順序查找方法
-
帶監視哨的查找技術
-
折半查找:
-
適用條件:
-
線性表中的記錄必須按關鍵碼有序
-
必須採用順序存儲
-
基本思想: 在有序表中, 去中間記錄作爲比較對象
-
若給定的值與中間記錄的關鍵碼相等, 則查找成功
-
若給定的值小於中間記錄的關鍵碼, 則在中間記錄的左半區繼續查找
-
若給定的值大於中間記錄的關鍵碼, 則在中間記錄的右半區繼續查找
-
不斷重複上述過程, 直到查找成功, 或查找的區域無記錄, 則查找失敗
-
折半查找判定樹
-
判定樹: 折半查找的過程可以用二叉樹來描述
-
樹中的每一個結點對應有序表中的一個記錄
-
結點的值爲該記錄在表中的位置
-
通常稱這個描述折半查找過程的二叉樹爲折半查找判定樹, 簡稱判定樹
-
當n=0時,折半查找判定樹爲空;
-
當n>0時
-
折半查找判定樹的根結點爲mide(n+1)/2
-
任意兩棵折半查找判定樹, 若他們的節點個數相同, 則他們的結構完全相同
-
具有n個結點的折半查找樹的高度爲[log_2~n]+1
-
任意結點的左右子樹中的結點個數最多相差1
-
任意結點左右子樹的高度最多相差1
-
任意兩個葉子結點所處的層數最多相差1
-
查找成功: 在表中查找任意記錄的過程, 即是折半查找判定樹從根結點到該結點的路徑, 和給定值比較次數等於該記錄結點在樹中的層數
-
#include<iostream>
-
using namespace std;
-
const int MaxSize=100;
-
class LineSearch{
-
public:
-
LineSearch(int a[],int n);
-
int SeqSearch(int k);//順序查找
-
int BinSearch1(int k);//折半查找
-
int BinSearch2(int k){int high=length;BinSearch2(1,high,k);}
-
private:
-
int data[MaxSize];
-
int length;
-
int BinSearch2(int low,int high,int k);//折半遞歸查找
-
};
-
LineSearch::LineSearch(int a[],int n){
-
length=n;
-
for(int i=1;i<=n;i++)
-
data[i]=a[i];
-
}
-
int LineSearch::SeqSearch(int k){
-
data[0]=k;
-
int i=length;
-
while(data[i]!=k) i--;
-
return i;
-
}
-
int LineSearch::BinSearch1(int k){
-
int low=1;
-
int high=length;
-
int mide;
-
while(low<=high){
-
mide=(low+high)/2;
-
if(data[mide]>k) high=mide-1;
-
else if(data[mide]<k) low=mide+1;
-
else return mide;
-
}
-
return 0;
-
}
-
int LineSearch::BinSearch2(int low,int high,int k){
-
if(low>high) return 0;
-
else{
-
int mide=(low+high)/2;
-
if(data[mide]>k)
-
return BinSearch2(low,mide-1,k);
-
else if(data[mide]<k)
-
return BinSearch2(mide+1,high,k);
-
else return mide;
-
}
-
}
-
int main(){
-
int data[6]={0,3,6,2,7,9};
-
int data0[6]={0,2,3,6,7,9};
-
LineSearch li(data0,5);
-
int n;
-
while(cin>>n){
-
int k=li.BinSearch2(n);
-
if(k==0) cout<<"no answer"<<endl;
-
else cout<<k<<endl;
-
}
-
}
-
二叉排序樹:
-
或者是一個空的二叉樹, 或者是具有下列性質的二叉樹
-
若它的左子樹不空, 則左子樹上的所有結點的值均小於根結點的值
-
若它的右子樹不空, 則右子樹上的所有結點的值均小於根結點的值
-
它的左右子樹也是二叉排序樹
-
中序遍歷二叉排序樹可以得到一個按關鍵碼有序的序列
-
二叉排序樹的插入:
-
若二叉排序樹爲空樹, 則將新插入的結點爲新的根結點; 否則, 新插入的結點必爲一個新的葉子結點, 其插入位置由查找過程得到
-
二叉排序樹的刪除算法:
-
被刪除的是葉子結點: 將雙親結點中相應的指針域的值改爲空
-
被刪除的結點只有左子樹或者右子樹: 將雙親結點的相應指針域的值 指向被刪除結點的左子樹(或者右子樹)
-
被刪除的結點既有左子樹也有右子樹: 以其前驅(左子樹中的最大值)代替之, 然後再刪除該結點的前驅結點. 以其後繼(右子樹中的最小值)代替之, 然後再刪除該前驅結點
-
平衡二叉樹:
-
或者是一棵空的二叉排序樹, 或者是具有下列性質的二叉排序樹
-
根結點的左子樹和右子樹的深度最多相差1
-
根結點的左子樹和右子樹也都是平衡二叉樹
-
平衡因子: 結點的平衡因子是該結點的左子樹的深度與右子樹的深度之差
-
最小不平衡子樹: 在平衡二叉樹的構造過程中, 以距離插入結點最近, 且平衡因子絕對值大於1的結點爲根的子樹
-
LL型
-
RR型
-
LR型
-
RL型
-
散列表:
-
直接定址法: 適用於事先知道關鍵碼, 關鍵碼集合不是很大且連續性較好
-
除留餘數法: H(key)=key mod p
-
一般情況下, 選p爲小於或等於表長(最好接近表長)的最小素數
-
除留餘數法是一種最簡單, 也是最常用的構造散列函數的方法, 並且不要求事先知道關鍵碼的分佈
-
數字分析法適用情況於事先知道關鍵碼的分佈, 關鍵碼均勻分佈
-
平方取中法
-
摺疊法(分段摺疊法)
-
衝突處理方法:
-
開放地址法
-
鏈地址法
-
建立公共溢出區
-
散列表的基本思想: 在記錄的存儲地址和它的關鍵碼之間建立一個確定的對應關係. 這樣不經過比較, 一次就能讀取得到所查元素的查找方法
-
散列表: 採用散列技術將記錄存儲在一塊連續的存儲空間中, 這塊連續的存儲空間稱爲散列表
-
散列函數: 將關鍵碼映射爲散列表中適當存儲位置的函數
-
散列地址: 由散列函數所得的存儲串地址
-
散列技術既是一種查找技術, 又是一種存儲技術
-
散列主要是面向查找的存儲結構
-
散列表一般不適用於允許多個記錄有相同關鍵碼的情況,
-
有衝突, 降低了查找效率, 體現不出計算式查找的優點
-
散列法也不適用於範圍查找
-
不能找到最大值, 最小值
-
也不可能找到在某一範圍內的記錄
-
衝突: 對於兩個不同的關鍵碼, 有相同的存儲位置
-
散列函數設計的原則:
-
計算簡單
-
函數值即散列地址分佈均勻
-
衝突的處理:
-
開散列方法:拉鍊法, 鏈地址法
-
閉散列方法: 開放定址法
-
建立公共溢出區
-
有關鍵碼得到的散列地址一旦產生了衝突, 就去尋找下一個空的散列地址, 並將記錄存入
-
線性探測法: 當衝突發生時, 從衝突位置的下一個位置起, 依次尋找空的散列地址
-
二次探測法
-
隨機探測法
-
在falsh法
-
有開放定址法處理衝突得到的散列表叫閉散列表
-
裝填因子的作用:
-
表長=元素個數/ 裝填因子