1. 程式人生 > 其它 >資料結構之陣列與經典面試題

資料結構之陣列與經典面試題

技術標籤:資料結構與演算法java

1、定義

所謂陣列,是有序的元素序列。
若將有限個型別相同的變數的集合命名,那麼這個名稱為陣列名。組成陣列的各個變數稱為陣列的分量,也稱為陣列的元素,有時也稱為下標變數。用於區分陣列的各個元素的數字編號稱為下標。陣列是在程式設計中,為了處理方便,
把具有相同型別的若干元素按無序的形式組織起來的一種形式。這些無序排列的同類資料元素的集合稱為陣列。int 的陣列你就不能存float
也不能存double。陣列是用於儲存多個相同型別資料的集合。通常用Array表示,也稱之為線性表,畫圖演示
在這裡插入圖片描述

2、特點

(1)陣列是相同資料型別的元素的集合。 (2)陣列中的各元素的儲存是有先後順序的,它們在記憶體中按照這個先後順序連續存放在一起。記憶體地址

(3)陣列元素用整個陣列的名字和它自己在陣列中的順序位置來表示。例如,a[0]表示名字為a的陣列中的第一個元素,a[1]代表陣列a的第二個元素,以此類推,

(4)隨機訪問(查詢)
陣列是連續的記憶體空間和相同型別的資料。正是因為這兩個限制,它才有了一個非常重要的特性:隨機訪問。但有利就有弊,這兩個限制也讓陣列的很多操作變得非常低效,比如要想在陣列中刪除、插入一個數據,為了保證連續性,就需要做大量的資料搬移工作。
(5)陣列的缺點:插入和刪除 實現程式碼:
設陣列的長度為n,現在,如果我們需要將一個數據插入到陣列中的第k個位置。刪除第N個位置的資料.那麼需要移動刪除和插入後面的陣列元素
(6)使用陣列一定要注意訪問越界問題;所以一定要多加判斷,尤其是在開始和結束。測試的時候也一樣注意頭和尾。

3.表現形式

(1)一維陣列
int a[],String a[] (2)多維陣列
int a[][],int a[][][]。 int a[m][n]:記憶體空間是多少? m*n a[0][10]:
連結串列解決,a[0]:->10>2 a[1]->15

4、ArrayList和陣列

本質是一樣的,都是陣列。ArrayList是JDK封裝了。不需要管擴容等操作;陣列的話就要你全部操作 兩者選擇:
不知道資料大小的肯定選ArrayList。
如果你知道資料的大小而且你又非常關注效能那就用陣列。

5、二維陣列的記憶體地址是怎麼樣的?寫出定址公式?

一維:a[] = new int[10]; ==> loc =

init_loc(初始記憶體地址)+index(陣列的下標)size(資料的長度) 二維=>轉化一維 1 2 3 4 5 6 =>
1 2 3 4 5 6 => 4的下標在二維裡面是 (1 ,0) =>在一維裡面是第3個。=> i
n(一維的長度)+j(在列
)=>13+0=3 a[i][j]: (i<n,j<m) loc=init_loc+(in+j)*size

6、總結:

陣列是一個最基礎最簡單的資料結構,必須要完全搞懂。它是儲存相同型別的一組資料,最大的兩個特點就是下標和隨機訪問。缺點就是插入和刪除是很慢的,時間複雜度為O(n)。

7、經典面試

7.1 、例子:手寫ArrayList
/**
 * @author zhz
 * @date 2020/11/11
 **/
public interface MyList {
    void add(int index, Object element);
    int size();
    void add(Object element);
    void remove(int index);
    Object get(int index);
    String toString();
    void ensureCapacityInternal();
}


import com.hr.tuling.array.MyList;
import java.util.Arrays;
/**
 * @author zhz
 * @date 2020/11/11
 **/
public class MyArrayList implements MyList {

    /**
     * 定義一個數組,用於儲存集合中的資料
     */
    private Object[] elementData;

    /**
     * 定義一個變數,用於儲存陣列中實際存放元素的個數
     */
    private int size;

    /**
     * 獲取陣列中實際存放元素的個數
     *
     * @return
     */
    public int size() {
        return this.size;
    }

    /**
     * 無參構造方法(預設設定elementData陣列的空間長度為10)
     */
    public MyArrayList() {
        this.elementData = new Object[10];
    }

    /**
     * 有參構造方法(指定設定elementData陣列的空間長度)
     *
     * @param cap 需要設定elementData的空間長度
     */
    public MyArrayList(int cap) {
        //1、判斷cap是否合法
        if (cap < 0) {
            throw new RuntimeException("引數不合法,cap:" + cap);
        }
        //2、例項化elementData陣列
        this.elementData = new Object[cap];
    }

