您的位置:首页 > 其它

算法导论----学习笔记08

2014-11-29 10:59 281 查看
按照查找的引出的先后顺序介绍:

1. 静态查找(树)表

以下介绍的是有序表查找,无序表只能顺序查找

二分查找

作为有序表查找的一种非常普通且实用的方法。大家并不陌生。

思想:先确定待查记录所在的范围(区间),然后逐步缩小范围找到或找不到该记录为止。如果mid对应值大于key,high = 密度-1;如果mid对应值小于key,low
= mid + 1;否则找到结果。

性能分析:对于任意的n,当较大(n>50)时,假设表中每个记录的查找概率相等(1/n),则查找成功时折半查找的近似平均查找长度为=
log2(n+1)-1。

斐波那契查找

原理:根据斐波那契序列的特点对表进行分割。

其中:


假设开始时数组A中记录个数比某个斐波那契数小1,即n=Fu-1,然后将给定值key和查找序列中A[Fu-1]进行比较,

若相等,则查找成功

若key > A[Fu-1],则在A[Fu-1+1]至A[Fu-1]区间的数组中进行查找;

若key < A[Fu-1],则继续在A[0]至A[Fu-1-1]区间的数组中进行查找;

性能分析:斐波那契查找的平均性能比折半查找好,但最坏情况下的性能 (虽然仍为O(lgn)) 却比折半查找差。

小小优点:分割时只需进行加、减运算。

插值查找

原理:是根据给定值key来确定进行比较关键字A[i]的查找方法。



其中,A[l]和A[h]分别为有序表中具有最小关键字和最大关键字的下标

性能比较:它只适合于关键字均匀分布的数组,在这种情况下,对数组较长的数组来说,其平均性能比折半查找好。

由于上面讨论的查找都是等概率的查找,如果待查找数为非等概率出现,那么上述的方法并非是使平均查找长度最短

-----------------------------------------------------------------------------------------------我是分割线----------------------------------------

最优二叉树(哈夫曼树)

思路:使用动态规划思想

[b]二、最优二叉查找树的最优子结构[/b]

最终的递归公式为:





[b]对于1≤i≤n.
且j≥i,
我们有:
[/b]

w(i,j)=w(i,j−1)+pj+qj

伪码:

<span style="color:#000000;"></span><pre name="code" class="cpp">OPTIMAL-BST(p, q, n)
let e[1 .. n + 1, 0 .. n], w[1, n + 1, 0 .. n],
and root[1..n, 1..n] be new tables
for i = 1 to n + 1
e[i, i - 1] = q<sub>i-1</sub>
w[i, i - 1] = q<sub>i-1</sub>
for l = 1 to n
for i = 1 to n - l + 1
j = i + l - 1
e[i, j] = ∞
w[i, j] = w[i, j -1] + p<sub>j</sub> + q<sup>j</sup>
for r = i to j
t = e[i, r - 1] + e[r + 1, j] + w[i, j]
if t < e[i, j]
e[i, j] = t
root[i, j] = r
return e and root



三、代码实现(C++):

//最优二叉查找树

#include <iostream>

using namespace std;

const int MaxVal = 9999;

const int n = 5;
//搜索到根节点和虚拟键的概率
double p[n + 1] = {-1,0.15,0.1,0.05,0.1,0.2};
double q[n + 1] = {0.05,0.1,0.05,0.05,0.05,0.1};

int root[n + 1][n + 1];//记录根节点
double w[n + 2][n + 2];//子树概率总和
double e[n + 2][n + 2];//子树期望代价

void optimalBST(double *p,double *q,int n)
{
//初始化只包括虚拟键的子树
for (int i = 1;i <= n + 1;++i)
{
w[i][i - 1] = q[i - 1];
e[i][i - 1] = q[i - 1];
}

//由下到上,由左到右逐步计算
for (int len = 1;len <= n;++len)
{
for (int i = 1;i <= n - len + 1;++i)
{
int j = i + len - 1;
e[i][j] = MaxVal;
w[i][j] = w[i][j - 1] + p[j] + q[j];
//求取最小代价的子树的根
for (int k = i;k <= j;++k)
{
double temp = e[i][k - 1] + e[k + 1][j] + w[i][j];
if (temp < e[i][j])
{
e[i][j] = temp;
root[i][j] = k;
}
}
}
}
}

//输出最优二叉查找树所有子树的根
void printRoot()
{
cout << "各子树的根:" << endl;
for (int i = 1;i <= n;++i)
{
for (int j = 1;j <= n;++j)
{
cout << root[i][j] << " ";
}
cout << endl;
}
cout << endl;
}

//打印最优二叉查找树的结构
//打印出[i,j]子树,它是根r的左子树和右子树
void printOptimalBST(int i,int j,int r)
{
int rootChild = root[i][j];//子树根节点
if (rootChild == root[1]
)
{
//输出整棵树的根
cout << "k" << rootChild << "是根" << endl;
printOptimalBST(i,rootChild - 1,rootChild);
printOptimalBST(rootChild + 1,j,rootChild);
return;
}

if (j < i - 1)
{
return;
}
else if (j == i - 1)//遇到虚拟键
{
if (j < r)
{
cout << "d" << j << "是" << "k" << r << "的左孩子" << endl;
}
else
cout << "d" << j << "是" << "k" << r << "的右孩子" << endl;
return;
}
else//遇到内部结点
{
if (rootChild < r)
{
cout << "k" << rootChild << "是" << "k" << r << "的左孩子" << endl;
}
else
cout << "k" << rootChild << "是" << "k" << r << "的右孩子" << endl;
}

printOptimalBST(i,rootChild - 1,rootChild);
printOptimalBST(rootChild + 1,j,rootChild);
}

int main()
{
optimalBST(p,q,n);
printRoot();
cout << "最优二叉树结构:" << endl;
printOptimalBST(1,n,-1);
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: