23.資料結構 查詢
1.查詢的基本概念
查詢表是由同一型別的資料元素(或記錄)構成的集合。由於“集合”中的資料元素之間存在著鬆散的關係,因此查詢表是一種應用靈便的結構。
關鍵字:用來標識一個資料元素(或記錄)的某個資料項的值。
主關鍵字:可唯一地標識一個記錄的關鍵字。(一對一,類似學號,工號)
次關鍵字:反之,用以標識若干記錄的關鍵字。(一對多,類似姓名,成績)
若查詢表中存在這樣一個記錄,則稱“查詢成功”。
查詢結果給出整個記錄的資訊,或指示該記錄在查詢表中的位置;
否則稱“查詢不成功”。
查詢結果給出“空記錄”或“空指標”。
對查詢表經常進行的操作:
1.查詢某個“特定”的資料元素是否在查詢表中;
2.檢索某個“特定”的資料元素的各種屬性;
3.在查詢表中插入一個資料元素;
4.刪除查詢表中的摸一個資料元素。
查詢表可分為兩類:
靜態查詢表:
僅作“查詢”(檢索)操作的查詢表。
動態查詢表:
作“插入”和“刪除”操作的查詢表。
有時在查詢之後,還需要將“查詢”結果為“不在查詢表中”的資料元素插入到查詢表中;或者,從查詢表中刪除其“查詢”結果為“在查詢表中”的資料元素,此類表為動態查詢表。
查詢演算法的評價指標:關鍵字的平均比較次數,也稱平均查詢長度ASL
(關鍵字比較次數的期望值)
n:記錄的個數
pi:查詢第i個記錄的概率(通常認為pi=1/n)
ci:找到第i個記錄所需的比較次數
2.線性表的查詢
2.1順序查詢(線性查詢)
應用範圍:
順序表或線性連結串列表示的靜態查詢表
表內元素之間無序
順序表的表示:
資料元素型別定義:
typedef struct
{
KeyType key;//關鍵字域
...//其他域
}ElemType;
typedef struct
{
//順序表結構型別定義
ElemType* R;//表基址
int length;//表長
}SSTable;
SSTable ST;//定義順序表ST
在順序表ST中查詢值為key的資料元素(從最後一個元素開始比較)
int Search_Seq(SSTable ST, KeyType key)
{
//若成功返回其位置資訊,否則返回0
for (i = ST.length; i >= 1; i--)
{
if (ST.R[i].key == key)
{
return i;
}
}
return 0;
}
//其他形式
int Search_Seq(SSTable ST, KeyType key)
{
for (i = ST.length; ST.R[i].key != key; i--)
if (i <= 0)
break;
if (i > 0)
return i;
else
return 0;
}
int Search_Seq(SSTable ST, KeyType key)
{
for (i = ST.length; ST.R[i].key != key && i>0; i--);
if (i > 0)
return i;
else
return 0;
}
順序查詢 改進:把待查關鍵字key存入表頭(“哨兵”、“監視哨”),從後往前逐個比較,可免去查詢過程中每一步都要檢測釋放查詢完畢,加快速度。
int Search_Seq(SSTable ST, KeyType key)
{
//設定監視哨的順序查詢
ST.R[0].key = key;
for (i = ST.length; ST.R[i].key != key; i--);
return i;
}
當ST.length較大時,此改進能使進行一次查詢所需的平均時間幾乎減少一半。
時間效率分析:
比較次數與key位置有關:
查詢第i個元素,需比較n-i+1次;
查詢失敗,需比較n+1次;
時間複雜度:O(n)
空間複雜度:一個輔助空間—O(1)
順序查詢的特點:
優點:演算法簡單,邏輯次序無要求,且不同儲存結構均適用。
缺點:ASL太長,時間效率太低。
2.2折半查詢(二分或對分查詢)
折半查詢:每次將待查記錄所在區間縮小一半。
折半查詢演算法(非遞迴演算法):
1.設表長為n,low、high和mid分別指向待查元素所在區間的上界、下界和中點,key為給定的要查詢的值
2.初始時,令low=1,high=n,mid=(low+high)/2的向下取整
3.讓k與mid指向的記錄比較
若key==R[mid].key,查詢成功
若key<R[mid].key,則high=mid-1
若key>R[mid].key,則low=mid+1
4.重複上述操作,直至low>high時,查詢失敗
int Search_Bin(SSTable ST, KeyType key)
{
low = 1;//置區間初值
high = ST.length;
while (low <= high)
{
mid = (low + high) / 2;
if (ST.R[mid].key == key)//找到待查元素
return mid;
else if (key < ST.R[mid].key)//縮小查詢區間
high = mid - 1;//繼續在前半區間進行查詢
else
low = mid + 1;//繼續在後半區間進行查詢
}
return 0;//順序表中不存在待查元素
}
折半查詢演算法(遞迴演算法):
int Search_Bin(SSTable ST, KeyType key,int low, int high)
{
if (low > high)//查詢補刀時返回0
return 0;
mid = (low + high) / 2;
if (key == ST.R[mid].key)
return mid;
else if (key < ST.R[mid].key)
Search_Bin(ST, key, low, mid - 1);
else
Search_Bin(ST, key, mid + 1, high);
return 0;
}
折半查詢的效能分析
折半查詢優點:效率比順序查詢高。
這般查詢缺點:只適用於有序表,且限於順序儲存結構(對線性連結串列無效)。
2.3分塊查詢(索引順序查詢)
3.樹表的查詢
3.1.二叉排序樹:
二叉排序樹的操作—查詢
typedef struct
{
KeyType key;//關鍵字項
InfoType otherinfo;//其他資料域
}ElemType;
typedef struct BSTNode
{
ElemType data;//資料域
struct BSTNode* lchild, * rchild;//左右孩子指標
}BSTNode, * BSTree;
BSTree T;//定義二叉排序樹T
二叉排序樹的遞迴查詢
BSTree SearchBST(BSTree T, KeyType key)
{
//二叉排序樹的遞迴查詢
if ((!T) || key == T->data.key)
return T;
else if (key < T->data.key)
return SearchBST(T->lchild, key);//在左子樹中繼續查詢
else
return SearchBST(T->rchild, key);//在右子樹中繼續查詢
}
二叉排序樹的查詢分析
二叉排序樹的查詢分析
二叉排序樹的操作—插入
二叉排序樹的操作—生成
從空樹出發,經過一系列的查詢、查詢操作後,可生成一棵二叉排序樹。
例:設查詢的關鍵字序列為{45,24,53,45,12,24,90},可生成二叉排序樹如下:
一個無序序列可通過構造二叉樹變程一個有序序列。構造樹的過程就是對無序序列進行排序的過程。
插入的結點均為葉子結點,故無序移動其他結點。相當於在有序序列上插入記錄而無需移動其他記錄。
但是,關鍵字的輸入順序不同,建立的二叉排序樹不同。
二叉排序樹的操作—刪除
從二叉排序樹中刪除一個結點,不能把以該結點為根的子樹都刪除,只能刪掉該結點,並且還應保證刪除後所得的二叉樹仍然滿足二叉排序樹的性質不變。
由於中序遍歷二叉排序樹可以得到一個遞增有序的序列。那麼,在二叉排序樹中刪去一個結點相當於刪去有序序列中的一個結點。
1.將因刪除結點而斷開的二叉連結串列重新連結起來。
2.防止重新連結後樹的高度增加。
總結:
3.2.平衡二叉樹
平衡二叉樹的定義:
又稱AVL樹
一棵平衡二叉樹或者是空樹,或者是具有以下性質的二叉排序樹:
1.左子樹與右子樹的高度之差的絕對值小於等於1;
2.左子樹和右子樹也是平衡二叉排序樹。
為了方便起見,給每個結點附加一個數字,給出該結點左子樹與右子樹的高度差。這個數字稱為結點的平衡因子(BF)。
平衡因子=結點左子樹的高度-結點右子樹的高度
根據平衡二叉樹的定義,平衡二叉樹上所有結點的平衡因子只能是-1、0或1。
失衡二叉排序樹的分析與調整
調整前先計算哪個結點是失衡結點
如果在一棵AVL樹中插入一個新結點後造成失衡,則必須重新調整樹的結構,使之恢復平衡
平衡調整的四種型別:
(1)LL型調整
AVL樹LL調整—例子:
(2)RR型調整
AVL樹RR調整—例子:
(3)LR型調整
AVL樹LR調整—例子:
(4)RL型調整
AVL樹RL調整—例子:
例題:
輸入關鍵字序列(16,3,7,11,9,26,18,14,15)給出構造一棵AVL樹的步驟。
3.3.B-樹
結點個數最多為階數-1,此題為5-1=4
結點個數最少為m/2取上限-1,此題為2
新增結點都是往葉子結點上新增
B-樹線是連在縫中的
用以下關鍵字序列{1,2,6,7,11,4,8,13,10,5,17,9,16,20,3,12,14,18,19,15}建立一棵5階B-樹。
對於該B-樹,給出刪除關鍵字8、16、15、4的過程。
3.4.B+樹
B+樹線是連在結點上的
4.雜湊表的查詢
雜湊表的基本概念
基本思想:記錄的儲存位置域關鍵字之間存在對應的關係。
對應關係—hash函式
Loc(i)=H(keyi)
優點:查詢效率高
缺點:空間效率低
雜湊表的若干術語
雜湊方法(雜湊法):
選取某個函式,依該函式按關鍵字計算元素的儲存位置,並按此存放;
查詢時,由同一個函式對給定值k計算地址,將k與地址單元中元素關鍵碼進行對比,確定查詢是否成功。
雜湊函式(雜湊函式):
雜湊方法中使用的轉換函式
雜湊表(雜湊表):
按照上述思想構造的表。
雜湊函式:H(key)=k
衝突:
不同的關鍵碼對映到同一個雜湊地址 key1≠key2,但是H(key1)=H(key2)。
同義詞:
具有相同函式值的多個關鍵字。
雜湊函式的構造方法
雜湊儲存:
選取某個函式,依該函式按關鍵字計算元素的儲存位置
在雜湊查詢法中,衝突是不可能避免的,只能儘可能減少。
1.直接定址法
Hash(key) = a*key + b (a,b為常數)
優點:以關鍵碼key的某個線性函式值為雜湊地址,不會產生衝突。
缺點:要佔用連續地址空間,空間效率低
例:{100,300,500,700,800,900},
雜湊函式 Hash(key) = key/100 (a=1/100,b=0)
2.除留餘數法
Hash(key) = key mod p (p是一個整數)
技巧:設表長為m,取p≤m且為質數
例:{15,23,27,38,53,61,70},
雜湊函式 Hash(key) = key mod 7
處理衝突的方法
1.開放地址法(開地址法)
基本思想:有衝突時就去尋找下一個空的雜湊地址,只要雜湊表足夠大,空的雜湊地址總能找到,並將資料元素存入。
1.1線性探測法
例:關鍵碼集為{47,7,9,11,16,92,22,8,3},雜湊表的表長為11;雜湊函式為Hash(key) = key mod 11;擬用線性探測法處理衝突。建雜湊表如下:
解釋:
①.47、7均是由雜湊函式得到的沒有衝突的雜湊地址;
②.Hash(29)=7,雜湊地址有衝突,需尋找下一個空的雜湊地址:
由H1=(Hash(29)+1) mod 11 =8,雜湊地址8為空,因此將29存入。
③.11、16、92均是由雜湊函式得到的沒有衝突的雜湊地址;
④.22、8、3(3的di為3)的情況同②
平均查詢長度ASL=(1+2+1+1+1+4+1+2+2)/9=1.67
1.2.二次探測法
關鍵碼集為{47,7,29,11,16,92,22,8,3}
設:雜湊函式為Hash(key) = key mod 11
其中:m為雜湊表長度,m要求是某個4k+3的質數;
di為增量序列
1.3.偽隨機探測法
(1 ≤ i < m)
其中:m為雜湊表長度
di為偽隨機數
2.鏈地址法(拉鍊法)
基本思想:相同雜湊地址的記錄鏈成一單連結串列,m個雜湊地址就設m個單連結串列,然後用一個陣列將m個單連結串列的表頭指標儲存起來,形成一個動態的結構。
鏈地址法建立雜湊表步驟:
Step1:取資料元素的關鍵字key,計算其雜湊函式值(地址)。若該地址對於的連結串列為空,則將該元素插入此連結串列;否則執行Step2解決衝突。
Step2:根據選擇的衝突處理方法,計算關鍵字key的下一個儲存地址。若該地址對於的連結串列不為空,則利用連結串列的前插法或後插法將該元素插入此連結串列。
鏈地址法的優點:
1.非同義詞不會衝突,無“聚集”現象。
2.連結串列上的結點空間動態申請,更適合於表長不確定的情況。
雜湊表的查詢
例:已知一組關鍵字{19,14,23,1,68,20,84,27,55,11,10,79},雜湊函式為:H(key) = key mod 13,雜湊表長為m = 16,設每個記錄的查詢概率相等。
(1)用線性探測再雜湊處理衝突,即
H(19) = 6
H(14) = 1
H(23) = 10
H(1) = 1 衝突,H(1)=(1 + 1) MOD 13 = 2
H(68) = 3
H(20) = 7
H(84) = 6 衝突,H(84)=(84 + 1) MOD 13 = 7
衝突,H(84)=(84 + 2) MOD 13 = 8
H(27) = 1 衝突,H(27)=(27 + 1) MOD 13 = 2
衝突,H(27)=(27 + 2) MOD 13 = 3
衝突,H(27)=(27 + 3) MOD 13 = 4
......
ASL = (1*6 + 2 + 3*3 + 4 + 9)/12 = 2.5
(2)鏈地址法處理衝突
對於關鍵字集{19,14,23,1,68,20,84,27,55,11,10,79},n=12
無序表查詢ASL=(n+1)/2=6.5
有序表折半查詢ASL=≈2.7
雜湊表上查詢ASL≠O(1)
雜湊表的查詢效率分析
使用平均查詢長度ASL來衡量查詢演算法,ASL取決於
1.雜湊函式
2.處理衝突的方法
3.雜湊表的填裝因子α=表中填入的記錄數/雜湊表的長度
(α越大,表中記錄數越多,說明表裝得越滿,發生衝突的可能性就越大,查詢時比較次數就越多)
ASL與填裝因子α有關!既不是嚴格的O(1),也不是O(n)
結論
雜湊表技術具有很好的平均效能,優於一些傳統的技術;
鏈地址法優於開地址法;→動態
除留餘數法作雜湊函式優於其他型別函式。(取小於等於表長的質數,獲得比較好的雜湊效果)
相關文章
- 重學資料結構(八、查詢)資料結構
- 【PHP資料結構】雜湊表查詢PHP資料結構
- Java資料結構(十五)—— 多路查詢樹Java資料結構
- 樹狀資料結構儲存方式——查詢篇資料結構
- 資料結構之查詢(順序、折半、分塊查詢,B樹、B+樹)資料結構
- 資料結構與演算法-二分查詢資料結構演算法
- 資料結構與演算法:查詢演算法資料結構演算法
- 【資料結構與演算法】—— 二分查詢資料結構演算法
- [資料結構] 二分查詢 (四種寫法)資料結構
- 查詢最佳化——查詢樹結構
- 資料結構與演算法整理總結---二分查詢資料結構演算法
- PostgreSQL 原始碼解讀(205)- 查詢#118(資料結構RangeTblEntry)SQL原始碼資料結構
- 資料結構與演算法-二叉查詢樹資料結構演算法
- 資料結構與演算法 第五章 查詢資料結構演算法
- 資料結構-並查集資料結構並查集
- 資料結構與演算法知識點總結(5)查詢樹資料結構演算法
- 資料結構和演算法之——二分查詢下資料結構演算法
- 資料結構和演算法之——二分查詢上資料結構演算法
- ORACLE遞迴查詢(適用於ID,PARENTID結構資料表)Oracle遞迴
- 【資料結構基礎應用】【查詢和排序演算法】資料結構排序演算法
- PostgreSQL 原始碼解讀(206)- 查詢#119(資料結構RangSubselect等)SQL原始碼資料結構
- 演算法與資料結構——二分查詢插入點演算法資料結構
- 『資料結構與演算法』二叉查詢樹(BST)資料結構演算法
- 6-1 二分查詢 (20分) PTA 資料結構資料結構
- 資料結構之並查集資料結構並查集
- 資料結構與演算法——查詢演算法-斐波那契(黃金分割法)查詢資料結構演算法
- PostgreSQL 原始碼解讀(204)- 查詢#117(資料結構SelectStmt&Value)SQL原始碼資料結構
- PostgreSQL 原始碼解讀(207)- 查詢#120(資料結構FromExpr&JoinExpr)SQL原始碼資料結構
- 資料結構與演算法-二叉查詢樹平衡(DSW)資料結構演算法
- 資料結構與演算法-二叉查詢樹平衡(AVL)資料結構演算法
- 【資料結構與演算法】手撕二叉查詢樹資料結構演算法
- 資料結構實驗之查詢七:線性之雜湊表資料結構
- 【資料結構】查詢結構(二叉排序樹、ALV樹、雜湊技術雜湊表)資料結構排序
- MySQL - 資料查詢 - 簡單查詢MySql
- ORACLE結構化查詢語句Oracle
- NKMySQL 查詢樹結構方式gllMySql
- iOS標準庫中常用資料結構和演算法之查詢iOS資料結構演算法
- 在進行行情 tick 資料儲存時,哪種資料結構查詢起來更快?資料結構