1.查找表可分為兩類:
(1)靜態查找表:僅做查詢和檢索操作的查找表。
(2)動態查找表:在查詢之后,還需要將查詢結果為不在查找表中的數據元素插入到查找表中;或者,從查找表中刪除其查詢結果為在查找表中的數據元素。
2.查找的方法取決於查找表的結構:由於查找表中的數據元素之間不存在明顯的組織規律,因此不便於查找。為了提高查找效率,需要在查找表中的元素之間人為地附加某種確定的關系,用另外一種結構來表示查找表。
3.順序查找表:以順序表或線性鏈表表示靜態查找表,假設數組0號單元留空。算法如下:
int location(SqList L, ElemType &elem)
{
i = 1;
p = L.elem;
while (i <= L.length && *(p++)!= e)
{
i++;
}
if (i <= L.length)
{
return i;
} else
{
return 0;
}
}
此算法每次循環都要判斷數組下標是否越界,改進方法:加入哨兵,將目標值賦給數組下標為0的元素,並從后向前查找。改進后算法如下:
int Search_Seq(SSTable ST, KeyType kval) //在順序表ST中順序查找其關鍵字等於key的數據元素。若找到,則函數值為該元素在表中的位置,否則為0。
{
ST.elem[0].key = kval; //設置哨兵
for (i = ST.length; ST.elem[i].key != kval; i--) //從后往前找,找不到則返回0
{
}
return 0;
}
4.順序表查找的平均查找長度為:(n+1)/2。
5.上述順序查找表的查找算法簡單,但平均查找長度較大,不適用於表長較大的查找表。若以有序表表示靜態查找表,則查找過程可以基於折半進行。算法如下:
int Search_Bin(SSTable ST, KeyType kval)
{
low = 1;
high = ST.length; //置區間初值
while (low <= high)
{
mid = (low + high) / 2;
if (kval == ST.elem[mid].key)
{
return mid; //找到待查元素
} else if (kval < ST.elem[mid].key)
{
high = mid - 1; //繼續在前半區間查找
} else
{
low = mid + 1; //繼續在后半區間查找
}
}
return 0; //順序表中不存在待查元素
} //表長為n的折半查找的判定樹的深度和含有n個結點的完全二叉樹的深度相同
6.幾種查找表的時間復雜度:
(1)從查找性能看,最好情況能達到O(logn),此時要求表有序;
(2)從插入和刪除性能看,最好情況能達到O(1),此時要求存儲結構是鏈表。
7.二叉排序樹(二叉查找樹):
(1)定義:二叉排序樹或者是一棵空樹;或者是具有如下特性的二叉樹:
①若它的左子樹不空,則左子樹上所有結點的值均小於根結點的值;
②若它的右子樹不空,則右子樹上所有的結點值均大於根結點的值;
③它的左、右子樹也都分別是二叉排序樹(對二叉排序順進行中序遍歷得到的是一個有序序列)。
(2)通常取二叉鏈表作為二叉排序樹的存儲結構。
typedef struct BiTNode //結點結構
{
TElemType data;
struct BiTNode* lchild, *rchild; //左右孩子指針
} BiTNode, *BiTree;
(3)二叉排序樹的查找算法:若二叉排序樹為空,則查找不成功;否則:
①若給定值等於根結點的關鍵字,則查找成功;
②若給定值小於根結點的關鍵字,則繼續在左子樹上進行查找;
③若給定值大於根結點的關鍵字,則繼續在右子樹上進行查找。
(4)從上述查找過程可見,在查找過程中,生成了一條查找路徑:
①查找成功:從根結點出發,沿着左分支或右分支逐層向下直至關鍵字等於給定值的結點;
②查找不成功:從根結點出發,沿着左分支或右分支逐層向下直至指針指向空樹為止。
(5)二叉排序樹中遞歸地查找關鍵字算法:
Status SearchBST(BiTree T, KeyType kval, BiTree f, BiTree &p) //在根指針T所指二叉排序樹中遞歸地查找其關鍵字等於kval的數據元素,若查找成功,則返回指針p指向該數據元素的結點,並返回函數值為TRUE;否則表明查找不成功,返回FALSE,指針f指向當前訪問結點的雙親,其初始調用值為NULL(f用於二叉排序樹的插入操作)
{
if (!T)
{
p = f;
return FALSE; //查找不成功
} else if (kval == T->data.key)
{
p = T;
return TRUE;
} else if (kval < T->data.key)
{
return SearchBST(T->lchild, kval, T, p); //在左子樹中繼續查找
} else
{
return SearchBST(T->rchild, kval, T, p); //在右子樹中繼續查找
}
}
(6)二叉排序樹的插入算法:根據動態查找表的定義,插入操作在查找不成功時才進行;若二叉排序樹為空樹,則新插入的結點為新的根結點;否則,新插入的結點必為一個新的葉子結點,其插入位置由查找過程得到。算法如下:
Status Insert BST(BiTree &T, ElemType e) //當二叉排序樹中不存在關鍵字等於e.key的數據元素時,插入元素值為e的結點,並返回TRUE;否則,不進行插入並返回FALSE
{
if (!SearchBST(T, e.key, NULL, p))
{
s = new BiTNode; //為新結點分配空間
s->data = e;
s->lchild = s->rchild = NULL;
if (!p)
{
T = s; //插入s為新的根結點
} else if (e.key < p->data.key)
{
p->lchild = s; //插入*s為*p的左孩子
} else
{
p->rchild = s; //插入*s為*p的右孩子
}
return TRUE; //插入成功
} else
{
return FALSE;
}
}
(7)二叉排序樹的刪除算法:和插入相反,刪除在查找成功之后進行,並且要求在刪除二叉排序樹上某個結點之后,仍然保持二叉排序樹的特性。可分三種情況討論:
①被刪除的結點是葉子:其雙親結點中相應指針域的值改為空;
②被刪除的結點只有左子樹或者只有右子樹:其雙親結點的相應指針域的值改為指向被刪除結點的左子樹或右子樹;
③被刪除的結點既有左子樹,也有右子樹:以其前驅結點替換該結點,再刪除該前驅結點;或者以其后繼節點替換該結點,再刪除該后繼結點。
算法描述如下:
Status DeleteBST(BiTree &T, KeyType kval) //若二叉排序樹T中存在其關鍵字等於kval的數據元素,則刪除該數據元素結點,並返回函數值TRUE,否則返回函數值FALSE
{
if (!T)
{
return FALSE; //不存在關鍵字等於kval的數據元素
} else
{
if (kval == T->data.key)
{
Delete(T);
return TRUE; //找到關鍵字等於key的數據元素
} else if (kval < T->data.key)
{
return DeleteBST(T->lchild, kval); //繼續在左子樹中進行查找
} else
{
return DeleteBST(T->rchild, kval); //繼續在右子樹中進行查找
}
}
}
void Delete(BiTree &p) //從二叉排序樹中刪除結點p,並重接它的左子樹或右子樹
{
if (!p->rchild)
{
p = p->lchild;
} else if (!p->lchild)
{
p = p->rchild;
} else
{
tmp = p->left;
while (tmp->right)
{
tmp = tmp->right;
}
p->data = tmp->data;
Delete(tmp);
}
}
(8)查找性能分析:對於每一棵特定的二叉排序樹,均可按照平均查找長度的定義來求它ASL,由值相同的n個關鍵字構造所得的不同形態的各棵二叉排序樹的平均查找長度的值不同,甚至可能差別很大。
8.平衡二叉樹:平衡二叉樹是二叉查找樹的另一種形式,特點為樹中每個結點的左、右子樹深度之差的絕對值不大於1。
(1)構造平衡二叉(查找)樹的方法是:在插入過程中,采用平衡旋轉技術(LL、RR、LR、RL)。
(2)當發生不平衡的情況,找到最小不平衡子樹進行調整:
①LL型:整體向右旋轉一次;
②RR型:整體向左旋轉一次;
③LR型:底部向左旋轉一次,變成LL型,再整體向右旋轉一次;
④RL型:底部向右旋轉一次,變成RR型,再整體向左旋轉一次。
例如:依次插入的關鍵字為5, 4, 2, 8, 6, 9
(3)平衡二叉樹的查找性能分析:在平衡樹上進行查找的過程和二叉排序樹相同,因此查找過程中和給定值進行比較的關鍵字的個數不超過平衡樹的深度。因此,在平衡二叉樹上進行查找時,查找過程中和給定值進行比較的關鍵字的個數和log(n)相當(最壞情況等效於順序表查找性能和n相當)。
9.B樹:
(1)定義:B樹是一種平衡的多路查找樹。在m階的B樹上,每個非終端結點可能含有:
①n個關鍵字Ki(1 ≤ i ≤ n,n < m);
②n個指向記錄的指針Di(1 ≤ i ≤ n);
③n+1個指向子樹的指針Ai(0 ≤ i ≤ n);
例如,下圖為一棵B樹:
(2)查找過程:
(3)插入操作:
(4)刪除操作:
(5)查找性能分析:
10.B+樹: