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

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

一、基本概念

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...

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容

  • 一些概念 数据结构就是研究数据的逻辑结构和物理结构以及它们之间相互关系,并对这种结构定义相应的运算,而且确保经过这...
    Winterfell_Z阅读 5,646评论 0 13
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,159评论 0 52
  • 作家巴金曾说过,我去开始写作,不是因为我有写作方面的才华,而是因为我有感情。我写作的缘由呢? 我不会说什么“我只是...
    初夏里的乌龟吖阅读 709评论 0 1
  • 今天,上午三节课连着上完。 然后去滨州坐车,一下午,从滨州去泰安。 一天的时间在路上。 下午到泰山帝苑酒店,酒店真...
    五碗呀阅读 149评论 0 0
  • 丑女“变形”记 吴老师弟子 刘文文 说实话,从...
    吴老师教语文阅读 252评论 2 2