zoukankan      html  css  js  c++  java
  • JAVA数据结构与算法(一)

    数据结构和算法概述

    数据结构就是把数据元素按照一定的关系组织起来的集合,用来组织和存储数据
    数据结构分为逻辑结构和物理结构两大类

    逻辑结构分类

    a.集合结构:集合结构中数据元素除了属于同一个集合外,他们之间没有任何其他的关系。
    b.线性结构:线性结构中的数据元素之间存在一对一的关系。
    c.树形结构:树形结构中的数据元素之间存在一对多的层次关系
    d.图形结构:图形结构的数据元素是多对多的关系
    

    物理结构分类

    顺序存储结构:把数据元素放到地址连续的存储单元里面,其数据间的逻辑关系和物理关系是一致的 ,比如我们常用的数组就是顺序存储结构。
    链式存储结构:数据元素存放在任意的存储单元里面,这组存储单元可以是连续的也可以是不连续的。此时,数据元素之间并不能反映元素间的逻辑关系,
    因此在链式存储结构中引进了一个指针存放数据元素的地址,这样通过地址就可以找到相关联数据元素的位置。
    

    算法

    根据一定的条件,对一些数据进行计算,得到需要的结果。
    在程序中,我们可以用不同的算法解决相同的问题,而不同的算法的成本也是不相同的。
    总体上,一个优秀的算法追求以下两个目标:
    1.花最少的时间完成需求;
    2.占用最少的内存空间完成需求;

    算法的复杂度分析

    时间复杂度分析

    时间复杂度分析实例

    大O记法规则

    推导大O阶的表示法有以下几个规则可以使用

    1. 用常数1取代运行时间中的所有加法常数;
    2. 在修改后的运行次数中,只保留高阶项;
    3. 如果最高阶项存在,且常数因子不为1,则去除与这个项相乘的常数;

    常见的大O阶


    复杂程度从低到高依次为:O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^3)
    我们提到的运行时间都指的是最坏情况下的运行时间.

    空间复杂度分析

    排序算法(笔试题)

    稳定:如果a原本在b前面且a=b,排序之后a仍然在b的前面。
    不稳定:如果a原本在b的前面且a=b,排序之后 a 可能会出现在 b 的后面。
    时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
    空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。

    手撕 冒泡排序

    原理:由上至下,每行对相邻两个元素进行大小比较,若左边的大,则交换位置。

    public class BubbleSort {
        public static void main(String[] args) {
            Integer[] aArray= {4,5,6,3,2,1};
            bubbleSort(aArray);
            System.out.println(Arrays.toString(aArray));
        }
    
        public static void bubbleSort(Comparable[] a){
            for(int i=a.length-1;i>0;i--){
                for(int j=0;j<i;j++){
                    if(Sort(a[j],a[j+1])){
                        exchange(a,j,j+1);
                    }
                }
    
            }
    
        }
        public static boolean Sort(Comparable lTemp, Comparable rTemp){
            return lTemp.compareTo(rTemp)>0;
        }
        public static void exchange(Comparable[] a,int i,int j){
            Comparable temp=a[i];
            a[i]=a[j];
            a[j]=temp;
        }
    }
    

    手撕 快速排序

    package simple;
    
    
    import java.util.Arrays;
    
    /**
     * @Author hwj
     * @Date 2020/8/14 9:41
     * @Desc: 快速排序是对冒泡排序的一种改进。它的基本思想是:
     * 一轮排序:
     * 定义第一个数字为基准,右指针指向最右侧,左指针指向最左侧
     * 先动右指针,当发现比基准小,记录右指针位置
     * 再动左指针,发现比基准大,记录左指针位置
     * 交换左右指针位置元素
     * 再循环先右后左,直至左指针+1>右指针
     * 交换基准元素与右指针
     * 或者右指针-1=0,则数组不变
     *
     * 分隔:
     * 通过一趟排序将要排序的数据分割成独立的两部分,
     * 其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,
     * 整个排序过程可以递归进行,以此达到整个数据变成有序序列。
     **/
    public class QuickSort {
        public static void main(String[] args) {
            Integer[] arr = {6, 1, 2, 7, 9, 3, 4, 5, 8};
            sort(arr);
            System.out.println(Arrays.toString(arr));
        }
        // 主排序方法入口
        public static void sort(Comparable[] arr){
            int lo=0;
            int hi=arr.length-1;
            sort(arr,lo,hi);
        }
        // 分段排序方法入口
        public static void sort(Comparable[] arr,int lo,int hi){
            // 当两个指针相遇,结束递归
            if (hi<=lo){
                return;
            }
            //对数组中,从lo到hi的元素进行切分
            int partition = partition(arr, lo, hi);
            //对左边分组中的元素进行排序
            sort(arr,lo,partition-1);
            //对右边分组中的元素进行排序
            sort(arr,partition+1,hi);
        }
        // 数组切分
        public static int partition(Comparable[] arr,int lo,int hi){
            Comparable key=arr[lo];// 把最左边的元素当做基准值
            int left=lo;// 定义一个左侧指针,初始指向最左边的元素
            int right=hi+1;// 定义一个右侧指针,初始指向左右侧的元素下一个位置
    //进行切分
            while(true){
    //先从右往左扫描,找到一个比基准值小的元素
                while(less(key,arr[--right])){//循环停止,证明找到了一个比基准值小的元素
                    if (right==lo){
                        break;//已经扫描到最左边了,无需继续扫描
                    }
                }
    //再从左往右扫描,找一个比基准值大的元素
                while(less(arr[++left],key)){//循环停止,证明找到了一个比基准值大的元素
                    if (left==hi){
                        break;//已经扫描到了最右边了,无需继续扫描
                    }
                }
                if (left>=right){
    //扫描完了所有元素,结束循环
                    break;
                }else{
    //交换left和right索引处的元素
                    exch(arr,left,right);
                }
            }
    //交换最后rigth索引处和基准值所在的索引处的值
            exch(arr,lo,right);
            return right; //right就是切分的界限
        }
        /*
       数组元素i和j交换位置
       */
        private static void exch(Comparable[] arr, int i, int j) {
            Comparable t = arr[i];
            arr[i] = arr[j];
            arr[j] = t;
        }
        /*
        比较v元素是否小于w元素
        */
        private static boolean less(Comparable v, Comparable w) {
            return v.compareTo(w) < 0;
        }
    }
    
    
    • 代码实现

      1)队列操作

      1. package queue;
        
        import java.util.Scanner;
        
        public class QueueOp {
        
            public static void main(String[] args) {
                ArrayQueue queue = new ArrayQueue(3);
                char key = ' ';
                Scanner scanner = new Scanner(System.in);
                boolean loop = true;
                // 输出队列
                while (loop) {
                    System.out.println("s(show):显示队列");
                    System.out.println("e(exit):退出程序");
                    System.out.println("a(add):添加数据到队列");
                    System.out.println("g(get):从队列取出数据");
                    System.out.println("l(location):显示队列指定位置数据");
                    key = scanner.next().charAt(0);
        
                    switch (key) {
                        case 's':
                            queue.ShowQueue();
                            break;
                        case 'a':
                            System.out.println("输出一个数");
                            int value = scanner.nextInt();
                            queue.addQueue(value);
                            break;
                        case 'g':
                            try {
                                int res = queue.outQueue();
                                System.out.printf("取出的数据是%d
        ", res);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            break;
                        case 'l':
                            int appoint = scanner.nextInt();
                            queue.ShowAppoint(appoint);
                    }
                }
        
        
            }
        
        }
        
        // 初始化
        class ArrayQueue {
            /**
             * 变量声明:
             * 1 数组最大容量
             * 2 队列头
             * 3 队列尾
             * 4 队列数组(一维)
             */
            private int MaxSize;
            private int front;
            private int rear;
            private int[] queue;
        
            public ArrayQueue(int MaxSize) {
                // 对声明的变量进行初始化
                this.MaxSize = MaxSize;
                front = -1;
                rear = -1;
                queue = new int[MaxSize];
            }
        
            // 判断队列是否满
            public boolean isFull() {
                return rear == MaxSize;
            }
        
            // 判断队列是否为空
            public boolean isEmpty() {
                return front == rear;
            }
        
            // 加数据
            public void addQueue(int n) {
                if (isFull()) {
                    System.out.println("队列满,不能加入数据~");
                    return;
                }
                rear++; //让rear后移
                queue[rear] = n;
        
            }
        
            // 取数据
            public int outQueue() {
                if (isEmpty()) {
                    throw new RuntimeException("队列空,不能取数据~");
                }
                front++; //让front后移
                return queue[front];
            }
        
            // 显示队列所有数据
            public void ShowQueue() {
                if (isEmpty()) {
                    throw new RuntimeException("队列空,无数据~");
                }
                int t = -1;
                t++; //让front后移
                System.out.printf("queue [%d]=%d/t", t, queue[t]);
            }
        
            //显示队列指定位置数据
            public void ShowAppoint(int appoint) {
                if (appoint <= -1 || appoint >= MaxSize) {
                    throw new RuntimeException("队列空,无数据~");
                }
                int t = -1;
                t++; //让front后移
                System.out.printf("queue [%d]=%d
        ", t, queue[t]);
            }
        }
        

      2)环形队列

      关键点:

        1)int[] arr 是定义一个整型数组当队列

        2)maxSize是数组的最大容量

        (这里规定,满队列时元素的个数是maxSize-1)

        3)front指向队列的第一个元素,也就是说 array[front] 是队列的第一个元素

        4)rear指向队列的最后一个元素,初值为0

        5)队列满的条件:(rear + 1) % maxSize == front

        队列为空的条件: rear == front

      package queue;
      
      import java.util.Scanner;
      
      public class CircleQueue {
          public static void main(String[] args) {
              //测试一把
              System.out.println("测试数组模拟环形队列的案例~~~");
      
              // 创建一个环形队列
              CircleArray queue = new CircleArray(4); //说明设置4,其队列有效数据最大是3
              char key = ' '; // 接收用户输入
              Scanner scanner = new Scanner(System.in);//
              boolean loop = true;
              // 输出一个菜单
              while (loop) {
                  System.out.println("s(show): 显示队列");
                  System.out.println("e(exit): 退出程序");
                  System.out.println("a(add): 添加数据到队列");
                  System.out.println("g(get): 从队列取出数据");
                  System.out.println("h(head): 查看队列头的数据");
                  key = scanner.next().charAt(0);// 接收一个字符
                  switch (key) {
                      case 's':
                          queue.showQueue();
                          break;
                      case 'a':
                          System.out.println("输出一个数");
                          int value = scanner.nextInt();
                          queue.addQueue(value);
                          break;
                      case 'g': // 取出数据
                          try {
                              int res = queue.getQueue();
                              System.out.printf("取出的数据是 %d
      ", res);
                          } catch (Exception e) {
                              // TODO: handle exception
                              System.out.println(e.getMessage());
                          }
                          break;
                      case 'h': // 查看队列头的数据
                          try {
                              int res = queue.headQueue();
                              System.out.printf("队列头的数据是%d
      ", res);
                          } catch (Exception e) {
                              // TODO: handle exception
                              System.out.println(e.getMessage());
                          }
                          break;
                      case 'e': // 退出
                          scanner.close();
                          loop = false;
                          break;
                      default:
                          break;
                  }
              }
              System.out.println("程序退出~~");
          }
      
      }
      
      
      class CircleArray {
          private int maxSize; // 表示数组的最大容量
          //front 变量的含义做一个调整:front就指向队列的第一个元素,也就是说arr[front]就是队列的第一个元素
          //front 初始值= 0
          private int front;
          //rear 变量的含义做一个调整:rear 指向队列的最后一个元素的后一个位置.因为希望空出一个空间做为约定
          //rear 初始值= 0
          private int rear; // 队列尾
          private int[] arr; // 该数据用于存放数据,模拟队列
      
          public CircleArray(int arrMaxSize) {
              maxSize = arrMaxSize;
              arr = new int[maxSize];
          }
      
          // 判断队列是否满
          public boolean isFull() {
              return (rear + 1) % maxSize == front;
          }
      
          // 判断队列是否为空
          public boolean isEmpty() {
              return rear == front;
          }
      
          // 添加数据到队列
          public void addQueue(int n) {
              // 判断队列是否满
              if (isFull()) {
                  System.out.println("队列满,不能加入数据~");
                  return;
              }
              // 直接将数据加入
              arr[rear] = n;
              // 将rear后移,这里必须考虑取模
              rear = (rear + 1) % maxSize;
          }
      
          // 取数据
          public int getQueue() {
              // 判断队列是否为空
              if (isEmpty()) {
      //            抛出异常
                  throw new RuntimeException("队列空,不能取数据~");
              }
              //这里需要分析出 front 是指向队列的第一个元素
              //1. 先把 front 对应的值保留到一个临时变量
              //2. 将 front 后移,考虑取模
              //3. 将临时保存的变量返回
              int value = arr[front];
              front = (front + 1) % maxSize;
              return value;
      
          }
      
          // 显示队列所有数据
          public void showQueue() {
              // 遍历
              if (isEmpty()) {
                  System.out.println("队列空的,没有数据~~");
                  return;
              }
      //        思路:从front开始遍历,遍历多少个元素
      
              for (int i = front; i < front + size(); i++) {
                  System.out.printf("arr[%d]=%d
      ", i % maxSize, arr[i % maxSize]);
              }
          }
      
          // 求出当前队列有效数据个数
          public int size() {
              // rear = 2
              // front = 1
              // maxSize = 3
              return (rear + maxSize - front) % maxSize;
          }
      
          // 显示队列的数据,注意不是取出数据
          public int headQueue() {
              // 判断
              if (isEmpty()) {
                  throw new RuntimeException("队列空的,没有数据~~");
              }
              return arr[front];
          }
      }
      
    初晨暖阳,夜落星河。 少年披梦,远方有歌。 红黄之上,春夏晚风。 闲肆游走,人群熙攘。
  • 相关阅读:
    27. Remove Element
    26. Remove Duplicates from Sorted Array
    643. Maximum Average Subarray I
    674. Longest Continuous Increasing Subsequence
    1. Two Sum
    217. Contains Duplicate
    448. Find All Numbers Disappeared in an Array
    566. Reshape the Matrix
    628. Maximum Product of Three Numbers
    UVa 1349 Optimal Bus Route Design (最佳完美匹配)
  • 原文地址:https://www.cnblogs.com/alidata/p/13448690.html
Copyright © 2011-2022 走看看