    /**
     * 新增元素
     *
     * @param element 需要新增的元素
     */
    @Override
    public void add(Object element) {
        //1、判斷陣列是否需要擴容
        ensureCapacityInternal();
        //2、把element新增進入陣列中
        elementData[size] = element;
        //3、更新size的值
        size++;
    }

    /**
     * 根據索引獲取元素值
     *
     * @param index 索引值
     * @return 陣列中index索引對應的元素值
     */
    @Override
    public Object get(int index) {
        //1、判斷索引是否合法,合法的取值範圍:【0,size-1】
        rangeCheck(index);
        //2、根據索引獲取對應的元素值
        return elementData[index];
    }

    /**
     * 根據索引刪除元素
     *
     * @param index 索引值
     */
    @Override
    public void remove(int index) {
        //1、判斷索引是否合法,合法的取值範圍:【0,size-1】
        rangeCheck(index);
        //2、把刪除索引之後的元素往前移動一位
        //2.1先獲得刪除索引及其之後的所有索引值
        for (int i = index; i < size; i++) {
            //2.2把後一個元素往前移動一位
            elementData[i] = elementData[i + 1];
        }
        //3、把最後一個實際新增的元素設定為預設值
        elementData[size - 1] = null;
    }

    /**
     * 根據索引插入元素
     *
     * @param index   插入元素的索引位置
     * @param element 需要插入的元素
     */
    @Override
    public void add(int index, Object element) {
        //1、判斷索引是否合法,合法的取值範圍:【0,size】-->插入的元素可以在實際新增元素的最末尾
        if (index < 0 || index > size) {
            throw new ArrayIndexOutOfBoundsException("索引越界異常,index:" + index);
        }
        // 2.判斷陣列是否需要擴容
        ensureCapacityInternal();
        // 3.插入索引及其之後的元素往後挪動一位(從後往前挪動)
        // 3.1獲得插入索引及其之後的所有索引值
        for (int i = size - 1; i >= index; i--) {
            // 3.2把前一個元素往後挪動一位
            elementData[i + 1] = elementData[i];
        }
        // 4.在插入索引位置實現賦值操作
        elementData[index] = element;
        // 5.更新size的值
        size++;
    }

    /**
     * 檢查索引是否合法(get和remove)
     *
     * @param index
     */
    private void rangeCheck(int index) {
        //1、判斷索引是否合法,合法的取值範圍:【0,size-1】
        if (index < 0 || index >= size) {
            throw new ArrayIndexOutOfBoundsException("索引越界異常,index:" + index);
        }
    }

    /**
     * 判斷陣列是否需要執行擴容操作
     */
    public void ensureCapacityInternal() {
        //1.1、當陣列的空間長度等於陣列實際存放元素的個數時,這時就需擴容擴容操作
        if (elementData.length == size) {
            //1.2、建立一個比原陣列空間長度更大的新陣列
            Object[] newArr = new Object[elementData.length * 2 + 1];
            //1.3、把原陣列中的元素拷貝進入新陣列中
            for (int i = 0; i < size; i++) {
                newArr[i] = elementData[i];
            }
            //1.4、讓原陣列儲存新陣列的地址值
            elementData = newArr;
        }
    }

    @Override
    public String toString() {
        return "ArrayList{" +
                "elementData=" + Arrays.toString(elementData) +
                '}';
    }

    public static void main(String[] args) {
        MyList myList = new MyArrayList(7);
        myList.add(2);
        myList.add(3);
        myList.add(2);
        myList.add(3);
        System.out.println(myList.get(2));
    }
}

7.2、陣列的反轉

import java.util.Arrays;

/**
 * 陣列的反轉
 * 例如:陣列{11, 22, 33, 44, 55, 66}反轉後為{66, 55, 44, 33, 22, 11}
 * @author zhz
 * @date 2020/10/03
 **/
public class 陣列的反轉 {
    /**
     *  方法一:
     *      1)新建陣列,用於儲存反轉後的結果
     *      2)把需要反轉陣列中的元素倒序存入新陣列中
     */
    public static int[] reverseOrderArray(int[] arr){
        // 1.定義一個新陣列,用於儲存反轉之後的結果
        int[] temp=new int[arr.length];
        // 2.把arr陣列中的所有元素倒序的存入temp陣列中
        // 2.1通過迴圈獲得arr陣列中的每一個元素
        for (int i = arr.length-1; i >= 0; i--) {
            // 2.2把arr陣列中的元素倒序存入temp陣列中
            temp[arr.length-1-i]=arr[i];
        }
        // 3.把反轉之後的陣列返回
        return temp;
    }
    /**
     *  方法二:把需要反轉陣列的元素首尾交換即可
     */
    public static void reverseOrderArray1(int[] arr){
        // 1.通過迴圈,獲得陣列前半部分的元素
        for (int i = 0; i <arr.length/2; i++) {
            // 2.把arr[i]和arr[arr.length - 1 - i]做交換
            int temp=arr[i];
            arr[i]=arr[arr.length-1-i];
            arr[arr.length-1-i]=temp;
        }
    }

