即仅查询的表,生成的时候不会进行调整
ASL:平均查找长度,公式中p是查找第i个元素的概率,c是查找第i个元素时比较的次数
该方法一般不用链式存储,比较麻烦,空间占用的也多。
从后向前比较,若直到第一个记录都不相等,则查找不成功
可以将 list[0] = key; 作为哨兵,省略对数组下表越界的检查,提高算法执行的速度(虽然我觉得好像没提高)
代码非常简单:
int list[100]={-1007},n; //哨兵,数组长度
int my_find(int x){
for(int i=n;list[i]!=-1007;i--){
if(list[i]==x) return i;
}
return 0;
}
性能分析:O(n)
在等概率查找的情况下,查找成功的ASL=(n+1)/2,查找失败的ASL=(n+1)
也叫二分查找,必!须!得!是!有序表!
int bifind(int low,int high){
int mid=(low+high)/2;
if(low>high) return 0;
if(arr[mid]==n) return mid;
if(arr[mid]>n) return bifind(low,mid-1);
if(arr[mid]
性能分析:O(logn)
二分查找的判定树:由此可以计算出概率相等的情况下查找成功/失败的ASL,即总查找次数÷数组长度
下图中ASL成功=(1+2*2+3*4+4*4)/11=3
ASL失败=(4*4+5*8)/11=5.09
也可以用公式,不过这个公式需要为满二叉树:
应用有很多很多,比如折半查找求一个数x的平方根:
#include
using namespace std;
double x;
double binary(double low,double high){
double mid=(low+high)/2;
if(high-low<1e-6) return mid;
if(mid*mid>x) return binary(low,mid);
if(mid*mid>t;
while(t--){
cin>>x;
printf("%.3lf\n",binary(0,x));
}
return 0;
}
索引表将主表分为几块,要求块内无序、块间有序。块间有序指后一块表中所有数字大于或小于前一块表的所有数字。索引表还会知道每个块中的max。
题目描述
给出一个队列和要查找的数值,找出数值在队列中的位置,队列位置从1开始
要求使用顺序索引查找算法,其中索引表查找和块内查找都采用不带哨兵、从头开始的顺序查找方法。
输入:
第一行输入n,表示主表有n个数据
第二行输入n个数据,都是正整数,用空格隔开
第三行输入k,表示主表划分为k个块,k也是索引表的长度
第四行输入k个数据,表示索引表中每个块的最大值
第五行输入q,表示有q个要查找的数值
第六行起,输入t个数值,输入t行
输出:
每行输出一个要查找的数值在队列的位置和查找次数,数据之间用短划线隔开,如果查找不成功,输出字符串error
#include
using namespace std;
int arr[1000],n,k,b[100],f,ans;//分成k块
int find_w(){ //寻找在哪个块中
int cnt=0;
ans=1;
if(f<=b[1]) return 1;
for(int i=1;ib[i]&&f<=b[i+1]) return i+1;
}
return 0;//error
}
int my_find(int x){
for(int i=1;i<=n/k;i++){ //在该块中继续寻找
ans++;
if(arr[i+n/k*(x-1)]==f) return i+n/k*(x-1);
}
return 0;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>arr[i];
cin>>k;
for(int i=1;i<=k;i++) cin>>b[i];
int q;
cin>>q;
while(q--){
ans=0;
cin>>f;
int x=find_w();
if(x==0) {
cout<<"error"<
表结构本身是在查找过程中动态生成的。若某值查找不成功,则插入该值。
左子树小于根,右子树大于根,中序遍历结果为从小到大的排序结果。
二叉排序树的插入、查找、删除,代码如下:
输入和输出:
第一行:初始结点个数n;随后输入n个结点。随后输出建树结果
第二行:输入需要查询的结点个数q;
随后q行输入需要查询的结点。如果查找成功,则输出查找次数,否则输出error
接着:输入需要删除的结点个数d
随后d行输入需要删除的结点。如果删除成功,则输出删除后的二叉排序树,否则输出error
#include
using namespace std;
int ans;
struct NODE {
int data;
NODE* left=nullptr;
NODE *right=nullptr;
};
class BisortTree {
public:
NODE *root=nullptr;
void* insert(NODE*&p,int key) { //建树过程
if(!p) {
p=new NODE();
p->data=key;
} else {
if(p->data>key) insert(p->left,key);
else insert(p->right,key);
}
}
void find_key(NODE *now,int key) {
if(key==now->data) return;
if(!now->left&&!now->right) {
ans=0;
return;//ans代表查找次数,失败则为0
}
if(keydata) ans++,find_key(now->left,key);
else ans++,find_key(now->right,key);
}
int B_delete(NODE *&now,int key) {
if(!now) return 0; //error
if(key==now->data) {
NODE *p=now;
if(!now->left&&!now->right) { //如果是叶子结点直接删除
now=nullptr;
delete p;
} else if(!now->left) { //如果只有左孩子,就用左孩子替代它
now=now->right;
delete p;
} else if(!now->right) { //如果只有右孩子,就用右孩子替代它
now=now->left;
delete p;
} else { //既有左孩子又有右孩子
NODE *parent=now; //记录q的前驱结点
NODE *q=now->left;//左转
while(q->right) { //然后向右找到尽头max,即先找到小于该结点的最大值
parent=q;
q=q->right;
}
now->data=q->data;
if(parent!=now)
parent->right=q->left;
else parent->left=q->left;
delete q;
}
return 1; //OK
}
if(keydata) B_delete(now->left,key);
else B_delete(now->right,key); //首先要找到要删除的结点的位置
}
void inorder(NODE *now) { //中序遍历
if(now->left) inorder(now->left);
cout<data<<" ";
if(now->right) inorder(now->right);
}
};
int main() {
int n,q,d;
cin>>n;
BisortTree T;
for(int i=1; i<=n; i++) {
int key;
cin>>key;
T.insert(T.root,key);
}
T.inorder(T.root);
cout<>q;
while(q--) {
int key;
cin>>key;
ans=1;
T.find_key(T.root,key);
if(ans) cout<>d;
while(d--) {
int key;
cin>>key;
int flag=T.B_delete(T.root,key);
if(flag) T.inorder(T.root),cout<
ASL成功与删除的计算参考二分查找的判定树,方法很像。
时间复杂度:O(logn)。最坏时间复杂度:O(n)
其特点为,树中的结点的左、右子树深度之差的绝对值不大于1,即为平衡因子,平衡因子只能取-1,0,1
(1)插入
如果在一棵平衡的二叉查找树中插入一个新结点,造成了不平衡,此时必须调整树的结构,使之平衡化。
(2)删除
平衡二叉树的删除与二叉排序树相同:
如果被删结点是叶子结点,那么直接删除;
如果有一个孩子,则让被删节点的父亲指向这个孩子;
如果有两个孩子,则找到被删节点的直接前驱(即小于该数的最大值)S,替代被删节点,然后对直接前驱S做删除处理。 注:S只能有一个左孩子或者没有孩子。
突然发现这个题没学代码怎么写,考试的话会理论应该就足够了。