1.顺序查找法
从序列的一端到另一端,找到元素返回对应下标,退出循环。
可能找的到,也可能找不到。
时间复杂度O(n)
int find(vector <int>nums, int target)
{
for(int i=0; i<nums.size(); i++)
{
if(nums[i]==target) return i;
}
return NULL;
}
2.哨兵法查找
选取头部(尾部)位置做哨兵,从尾部(头部)开始便利到头部(尾部),找到对应元素则返回下标。
原来的内存中有一个单元是不用的,这个单元用来存储哨兵。一定会找到,因为有哨兵。
// 0 号位置不放原始数据,用来存储哨兵(待查找的数据)
int find(vector <int>nums, int target)
{
arr[0] = target;
for(int i=nums.szie()-1; i>0; i--)
{
if(nums[i]==target) return i;
}
return NULL;
}
3.二分查找
前提:序列有序,并且顺序存取。因此链表不能跳着访问。
每一次都是拿要查找的数和子序列的中间位置比较,如果要查找的数比中间位置的小就往左边找,反之向右边找,如果找到返回中间位置下边,精力多次找不到返回-1.
int binarySearch(vector <int> nums, int left, int right)
{
int left = 0, right = length - 1, mid;
while(left<=right)
{
mid = left + (right - left)/2;
if(key < arr[mid]) left = mid+1;
else if(key == arr[mid]) return mid;
else right = mid-1;
}
}
4.分块查找
O(logK+m)
typedef struct Data{
int key;
int index;
}Data, ST;
int blocksearch(int arr[], int length, ST* st, int len_st, int key)
{
int left = 0. right = len_st -1;
int mid = left + ((right - left) >> 1);
while(left < right)
{
if(key < st[mid].key) right = mid; // 因为包含最大值在其中,所以不能漏掉right 所对应的值
else if(key > st[mid].key) left = mid + 1; // 因为left 所有对应的比过了,就直接跳开
else break;
mid = left + ((right - left) >> 1);
}
int begin = st[mid].index;
int end = mid >= len_st - 1? length :st[mid+1].index;
while (begin < end)
{
if(key==arr[begin]) return begin;
begin++;
}
return -1;
}
二叉查找树
左节点小于父节点,右节点大于父节点。 链式存储,适合插入和删除。
bool search(Node* root, int key)
{
while (root != NULL)
{
if (key == root->data)
return true;
else if (key < root->data)
root = root->left;
else
root = root->right;
}
return false;
}
平衡二叉树
AVL树又称为平衡二叉树,即Balanced Binary Tree或者Height-Balanced Tree,它或者是一棵空二叉树,或者是具有如下性质的二叉查找树:
左子树和右子树都是高度平衡的二叉树;
左子树和右子树的高度之差的绝对值不超过1。
#include <stdio.h>
#include <stdlib.h>
//分别定义平衡因子数
#define LH +1
#define EH 0
#define RH -1
typedef int ElemType;
typedef enum {false,true} bool;
//定义二叉排序树
typedef struct BSTNode{
ElemType data; //节点存储的数据
int bf; //平衡标志
struct BSTNode *lchild,*rchild;
}*BSTree,BSTNode;
//对以 p 为根结点(以 p 为轴)的二叉树做右旋处理,令 p 指针指向新的树根结点
void R_Rotate(BSTree* p)
{
// 令 p 的左孩子的右孩子作为 p 的左孩子
BSTree lc = (*p)->lchild;
(*p)->lchild = lc->rchild;
//令 p 作为 p 的左孩子的右孩子
lc->rchild = *p;
// 令 p 的左孩子作为新的根节点
*p = lc;
}
//对以 p 为根结点(以 p 为轴)的二叉树做左旋处理,令 p 指针指向新的树根结点
void L_Rotate(BSTree* p)
{
// 令 p 的右孩子的左孩子作为 p 的右孩子
BSTree rc = (*p)->rchild;
(*p)->rchild = rc->lchild;
//令 p 作为 p 的右孩子的左孩子
rc->lchild = *p;
// 令 p 的右孩子作为新的根节点
*p = rc;
}
//对以指针 T 所指向结点为根结点的二叉树作左子树的平衡处理,令指针 T 指向新的根结点
void LeftBalance(BSTree* T)
{
BSTree lc,rd;
lc = (*T)->lchild;
//进入此方法前就已经判断为左旋了,还需要确定是哪种左旋:1、直接左旋,2、先左旋后右旋
//查看以 T 的左子树为根结点的子树,失去平衡的原因:
// 如果 bf 值为 1 ,则说明添加在左子树为根结点的左子树中,需要对其进行右旋处理;
// 反之,如果 bf 值为 -1,说明添加在以左子树为根结点的右子树中,需要进行双向先左旋后右旋的处理
switch (lc->bf)
{
case LH:
(*T)->bf = lc->bf = EH;
R_Rotate(T);
break;
case RH:
rd = lc->rchild;
switch(rd->bf) //这部分不好理解,拿笔在纸上画一画就特别好理解了(这部分的情况在前面的讲解里没有)
{
case LH:
(*T)->bf = RH;
lc->bf = EH;
break;
case EH:
(*T)->bf = lc->bf = EH;
break;
case RH:
(*T)->bf = EH;
lc->bf = LH;
break;
}
rd->bf = EH;
L_Rotate(&(*T)->lchild);
R_Rotate(T);
break;
}
}
//右子树的平衡处理同左子树的平衡处理完全类似
void RightBalance(BSTree* T)
{
BSTree lc,rd;
lc= (*T)->rchild;
switch (lc->bf)
{
case RH:
(*T)->bf = lc->bf = EH;
L_Rotate(T);
break;
case LH:
rd = lc->lchild;
switch(rd->bf)
{
case LH:
(*T)->bf = EH;
lc->bf = RH;
break;
case EH:
(*T)->bf = lc->bf = EH;
break;
case RH:
(*T)->bf = EH;
lc->bf = LH;
break;
}
rd->bf = EH;
R_Rotate(&(*T)->rchild);
L_Rotate(T);
break;
}
}
//taller 用于记录插入新节点后是否使相应的子树高度增加,从而根据平衡因子判断是否需要対树进行平衡
//算法使用了递归,插入完成后,逐层向上对相应子树进行处理
//无返回值的地方,统一在最后 return 1;
int InsertAVL(BSTree* T,ElemType e,bool* taller)
{
//如果本身为空树(树的根节点或相应子树为空),则直接添加 e 为根结点
if ((*T)==NULL)
{
(*T)=(BSTree)malloc(sizeof(BSTNode));
(*T)->bf = EH;
(*T)->data = e;
(*T)->lchild = NULL;
(*T)->rchild = NULL;
*taller=true;
}
//如果二叉排序树中已经存在 e ,则不做任何处理
else if (e == (*T)->data)
{
*taller = false;
return 0;
}
//如果 e 小于结点 T 的数据域,则插入到 T 的左子树中
else if (e < (*T)->data)
{
//如果插入过程,不会影响树本身的平衡,则直接结束
if(!InsertAVL(&(*T)->lchild,e,taller))
return 0;
//判断插入过程是否会导致整棵树的深度 +1
if(*taller)
{
//判断根结点 T 的平衡因子是多少,由于是在其左子树添加新结点的过程中导致失去平衡,
//所以当 T 结点的平衡因子本身为 1(左高)时,需要进行左子树的平衡处理,否则更新树中各结点的平衡因子数
switch ((*T)->bf)
{
case LH:
LeftBalance(T); // 左旋対树进行平衡,平衡后树的高度不会增加
*taller = false;
break;
case EH:
(*T)->bf = LH; //更新平衡因子
*taller = true;
break;
case RH:
(*T)->bf = EH; //更新平衡因子
*taller = false;
break;
}
}
}
//同样,当 e>T->data 时,需要插入到以 T 为根结点的树的右子树中,同样需要做和以上同样的操作
else
{
if(!InsertAVL(&(*T)->rchild,e,taller))
return 0;
if (*taller)
{
switch ((*T)->bf)
{
case LH:
(*T)->bf = EH;
*taller = false;
break;
case EH:
(*T)->bf = RH;
*taller = true;
break;
case RH:
RightBalance(T);
*taller = false;
break;
}
}
}
return 1;
}
//判断现有平衡二叉树中是否已经具有数据域为 e 的结点
bool FindNode(BSTree root,ElemType e,BSTree* pos)
{
BSTree pt = root;
(*pos) = NULL;
while(pt)
{
if (pt->data == e)
{
//找到节点,pos指向该节点并返回true
(*pos) = pt;
return true;
}
else if (pt->data>e)
{
pt = pt->lchild;
}
else
pt = pt->rchild;
}
return false;
}
//中序遍历平衡二叉树
void InorderTra(BSTree root)
{
if(root->lchild)
InorderTra(root->lchild);
printf("%d ",root->data);
if(root->rchild)
InorderTra(root->rchild);
}
int main()
{
int i,nArr[] = {1,23,45,34,98,9,4,35,23};
BSTree root=NULL,pos;
bool taller;
//用 nArr查找表构建平衡二叉树(不断插入数据的过程)
for (i=0;i<9;i++)
{
InsertAVL(&root,nArr[i],&taller);
}
//中序遍历输出
InorderTra(root);
//判断平衡二叉树中是否含有数据域为 103 的数据
if(FindNode(root,103,&pos))
printf("\n%d\n",pos->data);
else
printf("\nNot find this Node\n");
return 0;
}
哈希表查找
816

被折叠的 条评论
为什么被折叠?



