精华内容
下载资源
问答
  • 折半查找和二叉排序树

    千次阅读 多人点赞 2019-10-10 14:19:28
    1.折半查找和二叉排序树的时间性能分析: 从查找过程看,二叉排序树与二分查找相似。就平均时间性能而言,二叉排序树上的查找和二分查找差不多,但不完全一致; 折半查找的性能分析可以用二叉判定树来衡量,平均...

    1.折半查找和二叉排序树的时间性能分析:

    •  从查找过程看,二叉排序树与二分查找相似。就平均时间性能而言,二叉排序树上的查找和二分查找差不多,但不完全一致;
    • 折半查找的性能分析可以用二叉判定树来衡量,平均查找长度和最大查找长度都是O(logn);
    • 二叉排序树的查找性能与数据的输入顺序有关,最好情况下的平均查找长度与折半查找相同,但最坏情况时,即形成单支树时,其查找长度为O(n)。
    • 折半查找的判定树唯一,而二叉排序树不唯一,相同的关键字其插入顺序不同可能生成不同的二叉排序树。

    2.就维护表的有序性而言,二叉排序树无需移动节点,只需修改指针即可完成插入和删除操作,平均执行时间是O(logn)。二分查找的对象是有序顺序表,若有插入和删除结点的操作,所花的代价是O(n)。

    3.当有序表是静态查找表时,宜用顺序表作为其存储结构,而采用二分查找实现其查找操作;若有序表是动态查找表,则应选择二叉排序树作为其逻辑结构。

    4.折半查找过程所对应的判定树是一棵平衡二叉树:每次把一个数组从中间分割时,总是把数组分为结点数相差最多不超过1的两个子数组,从而使得对应的判定树的两颗子树高度差绝对值不超过1。

    展开全文
  • 数据结构中的单链表;二叉树遍历;折半查找;二叉排序树;内部排序。有具体实现代码。
  • 折半查找、二叉排序树的建立、查找与删除、链式哈希表的建立与查找: ...4————二叉排序树查找—— 5————二叉排序树删除—— 6————查找关键字(线性探测) 7————查找散列表(链式)
  • 一、实验目的 1、掌握查找的特点。 2、掌握折半查找的基本思想及其算法。 3、熟悉二叉排序树的特点,掌握...2、根据关键字序列{45、24、53、12、37、93}构造二叉排序树,并完成插入13删除关键字5324的操作。 三...

    文中内容来源于《数据结构 --Java语言描述》(第二版) 刘小晶 杜选 主编
    此系列文章作为学校实验记录,若文中内容有误,请大家指出,谢谢

    一、实验目的

    1、掌握查找的特点。
    2、掌握折半查找的基本思想及其算法。
    3、熟悉二叉排序树的特点,掌握二叉排序树的插入、删除操作。

    二、实验内容

    1、设有关键字序列k={ 5 ,14 ,18 ,21 ,23 ,29 ,31 ,35 },查找key=21和key=25的数据元素。
    2、根据关键字序列{45、24、53、12、37、93}构造二叉排序树,并完成插入13删除关键字53和24的操作。

    三、实验步骤

    1、折半查找
    (1)从键盘输入上述8个整数5 ,14 ,18 ,21 ,23 ,29 ,31 ,35,存放在数组bub[8]中,并输出其值。
    (2)从键盘输入21,查找是否存在该数据元素,若存在,则输出该数据元素在表中的位置,否则给出查找失败的信息。
    (3)从键盘输入25,查找是否存在该数据元素,若存在,则输出该数据元素在表中位置,否则给出查找失败的信息。
    2、二叉排序树
    (1)二叉排序树存储定义
    (2)从键盘上输入六个整数45、24、53、12、37、9构造二叉排序树
    (3)输出其中序遍历结果。
    (4)插入数据元素13,输出其中序遍历结果。
    (5)删除数据元素24和53,输出其中序遍历结果。

    源代码

    //顺序表记录结点类
    package ch7;
    public class ElementType {
        public Object data;
    
        public ElementType(Object data) {
            this.data = data;
        }
        public ElementType() {
        }
        public String toString() {
            return (String)data;
        }
    }
    
    
    //顺序表记录关键字类
    package ch7;
    public class KeyType implements Comparable<KeyType> {
        public int key;
        public KeyType() {
    
        }
        public KeyType(int key) {
            this.key = key;
        }
        public String toString() {
            return key + "";
        }
        //覆盖Comparable接口中比较关键字大小的方法
        public int compareTo(KeyType another) {
            int thisVal = this.key;
            int anotherVal = another.key;
            if(thisVal<anotherVal) {
                return -1;
            } else {
                if(thisVal == anotherVal) {
                    return 0;
                } else {
                    return 1;
                }
            }
        }
    }
    
    
    //待排序的顺序表记录类
    package ch7;
    public class RecordNode {
        public Comparable key;
        public Object element;
        public RecordNode(Comparable key) {
            this.key = key;
        }
        public RecordNode(Comparable key,Object element) {
            this.key = key;
            this.element = element;
        }
        public String toString() {
            return "[" + key + "]";
        }
    }
    
    
    //待排序的顺序表类
    package ch7;
    import java.util.Scanner;
    public class SeqList {
        public RecordNode[] r;//顺序表记录结点数组
        public int curlen;//顺序表长度,即记录个数
        //顺序表的构造方法,构造一个存储空间容量为maxSize的顺序表
        public SeqList(int maxSize) {
            this.r = new RecordNode[maxSize];
            this.curlen = 0;
        }
        //在当前顺序表的第i个结点之前插入一个RecordNode类型的结点x
        public void insert(int i,RecordNode x) throws Exception{
            if(curlen == r.length) {
                throw new Exception("顺序表已满!");
            }
            if(i<0 || i>curlen) {
                throw new Exception("插入位置不合法!");
            }
            for (int j = curlen; j > i; j--) {
                r[j] = r[j - 1];//插入位置及之后的数据元素后移
            }
            r[i] = x;//插入x
            this.curlen++;//表长度增1
        }
    /*
    二分查找的递归写法
    public int binarySearchDG(int low,int high,Comparable key) {
        int mid;
        if(low<=high) {
            mid = low + high;
            if(r[mid].key.compareTo(key)>0) {
                return binarySearchDG(low,mid - 1,key);
            } else if(r[mid].key.compareTo(key)<0) {
                return binarySearchDG(mid + 1,high,key);
            } else {
                return mid;
            }
        }
        return -1;
    }
    */
    
        public int binarySearch(Comparable key) {
            if(curlen>0) {
                int low = 0,high = curlen - 1;//查找范围上下界
                while(low<=high) {
                    int mid = (low + high)/2;//中间位置,当前比较的数据元素位置
                    if(r[mid].key.compareTo(key) == 0) {
                        System.out.print("查找成功!");
                        return mid;//查找成功
                    } else if(r[mid].key.compareTo(key)>0) {//给定值更小
                        high = mid -1;//查找范围缩小到前半段
                    } else {
                        low = mid + 1;//查找范围缩小到后半段
                    }
                }
            }
            System.out.print("查找失败!");
            return -1;//查找不成功
        }
        //创建查找表,
        public static SeqList ST = null;//使查找表公开,这样才能在测试类中调用
        public static void createSearchList() throws Exception {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入查找表预分配空间的大小:");
            int maxSize = sc.nextInt();
            ST = new SeqList(maxSize);
            System.out.println("请输入关键字表长:");
            int kLength = sc.nextInt();
            KeyType[] k = new KeyType[kLength];
            System.out.println("请输入关键字:");
            for (int i = 0; i < kLength; i++) {
                k[i] = new KeyType(sc.nextInt());
            }
            for (int i = 0; i < kLength; i++) {
                RecordNode r = new RecordNode(k[i]);
                ST.insert(ST.curlen,r);
            }
        }
    }
    
    
    package ch9;
    import ch7.*;
    import ch7.RecordNode;
    import ch5.BiTreeNode;//二叉树的二叉链表结点类
    public class BSTree {//二叉排序树类
        public BiTreeNode root;//根结点
        public BSTree() {//构造空二叉排序树
            root = null;
        }
        //中根次序遍历以p结点为根的二叉树
        public void inOrderTraverse(BiTreeNode p) {
            if(p != null) {
                inOrderTraverse(p.lchild);
                System.out.print(((RecordNode)p.data).toString() + "");
                inOrderTraverse(p.rchild);
            }
        }
        //查找关键字为key的结点,成功返回结点值,失败返回null
        public Object searchBST(Comparable key) {
            if(key == null || !(key instanceof Comparable)) {
                System.out.println("查找"+key+"失败!");
                return null;
            }
            return searchBST(root , key);
        }
        //二叉排序树查找的递归算法
        //在二叉排序树中查找关键字值为key的结点,成功返回结点值,否则返回null
        private Object searchBST(BiTreeNode p,Comparable key) {
            if(p != null) {
                if(key.compareTo(((RecordNode)p.data).key) == 0) {
                    System.out.print("查找"+key+"成功!");
                    return p.data;
                }
                if(key.compareTo(((RecordNode)p.data).key) < 0) {
                    return searchBST(p.lchild,key);//左子树查找
                } else {
                    return searchBST(p.rchild,key);//右子树查找
                }
            }
            return null;
        }
        //在二叉排序树中插入关键字值为key,数据元素为theElement的新结点
        //插入成功返回true,失败返回false
        public boolean insertBST(Comparable key,Object theElement) {
            //不能插入空对象或不可比较大小的对象
            if(key == null || !(key instanceof Comparable)) {
                System.out.println("插入"+key+"失败!");
                return false;
            }
            if(root == null) {
                root = new BiTreeNode(new RecordNode(key,theElement));
                System.out.println("插入"+key+"成功!");
                return true;
            }
            return insertBST(root,key,theElement);
        }
        //将关键字值为key,数据元素为theElement的结点插入到以p为根的二叉排序树中的递归算法
        private boolean insertBST(BiTreeNode p, Comparable key, Object theElement) {
            if(key.compareTo(((RecordNode)p.data).key) == 0) {
                System.out.println("插入"+key+"失败!");
                return false;//不插入关键字值重复的结点
            }
            if(key.compareTo(((RecordNode)p.data).key) < 0) {
                if(p.lchild == null) {
                    p.lchild = new BiTreeNode(new RecordNode(key,theElement));
                    System.out.println("插入"+key+"成功!");
                    return true;
                } else {
                    return insertBST(p.lchild,key,theElement);
                }
            } else if(p.rchild ==null){
                p.rchild = new BiTreeNode(new RecordNode(key,theElement));
                System.out.println("插入"+key+"成功!");
                return true;
            } else {
                return insertBST(p.rchild,key,theElement);
            }
        }
        //二叉排序树中删除一个结点,若成功则返回被删除结点,否则返回null
        public Object removeBST(Comparable key) {
            if(root == null || key == null || !(key instanceof Comparable)) {
                System.out.println("删除"+key+"失败!");
                return null;
            }
            //在以root为根的二叉树中删除关键字值为elemKey的结点
            return removeBST(root,key,null);
        }
        //在以p为根的二叉排序树中删除关键字为elemKey的结点,parent是p的父结点,采用递归算法
        private Object removeBST(BiTreeNode p, Comparable elemKey, BiTreeNode parent) {
            if(p != null) {
                if(elemKey.compareTo(((RecordNode)p.data).key) < 0) {
                    return removeBST(p.lchild,elemKey,p);
                } else if(elemKey.compareTo(((RecordNode)p.data).key) > 0) {
                    return removeBST(p.rchild,elemKey,p);
                } else if(p.lchild != null && p.rchild != null) {
                    BiTreeNode innext = p.rchild;//寻找p在中根次序下的后继结点innext
                    while(innext.lchild != null) {// 寻找左子树中的最左孩子
                        innext = innext.lchild;
                    }
                    p.data = innext.data;//用后继结点代替p
                    return removeBST(p.rchild,((RecordNode)p.data).key,p);//递归删除结点p
                } else {//p是1度和叶子结点
                    if(parent == null) {//删除根结点,p = root
                        if(p.lchild != null) {
                            root = p.lchild;
                        } else {
                            root = p.rchild;
                        }
                        System.out.println("删除"+elemKey+"成功!");
                        return p.data;//返回被删除的结点p
                    }
                    if(p == parent.lchild) {//p是parent的左孩子
                        if(p.lchild != null) {
                            parent.lchild = p.lchild;//以p的左子树填充
                        } else {
                            parent.lchild = p.rchild;
                        }
                    } else if(p.lchild != null) {//p是parent的右孩子且p的左子树非空
                        parent.rchild = p.lchild;
                    } else {
                        parent.rchild = p.rchild;
                    }
                    System.out.println("删除"+elemKey+"成功!");
                    return p.data;
                }
            }
            System.out.println("删除"+elemKey+"失败!");
            return null;
        }
    
    }
    
    
    package ch9;
    import ch7.KeyType;
    import java.util.Scanner;
    import static ch7.SeqList.*;
    public class BinarySearchTest {
        public static void main(String[] args) throws Exception{
            int sum;
            createSearchList();
            System.out.println("请输入要查找的关键字个数:");
            Scanner sc = new Scanner(System.in);
            sum = sc.nextInt();
            System.out.println("请输入要查找的关键字:");
            while(sum>0) {
                KeyType key = new KeyType(sc.nextInt());
                System.out.println(key.key + "下标为:" + ST.binarySearch(key));
                sum--;
            }
        }
    }
    
    
    package ch9;
    import ch7.KeyType;
    import java.util.Scanner;
    public class BSTreeTest {
        public static void main(String[] args) {
            BSTree bstree = new BSTree();
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入关键字的个数:");
            int kLength = sc.nextInt();
            int[] k = new int[kLength];
            KeyType[] key = new KeyType[k.length];
            System.out.println("请输入关键字:");
            for (int i = 0; i < kLength; i++) {
                k[i] = sc.nextInt();
            }
            for (int i = 0; i < k.length; i++) {
                key[i] = new KeyType(k[i]);
                bstree.insertBST(key[i],null);
    
            }
    
            System.out.println("\n中序遍历二叉排序树:");
            bstree.inOrderTraverse(bstree.root);
            System.out.println();
            System.out.println();
    
            KeyType keyvalue;
            System.out.println("请输入要添加的关键码的个数:");
            int sum = sc.nextInt();
            System.out.println("请输入要添加的关键码:");
            while(sum>0) {
                keyvalue = new KeyType(sc.nextInt());
                bstree.insertBST(keyvalue,null);
                System.out.println("添加关键码:" + keyvalue + "后的中序遍历序列:");
                bstree.inOrderTraverse(bstree.root);
                System.out.println();
                sum--;
            }
    
            System.out.println("请输入要删除的关键码个数:");
            sum = sc.nextInt();
            System.out.println("请输入要删除的关键码:");
            while(sum>0) {
                keyvalue = new KeyType(sc.nextInt());
                bstree.removeBST(keyvalue);
                System.out.println("删除关键码:" + keyvalue + "后的中序遍历序列:");
                bstree.inOrderTraverse(bstree.root);
                System.out.println();
                sum--;
            }
        }
    }
    
    

    运行结果

    BinarySearchTest.java
    请输入查找表预分配空间的大小:
    20
    请输入关键字表长:
    8
    请输入关键字:
    5 14 18 21 23 29 31 35
    请输入要查找的关键字个数:
    2
    请输入要查找的关键字:
    21 25
    查找成功!21下标为:3
    查找失败!25下标为:-1
    
    Process finished with exit code 0
    
    BSTreeTest.java
    请输入关键字的个数:
    6
    请输入关键字:
    45 24 53 12 37 9
    插入45成功!
    插入24成功!
    插入53成功!
    插入12成功!
    插入37成功!
    插入9成功!
    
    中序遍历二叉排序树:
    [9][12][24][37][45][53]
    
    请输入要添加的关键码的个数:
    1
    请输入要添加的关键码:
    13
    插入13成功!
    添加关键码:13后的中序遍历序列:
    [9][12][13][24][37][45][53]
    请输入要删除的关键码个数:
    2
    请输入要删除的关键码:
    24 53
    删除37成功!
    删除关键码:24后的中序遍历序列:
    [9][12][13][37][45][53]
    删除53成功!
    删除关键码:53后的中序遍历序列:
    [9][12][13][37][45]
    
    Process finished with exit code 0
    
    
    展开全文
  • 实验:实现顺序查找,折半查找二叉排序树,哈希表实验原理:
  • 顺序查找表 二分查找表 折半查找二叉排序树 C#源代码 注意二叉排序树只实现了查找和插入算法,使用Visual Studio 2008开发
  • 单链表的基本操作,二叉树的遍历,折半查找和二叉排序树,内部排序等共四个实验的实现过程。
  • 数据结构课程设计-综合查找算法(顺序查找、折半查找二叉排序树、哈希表) 可以在Microsoft Visual C++ 上运行没有错误 包括论文word文档,答辩的ppt等
  • 折半查找 算法思想: 先确定待查记录的范围。 给定的值与中间记录进行比较 若相等,则找到, 返回位置。 若不相等,则缩小范围在前半部分或后半部分。 重复2,直到找到或不存在范围找不到结束。 二、动态查找 动态...

    查找

    一、静态查找(Static Search Table)

    顺序查找的存储结构

    typedef struct {
    	int key; //关键字
    }ElemType;
    
    typedef struct {
    	ElemType *elem; //数据元素存储空间基址 
    	int length; //表长度 
    

    顺序查找(Sequential Search)

    //顺序查找
    int Search_Seq(SSTable ST, int key) 
    {//在顺序表ST中顺序查找其关键字等于key的元素,若找到,怎函数值为该元素在表中的位置,否则为0 
    	ST.elem[0].key = key;
    	//起到监视哨的作用,目的在于免去查找过程中每一步都要检测整个表是否查找完毕 
    	int i;
    	for(i = ST.length; ST.elem[i].key != key; i-- );
    			return i;
    }
    
    

    折半查找(Binary Search)

    算法思想:

    1. 先确定待查记录的范围。
    2. 给定的值与中间记录进行比较
      若相等,则找到, 返回位置。
      若不相等,则缩小范围在前半部分或后半部分。
    3. 重复2,直到找到或不存在范围找不到结束。
    //折半查找
    int Search_Bin(SSTable ST, int key)
    {//关键字有序
    	int min, max, mid;
    	min = 1;
    	max = ST.length;
    	while(min <= max)
    	{
    		mid = (min + max)/2;
    		if(ST.elem[mid].key == key)
    			return mid;
    		else if(ST.elem[mid].key > key)
    			max = mid - 1;
    		else
    			min = mid + 1;
    	}
    	return 0;
    }
    

    二、动态查找(Dynamic Search Table)

    动态查找表的特点:

    • 表结构本身是在查找过程中动态生成的。即对给定值key, 若表中有其关键字等于key的记录,则查找成功返回,否则插入关
      键字等于key的记录。

    二叉排序树(Binary Sort Tree)

    什么是二叉排序树?(二叉查找树)
    或者是一棵空树,或者是具有下面性质的二叉树:

    1. 若它的左子树不空,则左子树上所有结点的值均小于它的根的值;
    2. 若它的右子树不空,则右子树上所有结点的值均大于它的根的值;
    3. 它的左、右子树也分别是二叉排序树。
    //二叉排序树
    BiTree SearchBST(BiTree T,int key)
    {//查找成功,返回指向该数据元素结点的指针,否则返回空指针 
    	//小于关键字在左子树中继续查找,大于关键字在右子树中继续查找
    	if(!T || T->key == key)
    		return T; //查找结束 
    	else if(T->key > key)
    		return SearchBST(T->lchild,key);
    	else
    		return SearchBST(T->rchild,key);
    }
    

    二叉排序树的插入

    二叉排序树是一种动态树表。其特点是:

    1. 树的结构通常不是一次生成的,而是在查找的过程中,当 不存在关键字等于给定值的结点时在进行插入。
    2. 新插入的结点一定是叶子,并且是查找不成功时查找路径 上最后一个结点的左子女或右子女。
    //插入操作
    int SearchBST(BiTree T, int key, BiTree &p)
    {//查找成功,指针p指向该数据元素结点,并返回1;
    //查找不成功,指针p指向查找路径上访问的最后一个结点,并返回0。 
    	if(!T)
    		return 0; //查找不成功
    	else if(T->key == key)
    	{
    		p = T;
    		return 1; //查找成功 
    	} 
    		
    	else if(T->key > key)
    	{
    		p = T;
    		return SearchBST(T->lchild,key, p);
    	}
    	else
    	{
    		p = T;
    		return SearchBST(T->rchild,key, p);
    	}
    }
    
    int InsertBST(BiTree &T, int key)
    {//当二叉排序树T中不存在关键字等于key的元素时,插入key并返回1,否则返回0 
    	
    	BiTree p, q;
    	p = NULL;
    	if(SearchBST(T,key,p) == 1)
    		return 0;
    
    	q = (BiTree)malloc(sizeof(BTree));
    	q->key = key;
    	q->lchild = NULL;
    	q->rchild = NULL;
    	if(p == NULL)
    		T = q;
    	else if(p->key > key)
    		p->lchild = q;
    	else
    		p->rchild = q;
    	return 1;
    }
    
    展开全文
  • 基于树的查找二叉排序树、平衡二叉排序树、B-树B+树) 基于散列表的查找 2 基于线性表的查找 2.1 定义分类 基于线性表的查找主要是两部分:(索引顺序表用的不是很多) 顺序查找(适用于两种存储结构)...

    整理内容来源:zzu信息工程学院数据结构ppt
    本节讨论两类不同的查找表:静态查找表动态查找表,给出在不同查找表上进行查找的不同算法和性能分析以及动态查找表的创建方法。

    1 查找的基本概念

    静态查找:

    • 基于线性表的查找

    动态查找:

    • 基于树的查找(二叉排序树、平衡二叉排序树、B-树和B+树)
    • 基于散列表的查找

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    2 基于线性表的查找

    2.1 定义和分类

    在这里插入图片描述
    基于线性表的查找主要是两部分:(索引顺序表用的不是很多)

    • 顺序查找(适用于两种存储结构)
    • 折半查找(有序表)

    注意区分 “有序”“顺序”:有序表中的“有序”是逻辑意义上的有序,指表中的元素按某种规则已经排好了位置。顺序表中的“顺序”是物理意义上的,指线形表中的元素一个接一个的存储在一片相邻的存储区域中。可以粗略地将“顺序表”理解为数组,将“有序表”理解为排好的数组。

    2.2 顺序查找

    2.2.1 思想

    从表中第一条/最后一条记录开始,逐个进行记录的关键字与给定值的比较,若某个记录的关键字和给定值比较相等,则查找成功,返回其在顺序表中的位序;反之,若直至最后一条/第一条记录其关键字和给定值比较都不等,则查找不成功,返回0

    2.2.2 算法实现

    监视哨:为能自动检验数组下标越界,在0下标处设置哨兵,若查找不成功,则循环会在0下标处自动终止,函数返回0

    int  Search_Seq( SSTable  ST,  KeyType key ){  
    	ST.elem[0].key = key; //0下标为监视哨
        for(i = ST.length; !EQ(ST.elem[i].key,key ); --i);           
        return i;              
    }//Search_Seq 
    

    举例:
    在这里插入图片描述

    2.2.3 性能分析

    这么暴力的做法时间复杂度当然不会低了
    在这里插入图片描述
    这里对O(n)可能没什么感觉,我们再往下看。

    2.3 折半查找

    折半查找在算法题中用的很多了,我之前专门写过关于折半查找的博客:算法 - 二分查找

    2.3.1 定义

    折半查找(二分查找):先确定待查记录所在范围,逐步缩小范围,直到找到或找不到该记录止。
    不过应注意,折半查找的应用范围是:有序表
    二分查找的思想和具体实现可参考那篇博客。

    2.3.2 判定树

    在这里插入图片描述

    2.3.3 性能分析

    时间复杂度为O(logn),当数量级比较大时,时间复杂度的差异就体现出来了。详见下图:
    在这里插入图片描述

    2.4 索引顺序表

    索引顺序表就不展开讲了,它的特点是:分块有序、块内无序。

    • 分块有序:用折半查找
    • 块内无序:用顺序查找

    在这里插入图片描述

    3 二叉排序树(二叉查找树、BST)

    3.1 定义

    二叉排序树是指空树或具有下列性质的二叉树:(不得不感慨课件确实很严谨)

    • 根的左子树若非空,则左子树上所有结点的关键字值均小于根结点的关键字值;
    • 根的右子树若非空,则右子树上所有结点的关键字值均大于根结点的关键字值;
    • 它的左右子树同样是二叉排序树。

    可以看出,这是一种递归式定义。

    3.2 查找过程

    • 若二叉排序树为空,则查找失败,返回空指针;
    • 若二叉排序树不空:
      • 首先将给定值和根结点的关键字比较,若相等则查找成功,返回根结点的地址。
      • 若给定值小于根结点的关键字值,则在其左子树上继续查找;
      • 若给定值大于根结点的关键字值,则在其右子树上继续查找。

    关于二叉排序树的算法实现,我们选用的存储结构是链式存储结构,即(lchild, data, rchild)
    原因是:链式存储结构可以快速实现插入和删除操作。
    具体的算法如下:

    BiTree SearchBST(BiTree T, KeyType key){
    	if((!T) || EQ(key,T->data.key)) return T;
    	if(LT(key,T->data.key)) 
    		return SearchBST(T->lchild, key); 
      	else return SearchBST(T->rchild, key);
    } //SearchBST 
    

    3.2 插入、构造方法

    在这里插入图片描述
    我们对查找算法可以适当修改,修改后的查找算法如下:

    Status SearchBST(BiTree T, KeyType key, BiTree f, BiTree &p){  //修改后的查找算法
       if(!T){  p=f;  return FALSE;  } 
       else if EQ(key,T->data.key)     
         {  p=T;   return TRUE;  }
       else if LT(key,T->data.key)          
    	   return SearchBST(T->lchild,key,T,p);    
       else return SearchBST(T->rchild,key,T,p); 
    }// SearchBST 
    

    其实对查找算法就是修改了如果查找不成功的话,对这个叶子结点进行了记录。(利用&p)

    ----------------------(乱入,前面的内容push一下)----------------
    在这里突然想到了“指针和引用的区别”,之前看过一篇文章一直存着,分享给大家:指针与引用, 值传递与地址传递的关系
    ----------------------(前面的内容pop出来)---------------------------

    如果得到了叶子结点,那我们就可以进行二叉排序树的插入操作了:

    Status InsertBST(BiTree &T, ElemType e)
    {
       if(!SearchBST(T,e.key,NULL,p))       
       {
         s=(BiTree)malloc(sizeof(BiTNode));             
         if(!s)   exit(OVERFLOW);
         s->data = e;     s->lchild = s->rchild = NULL; 
         if(!p) T=s;                   
         else if LT(e.key, p->data.key)   p->lchild = s;
         else   p->rchild = s;                 
         return TRUE;
       }
       else return FALSE;                    
    } 
    

    插入的示例和补充:
    在这里插入图片描述
    注意这里啊,在插入时,我们不需要移动其他结点,只需要修改一个结点的指针就好了。
    并且我们还应注意到,BST的建树过程就是查找失败时元素不断插入的过程。

    3.3 删除

    对于一般的二叉树,删去树中的一个结点会破坏整棵树的结构。对二叉排序树,删去一个结点相当于删去有序序列中的一个记录。
    在这里插入图片描述
    在删除时,我们有以下几种情况:
    在这里插入图片描述
    在这里插入图片描述
    注意上面这种情况,不管被删结点是只有左子树还是只有右子树,都把它的某个子树挂到它的父节点的子树上。

    在这里插入图片描述
    在这里插入图片描述
    个人喜欢第2种。

    3.4 性能分析

    在等概率情况下,完全二叉树的查找效率最高。在随机的情况下,二叉排序树的平均查找长度和O(logn)是等数量级的。
    其实看到这了难道不觉得和折半查找的判定树很像嘛,就是平均情况下。两者的原理是一样的。
    这里为什么要说“等概率情况”呢,因为有n个结点的二叉排序树并不唯一,平均查找长度与二叉排序树的形态有关,而二叉排序树的形态由关键字的插入顺序决定。比如插入顺序是1234531254构造的排序树是不同的。前者深度大,查找效率自然低了(前者其实等价于顺序查找)。
    怎样可以忽略关键字的插入顺序呢,这就是下面要介绍的平衡二叉排序树了。

    4 平衡二叉树(AVL树)

    4.1 定义

    平衡二叉树(AVL树):它或者是一棵空树,或者是满足下列性质的二叉树:

    • 其左、右子树深度之差的绝对值不大于1
    • 其左、右子树都是平衡二叉树

    害,怎么说呢,又是一个递归定义。(习惯了
    那么为什么要引入平衡二叉树呢,在二叉排序树的性能分析中我们已经看到,若一棵二叉排序树是平衡的,则树上任何结点的左右子树的深度之差不超过1,二叉树的深度与log2n同数量级。这样就可以保证它的平均查找长度与log2n同数量级。
    举个例子:
    在这里插入图片描述

    4.2 构造

    在这里插入图片描述
    这里就要介绍一种比较高级的平衡旋转技术:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    举个例子:10,5,15,12,20,14,30,18,35,2,0,3,4,构造该序列的平衡二叉排序树:
    其实没有图片画的那么复杂,这个平衡旋转技术还是很有感觉的。(就描述不出的平衡感
    在这里插入图片描述

    4.3 性能分析

    和BST树一样,性能是O(log2n)

    5 B-、B+树

    5.1 B-树的定义

    在这里插入图片描述
    这个定义需要强调两点:

    • 结点中的关键字个数至多为m-1(因为每个结点至多有m棵子树)
    • 根至少有一个关键字(因为若根结点不是叶子结点,至少有两棵子树)

    定义还有一个小要求:
    在这里插入图片描述
    给一个B-树的例子,便于理解。
    在这里插入图片描述

    5.2 引入B-树的原因

    前面介绍的查找方法适用于待查记录数较小的文件,查找时记录都读入内存中进行处理,统称为内查找法。若文件很大,查找时不能把记录全部读入内存(大量数据仍存放在硬盘上)时,则查找过程需要反复进行内、外存交换。
    由于硬盘的驱动受机械运动的制约,速度慢。所以提高查找效率的关键就是减少访问外存的次数。
    1970年R bayer和E macreight提出用B-树作为索引组织文件,提高访问速度、减少时间。B-树具有占用存储空间少、查找效率高等优点,常用在文件系统和数据库系统的索引技术中。
    举个例子:
    用二叉树组织文件,当文件的记录个数为106时,树高平均为17(log2106)。若以256阶B-树组织数据,则树高最多仅为3

    5.3 B-树的查找过程

    在这里插入图片描述
    查找操作的两个过程是:

    • 沿指针搜索结点(在磁盘中进行)
    • 在结点内进行查找(在内存中进行,因为前一步找到结点后会把结点内的信息读入内存中处理)

    在结点内进行查找一般是顺序查找或折半查找,而沿指针搜索结点的过程如下:
    从根开始查找,如果 Ki = KEY 则查找成功。

    • Ki < KEY < Ki+1; 查找 Ai 指向的结点
    • KEY < K1; 查找 A0 指向的结点
    • KEY > Kn; 查找 An指向的结点
    • 若 找到叶子,则查找失败。

    5.4 B-树的查找分析

    在磁盘上进行一次查找比在内存中进行一次查找耗时多很多,因此B-树的查找效率主要取决于访问外设的次数,即:取决于待查关键字所在结点在B-树上的层次数
    比如:
    设N=106,m=256,则h<=3,即最多访问外存3次可找到所有的记录。
    最后提一嘴关于B-树,B树就是B-树,不知道是谁把B-Tree翻译成B-树,误导了当年的我,想当年我一直不知道B树和B-树是一个玩意儿……

    5.5 B+树

    B+树是B-树的变异树。
    一棵mB+树和mB-树的差异:

    • n棵子树的结点中含有n个关键字;
    • 所有的叶子节点中包含了全部关键字的信息,及指向含这些关键字记录的指针,且叶子节点本身依关键字的大小自小而大顺序链接。
    • 所有的非终端节点可以看成是索引部分,结点中仅含有其子树(根结点)中的最大(或最小)关键字

    这个定义应该不难理解。
    当时B+树没要求掌握,所以课件上给的东西也很少。

    5.6 B+树的查找

    • 从最小关键字顺序查找
    • 从根开始随机查找

    6 哈希查找

    这个我就不写了,之前写过一篇。可以参考文章:【数据结构】【哈希】哈希表的概念和算法实现

    7 总结

    最后呢,总结一下查找的时间复杂度:

    • 顺序查找:O(n)
    • 折半查找:O(logn),(O(log2n)) 因为要先快排所以总复杂度为O(nlogn)
    • 二叉排序树(二叉查找树、BST):O(logn)(平均情况下)
    • 平衡二叉排序树(AVL树):O(logn)(O(log2n))
    • B树:O(logn) (O(log2n))
    • 哈希查找:O(1)
    展开全文
  • 折半查找 把low放在最左边,high放最右边,mid=(high+low)/2 如果low<=high则循环,当待查找数<mid,则high=mid-1,当待查数>mid,则low+1 当low=mid的时候,该值与查找数相等,则输出,...二叉排序树 if左
  • 【数据结构】折半查找及其二叉判定画法

    万次阅读 多人点赞 2019-09-25 23:55:40
    折半查找又叫二分查找,是数据结构中一种很重要的查找方式。 其特点有以下几个: 只能对有序的顺序表进行查找。 是一种静态查找。 查找的平均时间复杂度为o(log...折半查找和二叉排序树查找的平均查找长度均取决...
  • 折半查找  对于关键码有序的数列,用二分法查找。  比如123456789,要找2,先折半找5,2比5小,继续向左查找,找3,2比3小,继续向左查找,2匹配成功。  可以想到这是个递归的过程我这里递归非递归都写一遍。  ...
  • 折半查找二叉查找

    万次阅读 2016-02-17 18:03:09
    折半查找二叉查找的效率均高于顺序查找,在本文构建的折半查找二叉查找在生活中的应用也是十分广泛。
  • public class Search { public class BiTreeNode{ int m_nValue; BiTreeNode m_pLeft; BiTreeNode m_pRight; } //顺序查找,查到则返回该值下标,查不到返回-1. public...
  • 顺序查找 折半查找 二叉排序树

    千次阅读 2013-07-18 21:13:13
    1.顺序查找,折半查找二叉排序树操作定义 SeqSearch.h #include #define ARRAYLEN 8 int source[]={69, 65, 90, 37, 92, 6, 28, 54}; //静态查找表 int source1[ARRAYLEN + 1]={69, 65, 90, 37, 92, 6, 28, 54...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,217
精华内容 2,486
关键字:

折半查找和二叉排序树查找