• 数据结构12——查找


    查找主要分类:

    如上图所示:查找可分为动态查找和静态查找。

    静态查找:只是在数据集合中查找是否含有某个元素。

    动态查找:查找过程中包括数据的插入和删除中产生的数据。

    1:静态查找

    1.1:无序查找:相对容易,只提供无序查找的代码

    1 public static int seqSearch(int[] a,int ele){
    2         for (int i = 0; i < a.length; i++) {
    3             if (ele==a[i]) 
    4                 return i;
    5         }
    6          return -1;
    7     }

    1.2:有序查找

    有序查找又可以分为顺序查找和二分查找。

    1.2.1:顺序查找

    1 public static int orderSearch(int[] a ,int ele){
    2         int i;
    3         for (i = 0; a[i]<ele && i < a.length-1; i++) ;
    4         if (ele==a[i]) {
    5             return i;
    6         }
    7         else return -1;
    8     }

    1.2.3:二分查找

    public static int binarySearch(int[] a, int ele){
            int n=a.length;
            int low=0 , hight=n-1, mid;
            while(low<=hight){
                mid=(low+hight)/2;
                if (a[mid]<ele) 
                    low=mid+1;
                else if (a[mid]>ele) 
                    hight=mid-1;
                else return mid;
            }
            return -1;
        }

    时间复杂度分析:对于二分法查找,因为都是对半分开,所以对于数据长度为n的集合,查找的平均时间复杂度为  Log2n

    2:动态查找

    对于动态查找,在查找的过程中涉及到了数据的插入和删除,数据集合的长度都是动态变化的。

    动态查找的结构主要分为:二叉树结构(二叉排序树),树结构(B_树)。

    2.1:二叉排序树

    二叉排序树的主要特征为:

    (1):若左子树不为空,则左子树上所有的结点的数据元素值都小于根结点的数据元素值。

    (2):若右子树不为空,则右子树上所有的结点的数据元素值都小于根结点的数据元素值。

    (3):同时左右子树也为二叉排序树。

    二叉排序树的结点类:

    二叉排序树的结点类必须包括两个方面:数据,结点。  同时结点又分为左孩子结点,右孩子结点,父亲结点。

     1 package com.hone.search;
     2 /*
     3  * 定义一个二叉排序树结点类
     4  * 包含四个元素:左孩子结点,右孩子结点,数据,父母结点
     5  */
     6 public class BinarySortTreeNode {
     7     private BinarySortTreeNode leftChild;
     8     private BinarySortTreeNode rightChild;
     9     private BinarySortTreeNode parent;
    10     private int data;
    11     
    12     //没有孩子结点
    13     public BinarySortTreeNode(){
    14         leftChild=null;
    15         rightChild=null;
    16     }
    17     
    18     //没有孩子结点,只有自身元素的初始化方法
    19     public BinarySortTreeNode(int item){
    20         data=item;
    21         leftChild=null;
    22         rightChild=null;
    23     }
    24     
    25     public BinarySortTreeNode(int item, BinarySortTreeNode left,BinarySortTreeNode right){
    26         leftChild=left;
    27         rightChild=right;
    28         data=item;
    29     }
    30 
    31     //封装四个元素
    32     public BinarySortTreeNode getLeftChild() {
    33         return leftChild;
    34     }
    35 
    36     public BinarySortTreeNode getRightChild() {
    37         return rightChild;
    38     }
    39 
    40     public BinarySortTreeNode getParent() {
    41         return parent;
    42     }
    43 
    44     public int getData() {
    45         return data;
    46     }
    47 
    48     public void setLeftChild(BinarySortTreeNode leftChild) {
    49         this.leftChild = leftChild;
    50     }
    51 
    52     public void setRightChild(BinarySortTreeNode rightChild) {
    53         this.rightChild = rightChild;
    54     }
    55 
    56     public void setParent(BinarySortTreeNode parent) {
    57         this.parent = parent;
    58     }
    59 
    60     public void setData(int data) {
    61         this.data = data;
    62     }
    63     
    64     //获得左子树
    65     public BinarySortTreeNode getLeft(){
    66         return leftChild;
    67     }
    68     
    69     //获得右子树
    70     public BinarySortTreeNode getRight(){
    71         return rightChild;
    72     }
    73 
    74 }

    二叉排序树的类:

    二叉排序树的类中的方法主要包括查找,删除,插入

    二叉树遍历查找过程:

     1 //查找某一个元素的位置
     2     public BinarySortTreeNode find(int item){
     3         if (root != null) {
     4             BinarySortTreeNode temp=root;
     5             while(temp != null){
     6                 if (temp.getData() == item) {
     7                     return temp;
     8                 }
     9                 //如果item>temp.getData()  则数一定在右边,整个过程类似于二分查找
    10                 if (temp.getData()<item) 
    11                     temp.getRight();
    12                 else 
    13                     temp.getLeft();
    14             }
    15         }
    16         return null;
    17     }

    二叉排序树的插入过程:

    这里面的插入操作同时也包括查找过程,首先查找需要插入的数据是否在二叉树中存在,如果存在则结束,如果不存在,则根据需要插入结点的数值,把储存该数据元素的结点,插入到二叉排序树查找失败的左孩子或者右孩子结点。

    插入代码

     1 //插入一个元素,传入两个参数,一个为当前结点,一个为数据元素
     2     public void insert(BinarySortTreeNode ptr, int item){
     3         if (item < ptr.getData()) {            //插入左子树中
     4             if (ptr.getLeft()==null) {
     5                 BinarySortTreeNode temp=new BinarySortTreeNode(item);
     6                 temp.setParent(ptr);
     7                 ptr.setLeftChild(temp);
     8             }
     9             else
    10                 insert(ptr.getLeft(), item);
    11         }
    12         if (item > ptr.getData()) {            //插入右子树中
    13             if (ptr.getRight()==null) {
    14                 BinarySortTreeNode temp=new BinarySortTreeNode(item);
    15                 temp.setParent(ptr);
    16                 ptr.setRightChild(temp);
    17             }
    18             else
    19                 insert(ptr.getRight(), item);
    20         }
    21     }

    二叉树的删除算法:

    首先需要查找数据元素是否存在于二叉排序树中,如果不存在,则直接结束,如果存在又分为四种情况

    (1):待删除结点无孩子结点,这种情况只需要直接删除该节点即可

    (2):待删除结点只有左孩子结点,删除该结点,并且使该结点的父亲结点指向被删除结点的左孩子结点(但是在写代码过程中,被删除结点的左孩子结点是放在被删除结点                的左孩子位还是右孩子位?)

    (3):待删除结点只有右孩子结点,删除该结点,并且使该结点的父亲结点指向被删除结点的

    (4):待删除结点有左右孩子结点,第一步 :寻找要删除结点右子树的最小结点,

                      第二步 :将右子树中最小结点拷贝到要删除结点上面

                      第三步:最后删除右子树的最左结点

     1 //删除某一个元素
     2     public void delete(BinarySortTreeNode ptr, int item){
     3         if (ptr != null) {
     4             if (item<ptr.getData()) 
     5                 delete(ptr.getLeft(), item);        //在左子树遍历
     6             else if (item > ptr.getData()) 
     7                 delete(ptr.getRight(), item);        //在右子树 遍历
     8             /*
     9              * 当左右子树都存在时,首先查找数据元素值大于要删除结点元素的关键字的最小值,也就是寻找
    10              * 要删除结点右子树的最左结点,然后将其拷贝到要删除的结点
    11              * 最后删除右子树的最左结点
    12              */
    13             
    14             else if (ptr.getLeft() != null&& ptr.getRight()!=null) {
    15                 BinarySortTreeNode min;
    16                 min=ptr.getRight();
    17                 while(min.getLeft()!=null){
    18                     min=min.getLeft();
    19                 }
    20                 ptr.setData(min.getData());             //将最小数值赋值给ptr元素
    21                 //在ptr结点的右子树中递归删除min结点
    22                 delete(ptr.getRight(), min.getData());         
    23                 
    24             }
    25             
    26             /*
    27              * 当待删除结点只有右孩子时,画图理解
    28              * 删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点
    29              */
    30             
    31             else if (ptr.getLeft()==null&&ptr.getRight()!=null) {
    32                 ptr.getParent().setRightChild(ptr.getRight());
    33                 ptr.getRight().setParent(ptr.getParent());
    34                 
    35             }
    36             /*
    37              * 当待删除结点只有左孩子结点时,
    38              */
    39             else if (ptr.getLeft()!=null&&ptr.getRight()==null) {
    40                 ptr.getParent().setLeftChild(ptr.getLeft());
    41                 ptr.getLeft().setParent(ptr.getParent());
    42             }
    43             /*
    44              * 当待删除结点为叶子节点时
    45              */
    46             else {
    47                 BinarySortTreeNode parent=ptr.getParent();
    48                 if (parent.getLeft()==ptr) {
    49                     parent.setLeftChild(null);
    50                 }
    51                 else{
    52                     parent.setRightChild(null);
    53                 }
    54             }
    55         }
    56         
    57     }

      

    完整代码:

      1 package com.hone.search;
      2 
      3 /*
      4  * 二叉排序树的主要方法包括查找,删除,插入
      5  */
      6 public class BinarySortTree {
      7     public BinarySortTreeNode root;                //获得根节点
      8     
      9     //中序遍历
     10     private void inOrder(BinarySortTreeNode t,Visit vs){
     11         if (t!=null) {
     12             inOrder(t.getLeftChild(), vs);
     13             vs.print(new Integer(t.getData()));
     14             inOrder(t.getRightChild(), vs);
     15         }
     16     }
     17     
     18     //前序遍历
     19     private void preOrder(BinarySortTreeNode t,Visit vs){
     20         if (t!=null) {
     21             vs.print(new Integer(t.getData()));
     22             preOrder(t.getLeftChild(), vs);
     23             preOrder(t.getRightChild(), vs);
     24         }
     25     }
     26     
     27     //构造函数,初始化根节点
     28     public BinarySortTree (){
     29         root=null;
     30     }
     31     
     32 
     33     public BinarySortTreeNode getRoot() {
     34         return root;
     35     }
     36 
     37     public void setRoot(BinarySortTreeNode root) {
     38         this.root = root;
     39     }
     40     
     41     //统一遍历的接口
     42     public void preOrder(Visit vs){
     43         preOrder(root, vs);
     44     }
     45     public void inOder(Visit vs){
     46         inOrder(root, vs);
     47     }
     48     
     49     //取左孩子(左孩子可以是一个集合)
     50     public BinarySortTreeNode getLeft(BinarySortTreeNode current){
     51         return current != null ? current.getLeft():null; 
     52     }
     53     
     54     //取右孩子
     55     public BinarySortTreeNode getRight(BinarySortTreeNode current){
     56         return current != null ? current.getRight():null; 
     57     }
     58     
     59     //查找某一个元素的位置
     60     public BinarySortTreeNode find(int item){
     61         if (root != null) {
     62             BinarySortTreeNode temp=root;
     63             while(temp != null){
     64                 if (temp.getData() == item) {
     65                     return temp;
     66                 }
     67                 //如果item>temp.getData()  则数一定在右边
     68                 if (temp.getData()<item) 
     69                     temp.getRight();
     70                 else 
     71                     temp.getLeft();
     72             }
     73         }
     74         return null;
     75     }
     76     
     77     //插入一个元素,传入两个参数,一个为当前结点,一个为数据元素
     78     public void insert(BinarySortTreeNode ptr, int item){
     79         if (item < ptr.getData()) {
     80             if (ptr.getLeft()==null) {
     81                 BinarySortTreeNode temp=new BinarySortTreeNode(item);
     82                 temp.setParent(ptr);
     83                 ptr.setLeftChild(temp);
     84             }
     85             else
     86                 insert(ptr.getLeft(), item);
     87         }
     88         if (item > ptr.getData()) {
     89             if (ptr.getRight()==null) {
     90                 BinarySortTreeNode temp=new BinarySortTreeNode(item);
     91                 temp.setParent(ptr);
     92                 ptr.setRightChild(temp);
     93             }
     94             else
     95                 insert(ptr.getRight(), item);
     96         }
     97     }
     98     
     99     
    100     //删除某一个元素
    101     public void delete(BinarySortTreeNode ptr, int item){
    102         if (ptr != null) {
    103             if (item<ptr.getData()) 
    104                 delete(ptr.getLeft(), item);        //在左子树遍历
    105             else if (item > ptr.getData()) 
    106                 delete(ptr.getRight(), item);        //在右子树 遍历
    107             /*
    108              * 当左右子树都存在时,首先查找数据元素值大于要删除结点元素的关键字的最小值,也就是寻找
    109              * 要删除结点右子树的最左结点,然后将其拷贝到要删除的结点
    110              * 最后删除右子树的最左结点
    111              */
    112             
    113             else if (ptr.getLeft() != null&& ptr.getRight()!=null) {
    114                 BinarySortTreeNode min;
    115                 min=ptr.getRight();
    116                 while(min.getLeft()!=null){
    117                     min=min.getLeft();
    118                 }
    119                 ptr.setData(min.getData());             //将最小数值赋值给ptr元素
    120                 //在ptr结点的右子树中递归删除min结点
    121                 delete(ptr.getRight(), min.getData());         
    122                 
    123             }
    124             
    125             /*
    126              * 当待删除结点只有右孩子时,画图理解
    127              * 删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点
    128              */
    129             
    130             else if (ptr.getLeft()==null&&ptr.getRight()!=null) {
    131                 ptr.getParent().setRightChild(ptr.getRight());
    132                 ptr.getRight().setParent(ptr.getParent());
    133                 
    134             }
    135             /*
    136              * 当待删除结点只有左孩子结点时,
    137              */
    138             else if (ptr.getLeft()!=null&&ptr.getRight()==null) {
    139                 ptr.getParent().setLeftChild(ptr.getLeft());
    140                 ptr.getLeft().setParent(ptr.getParent());
    141             }
    142             /*
    143              * 当待删除结点为叶子节点时
    144              */
    145             else {
    146                 BinarySortTreeNode parent=ptr.getParent();
    147                 if (parent.getLeft()==ptr) {
    148                     parent.setLeftChild(null);
    149                 }
    150                 else{
    151                     parent.setRightChild(null);
    152                 }
    153             }
    154         }
    155         
    156     }  
    160 }

    总体而言:

    二叉排序树的插入,删除,时间复杂度的最重要的的查找部分。

    一般情况下:二叉排序树的平均查找长度O(log2n)

    最坏情况下:为一颗单分支退化树平均查找长度为   O(n)

  • 相关阅读:
    Codeforces A. Bear and Big Brother
    codeforces A. In Search of an Easy Problem
    c#判断两个对象和对象中的属性是否相同(以及记录对象中的哪些字段,和详细的改变情况)
    生成随机字符串
    SQL语句计算距离今天生日还差几天
    sqlServer 获取最新的一条数据
    c#所有部门及其下所部门生成树形图(递归算法获取或键值对方式获取)
    根据中文名,自动生成首字母的拼音码或拼音码(两种方法)
    char/varchar/nvarchar的区别
    c#中ofType的用法
  • 原文地址:https://www.cnblogs.com/xiaxj/p/6732279.html
Copyright © 2020-2023  润新知