一、数组

来源:互联网 发布:windows经典桌面壁纸 编辑:程序博客网 时间:2024/06/02 05:29

数据结构是数据存储的抽象结构,而不是实际结构。例如以数组为抽象数据结构,在实际磁盘中存储的数据,并非是顺序存储的。数组有下标,如果知道一个数的下标,可以通过a[index]直接取出数据,因为它有一个指针指向磁盘的某一个位置。

一、操作

0 1 2 3 4

1. 插入

数组的插入总是将新的数据项放入下一个有空的地方。a[index]。所以无论数组的数据项有多大,插入的时间复杂度都是O(1)。

2. 查找

  1. 线程查找 与N成正比
    查找有多种查找方式,如果数组是一个无序数组,通常查找一个值,都是线性查找,即从头开始遍历数组,直到找到这个值,查找过程结束。它的平均时间为:n/2。数据越大,查询耗时越大。
  2. 二分查找 与lg(N)成正比
    例如1-100的数字中,查找33这个数,最少用几次
步数 所判断的数 结果 可能值的范围 0 1-100 1 50 太大 1-49 2 25 太小 26-49 3 37 太大 26-36 4 31 太小 32-37 5 34 太大 32-33 6 32 太小 33-33 7 33 正确

使用二分查找,最多只使用7次即可完成查询。当前,前提是数组是已经排好序的。与线性查找相比,速度快了很多。
因为每次都是折半,所以它的最差查找时间为:log2n

3. 删除

删除某项数据后,当前数据末尾的数据项都要向前移动一个位置来填补它。所以,删除的时间复杂度是O(N)

二、数组的优缺点

优点

数组的优点就是插入速度快,逻辑简单易于理解。

缺点

  • 如果是无序数组,查找时间慢
  • 数组一旦被创建后,大小尺寸都是固定的,不方便扩展。

三、二分查找

    /**     * 二分查找     *     * @param ints 被查找数组     * @param searchKey 被查找值     * @return 返回数组下标,如果没有,则抛异常NotFondException     */public int find(int[] ints, int searchKey) throws Exception {        int start = 0;        int end = ints.length - 1;        int executionCount = 0;        while (start < end) {            executionCount++;            int index = (start + end) / 2;            if (ints[index] < searchKey) {                start = index + 1;            } else if (ints[index] > searchKey) {                end = index - 1;            } else {                System.out.println("共查找" + executionCount + "次");                return index;            }        }        throw new Exception("not found " + searchKey);    }

四、数组的排序

  • 冒泡排序
  • 选择排序
  • 插入排序
  • 归并排序
  • 希尔排序
  • 快速排序

1. 冒泡排序

思想

从左到右依次比较相邻的两个数,每次比较将大的数放在后边,最终结果是,最大的数将在末位,这表示第一回排序结束。
去除最后一个数,重复上面的步骤,这一回又得到最大的一个数在最后。
依次类推,循环n次后,将得到最终的结果。

还有一种思想,即始终都拿需要排序的子数组的第一个去与后面的进行比较,把最小的放在第一位,这样比较的结果是前面先排好序。与上面思维相反。一般写代码都是这样的。

图例

这里写图片描述

Java代码

   public static void sort(int[] array) {        if (array.length > 1) {            for (int i = 0; i < array.length; i++) {                for (int j = i; j < array.length; j++) {                    if (array[i] > array[j]) {                        int temp = array[i];                        array[i] = array[j];                        array[j] = temp;                    }                }            }        }    }    public static void sort2(int[] array) {        if (array.length > 1) {            for (int i = array.length - 1; i >= 0; i--) {                for (int j = 0; j < i; j++) {                    if (array[i] < array[j]) {                        int temp = array[i];                        array[i] = array[j];                        array[j] = temp;                    }                }            }        }    }

效率

冒泡排序的效率是非常低的。时间复杂度一般O(1)表示最好,O(lgn)次之。O(n)还行,O(n2)最差。从上面结果可以看出,冒泡排序比较次数为:(n-1)+(n-2)+…+2+1=n(n1)2,其时间复杂度为O(n2)。所以效率是最差的。

2. 选择排序

思想

选择排序的思想是在冒泡的基础上进行了一次改进。冒泡排序每比较一次差不多都需要交换位置,而选择排序则一趟比较,只需要交换一次。它的思维是将最小的进行标记,然后和待排序数组的第一个值进行交换。

图解

这里写图片描述

Java代码

    public void sort(int[] array) {        for (int i = 0; i < array.length; i++) {            int index = i;            int temp = array[index];            for (int j = i; j < array.length; j++) {                if (array[index] > array[j]) {                    index = j;                }            }            array[i] = array[index];            array[index] = temp;        }    }

效率

选择排序和冒泡相比,虽然时间复杂度并没有变化,只是它的复制交换次数变少了。如果是一个对象排序,复制一个对象耗时如果比较大的话,选择排序将是更好的选择。

3. 插入排序

思想

插入排序的思想是,一个数组,前面有k个值是已经排好序的,然后从k+1开始,依次从后向前比较,插入到已排序的数组的合适位置。

图解

这里写图片描述

实现

    public static void sort(int[] array) {        for (int i = 1; i < array.length; i++) {            int index = i - 1;            while (index >= 0 && array[index] >= array[index + 1]) {                int temp = array[index];                array[index] = array[index + 1];                array[index + 1] = temp;                index--;            }        }    }

效率

插入排序的最差情况是,每次插入时,都将插入到第一位,比较次数依次为:1+2+……+(n-1)。和冒泡排序相等。这是插入排序的最差情况。最好情况是0,即已经是有序了。所以,插入排序的平均值是最差的一半。也就是n(n1)4
综上可以看出,插入排序速度理论上是冒泡排序的一倍。以上三种方式插入排序是简单排序里面最快的一种,而且也易于理解。

4. 归并排序

思想

面试的时候,面试官问了我一个问题,两个有序的数组,合并后继续保持有序,如何实现。当时想都没想,回答合并再排序。面试官继续问,还有没有更好的方式。在这之前并没有归并的概念(也许大学是学过,不过我确实不记得归并的思想),于是我简单想了一下,一次合并的时候,就让它有序。
例如:int[] a = {1,3,5,7,9};int[] b = {0,2,4,6,8};合并到c数组时:
1与0比较,0小,0先放入c,接着b数组指针向后移动一位,继续比较,1比2小,1放入c中,a数组指针向后移动一位。依次类推,就能完成。
归并排序的思想是根据此为基础,将一个数组拆分成一半,再拆分……依次合并。最终得到一个有序数组。

图解

实现

效率

5. 希尔排序

思想

图解

实现

效率

6. 快速排序

思想

图解

实现

效率

原创粉丝点击