王道考研系列--数据结构

温故而知新,打好基础才能走得更远。

一、基本概念

1、数据结构的基本概念

数据:是信息的载体,是描述客观事物属性的数、字符以及所有能输入到计算机中并被计算机程序识别和处理的符号的集合。
结构:数据元素相互之间的关系叫做“结构”
数据结构:相互之间存在一种或多种特定关系的数据元素的集合。
数据结构包括三方面内容:逻辑结构、存储结构、数据的运算。

2、算法的基本概念

算法:特定问题求解步骤的一种描述
特性:有穷性、确定性、可行性、输入、输出
算法效率的度量:
1、时间复杂度:最深层循环内的语句的频率。
常见的时间复杂度:

O(1)<O(log2n)<O(n)<O(nlog2n)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n)

2、空间复杂度:S(n),算法所耗费的存储空间

二、线性表

线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列。
顺序表由数组下标、数据元素组成。
顺序表不一定是数据按照大小排序的线性表。

线性表的链式表示
1、单链表 单链表的查找、插入、删除操作
2、双链表 双链表的插入、删除操作
3、循环链表

三、栈和队列

栈的定义:只允许在一端进行插入、删除操作的线性表
特点:先进后出

队列的定义:只允许在表的一端进行插入,在表的另一端进行删除。
特点:先进先出

四、树、二叉树

1、二叉树的遍历
前序遍历、中序遍历、后序遍历

五、图

日常工作对图的应用不是很多,是我平时接触的情景太low了吗?

六、查找

1、顺序查找:从线性表的一端开始,逐个检查关键字是否满足条件。找到则返回成功,没找到,则返回失败。

int orderSearch(int searchKey, int[] array) {
        if (array == null || array.length < 1) {
            return -1;
        }
        
        for (int i = 0; i < array.length; i++) {
            if (searchKey == array[i]) {
                return array[i];
            }
        }
        
        return -1;
    }

2、二分查找

int binarySearch(int searchKey, int[] array) {
        int low = 0;
        int high = array.length -1;
        while(low <= high) {
            int middle = (low + high) / 2;
            if (searchKey > array[middle]) {
                low = middle + 1;
            } else if (searchKey < array[middle]) {
                high = middle - 1;
            } else {
                return middle;
            }
        }
        
        return -1;
    }

3、分块查找

/**
     * 分块查找
     * 
     * @param index  索引表,存放各块的最大值
     * @param st     顺序表
     * @param key    查找关键字
     * @param m      顺序表中各块长度相等
     * @return
     */
    int blockSearch(int[] index, int[] st, int key, int m) {
        int i = binarySearch(key, index);
        
        if (i >= 0) {
            int j = i > 0 ? i * m : i;
            int len = (i + 1) * m;
            
            // 在确定的块中用顺序查找方法查找key
            for (int k = j; k < len; k++) {
                if (key == st[k]) {
                    return k;
                }
            }
        }
        
        return -1;
    }

4、散列表
之前的查找都是基于比较进行查找,Hash表是通过哈希函数直接求出结点的地址,是关键字到地址的直接转换方法。
(1)哈希函数:一个把查找表中的关键字映射为该关键字对应的地址的函数。
(2)散列表:根据关键字而直接进行访问的数据结构。

处理冲突的方法:
(1)开放定址法:如果两个数据元素的哈希值相同,则在哈希表中为后插入的数据元素另外选择一个表项。当程序查找哈希表时,如果没有在第一个对应的哈希表项中找到符合查找要求的数据元素,程序就会继续往后查找,直到找到一个符合查找要求的数据元素,或者遇到一个空的表项。  
(2)拉链法:将哈希值相同的数据元素存放在一个链表中,在查找哈希表的过程中,当查找到这个链表时,必须采用线性查找方法。

/**
     * Hash查找
     * 
     * @param hash
     * @param hashLength
     * @param key
     * @return
     */
    int searchHash(int[] hash, int hashLength, int key){
        int hashAddress = key % hashLength;  // 除留余数法
        
        // 指定的hashAddress对应值存在但不是关键值,则用开放寻址法继续定位
        while (hash[hashAddress] != 0 && hash[hashAddress] != key) {
            hashAddress = (++hashAddress) % hashLength;
        }
        
        // 查找到了开放单元,表示查找失败
        if (hash[hashAddress] == 0) {
            return -1;
        }
        
        return hashAddress;
    }

七、排序

1、排序的概念:重新排列表中的元素,使表中的元素满足按照关键字递增或递减的过程。
2、插入排序:直接插入排序、折半插入排序、希尔排序
直接插入排序:将元素从无序子序列取出,插入有序序列子序列中。

private static void insertSort(int[] array) {
        int n = array.length;
        int i,j;
        for (i = 1; i < n; i++) { // 无序列表的第一位比较数据就是index = 1的数据
            int temp = array[i]; // 本次循环,待插入有序列表的数
            
            // 以下遍历有序表,从后往前查找待插入位置
            // 无序列表取出的temp小于前驱,则无序列表所有元素向后移一位
            for (j = i- 1; j >= 0 && temp < array[j]; j--) { 
                array[j + 1] = array[j];
            }
            
            array[j + 1] = temp; // 插入元素
        }
        
        // 打印结果
        System.out.print("排序结果:");
        for (int k = 0; k < array.length; k++) {
            System.out.print(" " + array[k]);
        }
    }

折半插入法:在遍历有序表查找待插入元素位置时使用二分查找法进行插入位置的确定,其余思路和直接插入法保持一致。

