全文重点在代码–少理论
静态查找:只做查找操作,而不改动表中数据元素;
顺序查找
从表中的最后一个数据元素开始,逐个同记录的关键字做比较,如果匹配成功,则查找成功;反之,如果直到表中第一个关键字查找完也没有成功匹配,则查找失败。
//顺序查找--O(n)--遍历数组\链表
int test_sequential_search(int a[], int n, int keyval)
{
for (int i = 0; i < n; i++)
{
if (a[i] == keyval)
return i; //返回下标
}
return -1;
}
二分查找(折半)-数组必有序
双指针查找某一个值是否存在(另一个作用:当查找元素重复时查找左右边界)
//二分查找--O(log2n)--双指针(找中点-mid)
int test_binary_search(int a[], int n,int keyval)
{
if (n < 0 ) return -1;
//定义双指针
int left = 0;
int right = n - 1; //用的下标
int mid = ((right - left) >> 1 )+ left;
while (left <=right)
{
if (keyval == a[mid])
{
return mid;
}
else if (a[mid] < keyval)
{
left = mid + 1;
}
else if (a[mid] > keyval)
{
right = mid - 1;
}
}
}
找边界
int left_bound(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0;
int right = nums.length; // 注意
while (left < right) {
// 注意
int mid = (left + right) / 2;
if (nums[mid] == target) {
right = mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid; // 注意
}
}
return left;
}
动态查找:查找成功可以对其进行删除;如果查找失败,即表中无该关键字,可以将该关键字插入到表中。
二叉查找树(BST)
创建、查找、插入、删除
如果二叉排序树是平衡的,则n个节点的二叉排序树的高度为Log 2n+1,其查找效率为O(Log 2n),近似于折半查找。如果二叉排序树完全不平衡,(不平衡指右两边的子节点的数量不一致)则其深度可达到n,查找效率为O(n),退化为顺序查找。一般的,二叉排序树的查找性能在O(Log 2n)到O(n)之间。因此,为了获得较好的查找性能,就要构造一棵平衡的二叉排序树。很多改进版的二叉排序树可以使树高为O(logn),如AVL、红黑树等。对于排序二叉树,若按中序遍历就可以得到由小到大的有序序列。
**//二叉查找(排序、搜索)树-动态过程--[O(log2n),(n)]之间--创建、插入、删除、查找
/*
*二叉排序树中,如果其根结点有左子树,那么左子树上所有结点的值都小于根结点的值;
*二叉排序树中,如果其根结点有右子树,那么右子树上所有结点的值都大小根结点的值;
*二叉排序树的左右子树也要求都是二叉排序树;
*/
typedef struct BinarySearchTree
{
int data;
struct BinarySearchTree* left_child, * right_child;
}binary_search_tree;
//插入(创建)
void bst_insert(binary_search_tree*& p,int data)//改变指针的值需要二级指针
{
if (p == NULL)//插入节点为空
{
if((p = new binary_search_tree)==NULL)
cout<<"error"<<endl;
p->data = data;
p->left_child = p->right_child = NULL;
}
else if (p->data >= data) //根据二叉搜索树的特点左孩子比父节点小,右孩子比父节点大插入
bst_insert(*(&(p->left_child)), data);//先取地址再取值
else if (p->data < data)
bst_insert(*(&(p->right_child)), data);
}
//查找
binary_search_tree* bst_search(binary_search_tree* p, int keyval)
{
if (p == NULL)
return NULL;
if (p->data == keyval)
return p;
else if (p->data > keyval)
bst_search(*(&(p->left_child)), keyval);
else if (p->data < keyval)
bst_search(*(&(p->right_child)), keyval);
}
void delete_bst(binary_search_tree*& p, int del_val)//同理修改值针的地址
{
if (p == NULL)
return;
else if(p->data==del_val)
{
if (p->left_child == NULL)//左孩子为空
{
binary_search_tree* temp = p;
p = p->right_child;
delete temp;
}
else//左孩子不为空时
{
binary_search_tree* head = p, *next = p->left_child;
//找左子树的右子叶子节点,如果没有就父节点代替节点p,(为保持其它元素之间的相对位置不变,
//可按中序遍历保持有序进行调整。比较好的做法是,找到*p的直接前驱(或直接后继)*next,
//用*next来替换结点*p,然后再删除结点*next)
while (next->right_child) // eg1: 7 | eg2: 7
{
// 2 8 | 2 8
head = next; // 1 (null) | 1 4
next = next->right_child; // | 3(null)
}
p->data = next->data; //用*next来替换结点*p, eg2: head->data=2;next->data=4
if (p = head) //eg1所示:用2替代7,然后删除2;(即*next没有右叶子节点)
p->left_child = next->left_child;
else //eg2所示:用4替代7,然后删除4;(即*next有右叶子节点)
{
head->right_child = next->left_child;
}
delete next;//删掉直接前驱
}
}
else if (p->data > del_val)
delete_bst(*(&(p->left_child)), del_val);
else if (p->data < del_val)
delete_bst(*(&(p->right_child)), del_val);
}
//中序遍历输出
void printbst(binary_search_tree* p)
{
if (p)
{
printbst( p->left_child);
cout << p->data << ' ';
printbst( p->right_child);
}
}
//程序入口
void test_bstsearch(int a[],int n)
{
//插入入口
binary_search_tree* head=NULL;
for (int i = 0; i < n; i++)
{
bst_insert(head, a[i]);
}
printbst(head);
cout << endl;
//查找入口
/* binary_search_tree* temp = bst_search(head, 23);
if(temp!=NULL)
cout << "Find results:"<<temp->data << endl;
else
cout << "Not find. " << endl;*/
//删除入口
delete_bst(head, 7);
printbst(head);
cout << endl;
}**
平衡二叉树(VAL)
AVL有BST的所有性质,(比如中序遍历单调递增),但AVL是在BST的基础上优化而来,平衡化的结果,平衡因子<=1;
//平衡二叉树(AVL)--O(logn)--就是在二叉排序树(BST)的基础上,任意节点的左右子结点个数差不超过1;
//所以:每一次插入或者删除元素后都要判断是否平衡(不平衡就要旋转)
typedef struct AVL_tree {
int data;
struct AVL_tree* leftchild, *rightchild;
int hight; //记录每个节点的深度
}avl_node,* avl_tree_t