    public static void main(String[] args) {
        int[] arr={11,22,33,44,55,66};
        //System.out.println(Arrays.toString(陣列的反轉.reverseOrderArray(arr)));
        陣列的反轉.reverseOrderArray1(arr);
        System.out.println(Arrays.toString(arr));
    }
}

7.3、 找陣列中重複的元素

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author zhz
 * @date 2020/10/03
 **/
public class 找陣列中重複的元素 {
    /**
     * 問題:在一個長度為n的數組裡的所有數字都在0到n-1的範圍內。 陣列中某些數字是重複的,
     * 但不知道有幾個數字是重複的。也不知道每個數字重複幾次。請找出陣列中任意一個重複的數字。
     * 例如,如果輸入長度為7的陣列{2,3,1,0,2,5,3},那麼對應的輸出是第一個重複的數字2
     *
     * 解決:第一種,用map做計數器,當大於1時,則返回true,否則false
     */
    public static boolean duplicate(int numbers[],int length,int [] duplication) {
        Map<Integer, Integer> map = new HashMap<>();
        int count=1;
        // 1.判斷arr為null或arr.length等於0的情況
        if(numbers == null || length == 0) {
            return false;
        }
        for (int i = 0; i < length; i++) {
            // 3.判斷陣列元素是否合法
            if(numbers[i] < 0) {
                return false;
            }
            if (!map.containsKey(numbers[i])){
                map.put(numbers[i],count);
            }else{
                map.put(numbers[i],map.get(numbers[i])+1);
            }
        }
        for (Map.Entry<Integer,Integer> entry : map.entrySet()){
            if (entry.getValue()>1){
                duplication[0]=entry.getKey();
                return true;
            }
        }
        return false;
    }

    /**
     * 題目:在一個長度為 n 的陣列 nums 裡的所有數字都在 0~n-1 的範圍內。數
     * 組中某些數字是重複的,但不知道有幾個數字重複了,也不知道每個數字重複了幾次。
     * 請找出陣列中任意一個重複的數字。
     *
     * 解決:用set去判重
     */
    public int findRepeatNumber(int[] nums) {
        Set<Integer> set=new HashSet<>();;
        int res=0;
        for (int num : nums) {
            if (!set.contains(num)) {
                set.add(num);
            }else {
                res=num;
            }
        }
        return res;
    }

    public static void main(String[] args) {
        找陣列中重複的元素.duplicate(new int[]{
                0, 3, 4, 1, 4, 8
        },6,new int[]{1});
    }
}

7.4、使奇數位於偶數前面

import java.util.Arrays;

/**
 * 使奇數位於偶數前面
 * 輸入一個整型陣列,實現一個方法來調整該陣列中的元素的順序,
 * 使得所有奇數位於陣列的前半部分,所有偶數位於陣列的後半部分。
 * @date 2020/10/03
 **/
public class 使奇數位於偶數前面 {

    /**
     * 使奇數位於偶數前面
     * @param array 需要調整奇偶數位置的陣列
     */
    public static void reOrderArray(int[] array) {
        // 1.處理arr為null的情況
        if (array == null) {
            throw new NullPointerException("空指標異常,array:" + array);
        }
        // 2.定義兩個下標,min的初始值為0,max的初始值為arr.length - 1
        int min = 0;
        int max = array.length - 1;
        // 3.定義一個迴圈,用於調整陣列中奇偶數的位置
        while (min < max) {// 如果min小於max,則一直調整陣列中元素的位置
            // 4.讓min從前往後找,如果arr[min]的值為偶數,則停止查詢
            while (min < max && array[min] % 2 != 0) {
                min++;
            }
            // 5.讓max從後往前找,如果arr[max]的值為奇數,則停止查詢
            while (min < max && array[max] % 2 == 0) {
                max--;
            }
            // 6.如果min的值不等於max,則交換arr[min]和arr[max]的值
            if (min != max) {
                int temp = array[min];
                array[min] = array[max];
                array[max] = temp;
            }
        }
    }

    /**
     *新開一個數組空間
     * @param nums
     * @return
     */
    public int[] exchange(int[] nums) {
        if (nums==null||nums.length==0){
            return nums;
        }
        int left=0;
        int right=nums.length-1;
        int[] res=new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            if ((nums[i]&1)==0){//偶數
                res[right--]=nums[i];
            }else{
                res[left++]=nums[i];
            }
        }
        return res;
    }

    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        使奇數位於偶數前面.reOrderArray(array);
        System.out.println(Arrays.toString(array));
    }
}