数据结构与算法

数据结构知识点:

在这里插入图片描述
1.队列和栈说经常使用的数据结构,特点为:队列先进先出,栈是后进先出。
2.表包括很多种,有占有连续空间的数组;用指针链接的单向链表和双向链表;首尾相连的循环链表;及散列表,哈希表。
3.图,在特定的领域使用的比较多,例如路由算法中使用的比较多,分为有向图,无向图,带权图。
4.树,树一般用作查找和排序的辅助结构;(二叉树;多叉树)

a.多叉树包括B树族,有B树,B+树,B*树,比较是和做文件索引,另一个是字典树,适合进行字符串你的多模匹配。
b.二叉树包括平衡二叉树,红黑树,哈夫曼树,以及堆,适合用于数据的查询和排序。需要连接二叉树的构建,插入,删除操的实现,需要掌握二叉树的前序,中序,后续遍历。

二叉树:

二叉树满足以下条件:每个节点包含一个值,每个节点至多有两个子树,每个节点的左子树节点的值都小于自身,右子树节点的值都大于自身的值。
二叉树的查询时间复杂度是log(N) ,但随着不断地插入,删除节点,二叉树的高度可能会不断变大,当一个二叉树所有的节点都只有左子树或者右子树时,其查询性能就退化成线性了。

二叉树遍历

遍历:就是按照某种次序访问树中所有节点,且每个节点恰好只能访问一次
将整个二叉树分为三个部分,根、左子树、右子树;那么根据根的遍历顺序就有三种遍历方式:

先序遍历DLR:根、左子树、右子树
中序遍历LDR:左子树、根、右子树
后序遍历LRD:左子树、右子树、根

如下图: (方法:先找根,先将根放在对应位置)
在这里插入图片描述
定义二叉树节点类

public class Node {
    int value; //节点值
    Node leftChild; //左子树引用
    Node rightChild;//右子树引用

    public Node(int value) {
        this.value = value;
    }

    public Node(int value, Node leftChild, Node rightChild) {
        super();
        this.value = value;
        this.leftChild = leftChild;
        this.rightChild = rightChild;
    }
}

平衡二叉树

平衡二叉树可以很好解决上面所说的这个问题,平衡二叉树保证每个节点左右子树的高度差的绝对值不超过1,叉树和删除可能经常需要旋转来保持平衡,比较适合插入,删除比较少的场景。

红黑树

在这里插入图片描述

红黑树是一种更加实用的非严格的平衡二叉树,红黑树更关注局部平衡而非整体平衡;确保没有一条路径会比其他路径长出2倍,所以是接近平衡的,但减少了许多不必要的旋转操作,更加实用。java8的HashMap中就应用了红黑树来解决散列冲突时的查找问题。TreeMap也是通过红黑树来保证有序性的

红黑树除了具有二叉树的特点外还具有一下规则:

1.根节点是黑色
2.每个叶子节点都是黑色的空节点
3.红色节点的两个子节点都是黑色的
4.任意节点到其叶子节点的每条路径上,包含相同数量的黑色节点

B 树

在这里插入图片描述

B树是一种多叉树,也叫多路搜索树。B树中每个节点可以存储多个元素,非常适合用在文件索引上,可以有效减少磁盘IO次数,B树种所有节点的最大子节点树称为B树的阶(如上图:3阶B树)

B+树

B+树的定义与B树基本相同,但也具有以前特点:
1.节点中的关键字与子树数目相同,比如节点中有三个关键字,那么就有三颗子树。
2.关键字对应的子树节点都大于或等于关键字,子树中包括关键字自身。
3.所有关键字都有出现在叶子节点上
4.所有叶子节点都有指向下一个叶子节点的指针。

与B树不同,B+树在搜索时不会在非叶子节点命中,一定会查询到叶子节点;另外一个,叶子节点相当于数据存储层,保存关键字对应数据,而非叶子节点只保存关键字和指向节点的指针,不保存关键字对应的数据,所以同样数量关键字的非叶子节点B+树比B树要小很多。

B+树更适合索引系统,MySQL数据库的索引就提供B+树实现:

1.由于叶子节点之间有指针相连,B+树更适合范围检索;
2.由于非叶子节点只保存关键字和指针,同样大小非叶子节点,B+树可以容纳更多的关键字,可以降低树高,查询时读写代价更低。
3.B+树的查询效率比较稳定。任何关键字的查找必须走一条从根节点到叶子节点的路,所有关键字查询路径长度相同,相率相当。

栈(stack)又称堆栈,他是运算受限的线性表,其限制是仅允许在表的一端进行插入和删除操作,不允许在其他位置进行插入,查找,删除等操作。
表中进行插入,删除操作的一段称为栈顶(top),栈顶保存的元素称为栈顶元素。相对的表的另一端称为栈底(bottom)

对栈操作的专业词汇:入栈 (push)出栈(pop)获取栈顶元素(peek)
栈的存储结构:和线性表类似,堆栈也有两种存储结构,顺序存储结构和链式存储结构。
先进后出

