目录
一、顺序查找
(1)定义结构
//顺序查找:顺序表用指针实现
typedef int ElemType;
typedef struct {
ElemType *elem; //整形指针,存申请的堆空间的地址
int TableLen;//存个数
}SSTable;
(2)初始化
void ST_Init(SSTable &ST,int len){
//王道多申请一个位置为了存放哨兵,初试可以不申请
ST.TableLen = len +1;
ST.elem = (ElemType*)malloc(sizeof (ElemType) * ST.TableLen);
int i;
srand(time(NULL)); //随机数生成(初试不考)
//机试自己选数字测试即可
for (i = 0; i < ST.TableLen; ++i)
{
ST.elem[i] = rand()%100;//0~99之间
}
}
(3)查找
//普通
int Sq_Search(SqTable ST,int e){
for (int i = 0; i < ST.len; ++i) {
if(i<=ST.len && e == ST.data[i]){
return i ;
}
}
return -1;
}
int search_seq(SSTable ST,ElemType key){
ST.elem[0] = key;
int i;
for (i = ST.TableLen-1; ST.elem[i]!=key; i--);
return i;
}
(4)输出顺序表
void ST_Print(SSTable ST){
int i ;
for (int i = 1; i < ST.TableLen; ++i) //不输出哨兵
{
printf("%-3d",ST.elem[i]);
}
printf("\n");
}
二、折半查找(二分查找)
2.事前准备
(1)创建顺序表
见上面顺序查找
(2)排序
使用<stdlib.h>中的qsort(),第一个参数为待排序的数据,第二个为待排序数据的长度,第三个为单个排序数据的大小,第四个为判断规则,需要自己编写函数
compare 函数:两个空类型的指针left和right,当left指向的data大于right返回的data,return正值,小于则返回负值,相等return 0 ,left-right排序结果为升序;降序right-left
// right 和left 指向arr中任意两个元素
int compare(const void *left,const void *right){
return *(int*)left - *(int*)right;//升序
return *(int*)right - *(int*)left;//降序
}
qsort(ST.elem,ST.TableLen,sizeof(ElemType),compare);//排序
3.思路
int BinarySearch(SSTable L,ElemType key){
int low =0;
int high = L.TableLen -1;
int mid;
while(low <= high){//使mid取到所有情况
mid = low + (high-low)/2;
if(key > L.elem[mid]){
low = mid + 1;
}
else if(key <L.elem[mid]){
high = mid - 1;
}else{
return mid;
}
}
return -1;
}
三、二叉排序树(二叉查找树)
1.定义
typedef int ElemType;
typedef struct BSTNode{
ElemType data;
struct BSTNode *lchild,*rchild;
}BSTNode,*BSTree;
2.创建
//插入单个ele
int Insert(BSTree &T,ElemType e){
if(T==NULL){
T = (BSTNode*)malloc(sizeof(BSTNode));
T->data = e;
T->lchild =T->rchild= NULL;
return 1;
}
else if(e == T->data) return 0;//相同不插入
else if(e < T->data) return Insert(T->lchild,e);
else return Insert(T->rchild,e);
}
//循环插入
void CreateTree(BSTree &T,ElemType e[],int n){
T = NULL;
int i;
for (i = 0; i < n ; i++) {
Insert(T,e[i]);
}
}
3.查找
//非递归查找
BSTNode* BSTFind(BSTree T,ElemType e,BSTNode* &parent){//记录目标结点的parent
parent = NULL;
while(T!= NULL && e != T->data){
parent = T;
if(e > T->data) T = T->rchild;
else T = T->lchild;
}
return T;
}
//递归
BSTNode* BSTFind2(BSTree T,ElemType e){
if(T == NULL) return NULL;
if(T->data == e) return T;
else if(e < T->data) return BSTFind2(T->lchild,e);
else return BSTFind2(T->rchild,e);
}
6.输出
void print(BSTree T){
if(T!=NULL){
print(T->lchild);
printf("%-3d",T->data);
print(T->rchild);
}
}
(2)思路(不考虑等于)
指针T指向待找结点,当该结点大于当前结点,往右走,小于则往左走
找到了T就是插入的位置,那怎么跟前一个结点链接呢?
引入parent结点,在查找之前令 parent=T,找到之后直接parent左右孩子赋值即可
//创建树的空间
void Create_BST(BiTree &T,KeyType* str,int len){
//str是整型arr,传入参数中弱化为整型指针
int i;
for ( i = 0; i < len; i++)
{
BST_Insert(T,str[i]);
}
}
//插入结点
int BST_Insert(BiTree &T,KeyType k){
//54,20,66,40,28,79,58
//为进入的结点申请空间
BiTree TreeNew = (BiTree)calloc(1,sizeof(BSTNode));
TreeNew ->key = k;
if(NULL == T){//空树,插入的是树根
T = TreeNew;
return 0;
}
//非空,找位置
BiTree p=T,parent;//p用来查找树
//p找到待插入的pos,so引入parent
while(p){//初试不考虑相等元素
parent = p;
if(k > p->key){
p = p->rchild;
}else if(k<p->key){
p = p->lchild;
}else{ // ==
return -1;//不考,可以不考虑
}
}
//p为null了跳出循环,有了parent
//but不知道放parent的左孩子还是右孩子
if(k > parent->key){//用值比较
parent ->rchild = TreeNew;
}else if(k < parent->key){
parent ->lchild = TreeNew;
}
return 0;
}
四、二叉排序树删除
//使用递归实现
void DeleteNode(BiTree &root,KeyType x){
//引用root,为了改变删除结点,直接顶上即可
if(NULL == root){//空树
return;
}
if(x > root->key){
DeleteNode(root->rchild,x);
}
else if(x < root->key){
DeleteNode(root->lchild,x);
}else{//找到了待删除的结点
if(root->lchild == NULL){
BiTree TempNode = root;
root = root->rchild;
free(TempNode);
}else if(root->rchild == NULL){
BiTree TempNode = root;
root = root->lchild;
free(TempNode);
}else{//都不为null
//左子树的最右结点or右子树的最左结点放到删除结点的位置上
BiTree TempNode = root->lchild;
//找到左子树的最右结点
while(TempNode->rchild){
TempNode = TempNode->rchild;
}
root ->key = TempNode->key;
//因为root把根结点覆盖
//在左子树中找到值为待删除的结点值并删除,而不是直接删除tempnode、
DeleteNode(root->lchild,TempNode->key);
}
}
}
五、AVL定义
//AVL
typedef struct AVLNode{
ElemType data;
int balance;
struct AVLNode *lchild,*rchild;
}AVLNode,*AVLTree;
六、RBT定义
//RBT
typedef struct RBTNode{
ElemType data;
struct RBTNode *parent;
struct RBTNode *lchild,*rchild;
int color;//0表示R,1表示B
}RBTNode,*RBT;
七、真题
1.题目 2014-42
2.思路
二分查找的分治思想
找两个arr的中位数比较大小,小的中位数前面的肯定不是整体的中位数,大的中位数后面的肯定不会是整体的中位数,因此可以舍弃,当每个arr只剩下一个时候,小的就是整体的中位数
3.实现
attn:s、d指向队列头尾,mid是中间元素,当是奇数个元素,小的舍弃中位数之前的,大的到中位数那;偶数个元素时,小的舍弃中位数及其之前的元素,大的舍弃后面的元素,保留中位数
如何确定是否保留呢?若最后就剩俩个,则必须舍弃自己才能剩下1个,so需要舍弃本身
大的如何确定舍弃多少呢?每次两个arr舍弃的个数需要相同,确定d到mid的位置即可
int MidSearch(int *A,int *B,int n){
int s1 = 0,d1=n-1,m1,s2=0,d2=n-1,m2;
while(s1!=d1 || s2!=d2){//两个都相等才停止
m1 = (s1 +d1)/2;
m2 = (s2 +d2)/2;
if(A[m1] ==B[m2] ){//相等
return A[m1];
}else if(A[m1] <B[m2]){
if((s1+d1)%2==0){//奇数个元素
//例子:一共五个元素,s1=0,d1=4,2的倍数
s1 = m1;//小的舍弃自己前面元素
d2 = m2;//大的
}else {//偶数个元素
s1 = m1 + 1;//小的舍弃自己及前面元素
d2 = m2;//大的舍弃后面的保留中间的
}
}else{//A[m1] > B[m2]
if((s1+d1)%2==0){
d1 = m1;
s2 = m2;
}else{
d1 = m1;
s2 = m2+1;
}
}
}
return A[s1] < B[s2] ? A[s1] : B[s2];//返回小的
}