private static void midInsertsort(int[] array) {
        int n = array.length;
        int i, j, low, high, mid;
        for (i = 1; i < n; i++) {
            int temp = array[i];

            // 以下为二分法在有序表中查找插入位置
            low = 1;
            high = i - 1;
            while (low <= high) {
                mid = (low + high) / 2;
                if (temp > array[mid]) { // 说明temp的位置在左半部分
                    low = mid + 1;
                } else { // 说明temp的位置在有半部分
                    high = mid - 1;
                }
            }

            // 有序表的元素向后移一位
            for (j = i - 1; j >= 0 && temp < array[j]; j--) {
                array[j + 1] = array[j];
            }

            array[j + 1] = temp; // 插入元素

        }

        // 打印结果
        System.out.print("排序结果:");
        for (int k = 0; k < array.length; k++) {
            System.out.print(" " + array[k]);
        }
    }

希尔排序:将整个无序序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序时,再对全体元素进行一次直接插入排序。
https://www.cnblogs.com/snowcan/p/6244391.html

2、交换排序:冒泡排序、快速排序
冒泡排序:对未排序范围内的相邻两个数进行比较,若后者比前者小,则互换位置,否则进入下一位继续比较(默认按照升序排列)

private static void bubbleSort(int[] array) {
        int n = array.length;
        boolean exchange;
        
        for (int i = 0; i < n; i++) {
            exchange = false;
            for (int j = 0; j < n - (i + 1); j++) {  // 这里只对未排序部分进行遍历比较
                if (array[j] > array[j + 1]) {
                    exchange = true;
                    int temp = array[j + 1];
                    array[j + 1] = array[j];
                    array[j] = temp;
                }
            }
            
            if(!exchange) // 无序互换,跳出循环,进行下一次比较
                break;
        }
        
        // 打印结果
        System.out.print("排序结果:");
        for (int k = 0; k < array.length; k++) {
            System.out.print(" " + array[k]);
        }
    }

快速排序:通过一趟排序将要排序的数据分割成独立的两部分,使其中一部分比另一部分所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
算法过程:
1.设置 low=0, high=N-1。
2.选择一个基准元素赋值给temp,即temp=a[low]。
3.从high开始向前搜索,即由后开始向前搜索(high–),找到第一个小于temp的值,将a[high]和a[low]交换。
4.从low开始向前后搜索,即由前开始向后搜索(low++),找到第一个大于temp的值,将a[high]和a[low]交换。
5.重复第3步和第4步,直到 low==high ,3,4步中,若没找到符合条件的值,执行 high– 或 low++ ,直到找到为止。进行交换时 low和high的位置不变。当low==high时循环结束。

private static void quickSort(int[] array, int low, int high) {
        if (low < high) {
            /**
             * 将数组一分为二
             */
            int middle = getMiddle(array, low, high);
            
            /**
             * 将小于基准元素的数据进行递归排序
             */
            quickSort(array, low, middle - 1);
            
            /**
             * 将大于基准元素的数据进行递归排序
             */
            quickSort(array, middle + 1, high);
        }
    }
    
    private static int getMiddle(int[] array, int low, int high) {
        int temp = array[low]; // 数组第一个元素为基准元素
        while (low < high) {
            while (low < high && array[high] > temp) {
                high--;
            }
            
            /**
             * 比基准小的数据移到低端
             */
            array[low] = array[high];  
        
            while (low < high && array[low] < temp) {
                low++;
            }
             /**
             * 比基准大的记录移到高端
             */
            array[high] = array[low];
        }
        
        /**
         * 此时 low == high
         */
        array[low] = temp;              
        return low;    
    }

3、选择排序:简单选择排序、堆排序
简单选择排序:在待排序数据中,选出最小的一个数与第一个位置的数交换;然后在剩下的数中选出最小的数与第二个数交换;依次类推,直至循环到只剩下两个数进行比较为止。
0.初始状态 3,1,5,7,2,4,9,6(共8个数)

1.n=8 个数中,最小数值为1,与第一个数交换:1,3,5,7,2,4,9,6

2.剩下 n-1=7 个数中,最小数值为2,与第二个数交换:1,2,5,7,3,4,9,6

3.剩下 n-2=6 个数中,最小数值为3,与第三个数交换:1,2,3,7,5,4,9,6

4.剩下 n-3=5 个数中,最小数值为4,与第四个数交换:1,2,3,4,5,7,9,6

5.剩下 n-4=4 个数中,最小数值为5,与第五个数交换:1,2,3,4,5,7,9,6

6.剩下 n-5=3 个数中,最小数值为6,与第五个数交换:1,2,3,4,5,6,9,7

7.剩下 n-6=2 个数中,最小数值为7,与第五个数交换:1,2,3,4,5,6,7,9

private static void selectSort(int[] array) {
        int n = array.length;
        for (int i = 0; i < n; i++) {
            int k = i;
            for (int j = i + 1; j < n; j++) {
                if (array[j] < array[i]) {
                    k = j;
                }
            }

            if (k != i) { // 说明需要换位了,后一位比前一位小
                int temp = array[i];
                array[i] = array[k];
                array[k] = temp;
            }

            print(array, n, i);
        }

        printResult(array, n);
    }

    private static void print(int[] a, int n, int i) {
        // TODO Auto-generated method stub
        System.out.print("第" + i + "次:");
        for (int j = 0; j < n; j++) {
            System.out.print(" " + a[j]);
        }
        System.out.println();
    }

    private static void printResult(int[] a, int n) {
        System.out.print("最终排序结果:");
        for (int j = 0; j < n; j++) {
            System.out.print(" " + a[j]);
        }
    }

堆排序:详情看外部链接
https://www.cnblogs.com/snowcan/p/6595813.html

另外还有归并排序、基数排序、外部排序,详情请查看其他资料。
END…

    原文作者:捉影T_T900
    原文地址: https://www.jianshu.com/p/e6ebad739069
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