队列

队列(queue)和栈一样也是一种运算受限的线性表,其限制条件是仅允许在表的一端进行插入,在表的另一端进行删除。
在队列中把插入元素的一段称队尾(rear),删除元素的一段称为队首(front)
先进先出

时间复杂度:

时间复杂度链接描述
若存在函数 f(n),使得当n趋近于无穷大时,T(n)/ f(n)的极限值为不等于零的常数,则称 f(n)是T(n)的同数量级函数。
记作 T(n)= O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。
渐进时间复杂度用大写O来表示,所以也被称为大O表示法。

如何推导出时间复杂度呢?有如下几个原则:

  • 如果运行时间是常数量级,用常数1表示;
  • 只保留时间函数中的最高阶项;
  • 如果最高阶项存在,则省去最高阶项前面的系数。

排序算法

1.冒泡排序

/**
    int[] arr = new int[] {3, 6, 10, 9, 5, 7, 4};
     * 3 2 6 5 7 4 9  第一轮
     * 2 3 5 6 4 7  第二轮
     * 2 3 5 4 6
     * 2 3 4 5
     * 2 3 4
     * 2 3
     */
    public static void sort(int[] arr) {
        int min;
        //比较多少轮
        for (int i = 0; i < arr.length - 1; i++) {
            //每轮比较几个数
            for (int j =0;j<arr.length-1-i;j++)
            if (arr[j] > arr[j+1]) {
                min = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = min;
            }
        }
        System.out.println(Arrays.toString(arr));
    }

2.快速排序

在这里插入图片描述

public static void quickSort(int[] arr, int left, int right) {
        int l = left;//左下标
        int r = right;//右下标
        //中轴值(取数组中间的值作为比较对象)
        int pivot = arr[(left + right)/2] ;
        int temp ;
        //while循环目的让比pivot下的值放在左边,比pivot大的值放在右边
        while (l < r) {
            //在pivot左边找,找到大于等于pivot的值才退出
            while (arr[l] < pivot) {
                l += 1;
            }
            //在pivot右边找,找到小于等于pivot的值才退出
            while (arr[r] > pivot) {
                r -= 1;
            }
            //如果l大于等于r说明小于pivot的值全部在左边,大于pivot的值全部在右边
            if (l >= r) {
                break;
            }
            //交换值
            temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;
            //如果交换完,发现arr[l]==pivot的值,则r--,前移
            if (arr[l] == pivot) {
                r -= 1;
            }
            //如果交换完,发现arr[r]==pivot的值,则l++,后移
            if (arr[r] == pivot) {
                l += 1;
            }
            //如果出现l==r,必须l++,r--
            if (l == r) {
                l += 1;
                r -= 1;
            }
            System.out.println("===============l:"+l);
            System.out.println("===============r:"+r);

            //向左递归
            if (left < r) {
                quickSort(arr, left, r);
            }
            //向右递归
            if (right > l) {
                quickSort(arr, l, right);
            }

        }
    }

3.选择排序

算法思想:首先,找到数组中最小的元素,再将他和数组的第一个元素交换(如果第一个元素就是最小的那就和自己交换),再在剩下的元素中找到最小的那个,与第二个元素交换,如此反复,直至最后一个元素找不到最小的元素(即自己就是最小的元素)。
选择排序的内循环只是比较当前与目前已知最小元素,外循环比较交换元素

public static void selectSort(int[] arr) {
        for (int i=0 ;i<arr.length-1;i++) {
            int minIndex = i;
            int min = arr[i];
            for (int j = i + 1; j < arr.length; j++) {
                if (min > arr[j]) {//说明假定的最小值不是最小
                    min = arr[j];  //找到数组最小值,
                    minIndex = j; //找到数组最小值所对应的索引
                }
            }
//            将最小值放到arr[i]的位置
            if (minIndex != i) {
                arr[minIndex] = arr[i];//将最小值与数组第一位进行交换
                arr[i] = min;
            }
        }
    }

4.插入排序

将数组看作有序部分和无序部分,默认第一个元素是有序的。
从第二个元素开始往前插入,如果有序部分的元素大于要插入的元素,就继续向前遍历,直到碰见一个元素小于要插入的元素,这时,将要插入的元素插入该元素后面。
注意,在遍历的时候,大于要插入元素的元素一直在向后移动。

public static void insertSort(int[] arr) {
        //定义待插入的数
        for (int i = 1; i < arr.length; i++) {
            int insertVule = arr[i];
            int insertIndex = i-1;//即arr[i]前面的数
            第一次先比较arr[1]与arr[0],然后退出while;
            // 第二次比较arr[2]与arr[1],接着比较arr[1]与arr[0]再退出while
            while (insertIndex >= 0 && insertVule < arr[insertIndex]) {  
                arr[insertIndex + 1] = arr[insertIndex];
                insertIndex --;
            }
            //当退出while循环时,说明插入的位置找到插入位置
            arr[insertIndex + 1] = insertVule;
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值