一、数组

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

一、操作

01234

1. 插入

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

2. 查找

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

使用二分查找,最多只使用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. 快速排序

思想
图解
实现
效率
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值