Java實現數據結構(一)——數組

1 數組基礎知識回顧

數組的定義

數組是由n的相同類型的元素構成的有序序列,每個數據元素稱爲一個數組元素,每個元素受n個線性元素的約束,每個元素在n個線性關係中的序號稱爲該元素的下標,並稱該數組爲n維數組。

數組的存儲

大多數編程語言都支持數組數據類型進行存儲,一個數組的所有元素在內存中佔有一段連續的存儲空間。

  • 以一維數組爲例:LOC(ai) = LOC(a0)+(i)*L;L是每個數組元素所佔的存儲單元;
  • 以二維數組來說,有按列存儲和按行存儲的方式。以按行存儲爲例,先行後列,先存儲行號較小的元素,行號相等先存儲列號較小的元素。設二維數組行下標與列下表的範圍分別爲分別爲[l1,h1],[l2,h2]則存儲結構關係式爲LOC(ai,j)=LOC(al1,l2)+[(i-l1)*(h2-l2+1)+(j-l2)]*L;如下圖爲按行優先存儲的存儲方式。
    在這裏插入圖片描述
  • 多維數組可以依照二維數組來推,原理相同

數組的分類

數組分爲靜態數組與動態數組;
靜態數組:主要特點是在在程序編譯時分配空間的數組
動態數組:在程序運行時是會自動擴容。

Java實現數組結構

動手實現靜態數組默認存放10個元素,實現CRUD

import java.util.Objects;
<E>爲抽象數據類型實現泛型
public class ArrayList<E> {
    private E [] data;//存放數組元素
    private int size;//獲取數組的長度
    //初始化數組
    public ArrayList (int capacity){
        data = (E[]) new Objects[capacity];//capacity爲數組容量
        size = 0;//初始化
    }
    //默認容量爲10;
    public ArrayList(){
        this(10);
    }
	//獲取數組的容量
    public int getCapacity(){
        return data.length;
    }
    //添加元素
    // 在index索引的位置插入一個新元素e
    public void add(int index, E e){
        if(size == data.length)
            throw new IllegalArgumentException("Add failed. Array is full.");
        if(index < 0 || index > size)
            throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size.");

        for(int i = size - 1; i >= index ; i --)
            data[i + 1] = data[i];

        data[index] = e;

        size ++;
    }

	//在最後面添加元素   
    public void addLast(E e){
        add(size,e);
    }
	//重寫Java的toString
    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        res.append(String.format("Size = %d,Capacity = %d\n",size,data.length));
        res.append("[");
        for(int i = 0 ;i<size;i++){
            res.append(data[i]);
            if(i!=size - 1){
                res.append(',');
            }

        }
        res.append(']');
        return res.toString();
    }
    //按值查找,返回下標
    public int find(E e){
        for (int i = 0; i < size; i++) {
            if(data[i]==e){
                return i;
            }
        }
        return -1;
    }
    //按照下標查找
    public E findElement(int index){
        if(index <0 || index > size){
            throw new IllegalArgumentException("index range is invaild , Please reconsider");
        }
        return data[index];
    }
    //修改元素
    public void setElement(int index,E element){
        data[index] = element;
    }
    //刪除元素
    public E remove(int index){
        if(index <0 || index > size){
            throw new IllegalArgumentException("remove range is invaild , Please reconsider");
        }
        E ret = data[index];
        for (int i = index+1; i < size; i++) {
            data[i-1]= data[i];
        }
        size--;
        return ret;
    }
}

測試

ArrayList arrayList = new ArrayList();

arrayList.addLast(10);
for (int i = 0; i <9 ; i++) {
    arrayList.addLast(i);
}
System.out.println(arrayList);
int find = arrayList.find(3);
int finde = (int) arrayList.get(3);
System.out.println(String.format("按值查找:%d,按下標查找:%d",find,finde));
arrayList.set(3,5);
System.out.println(arrayList);
arrayList.remove(1);
System.out.println(arrayList);

結果

Array: size = 10 , capacity = 10
[10, 0, 1, 2, 3, 4, 5, 6, 7, 8]
按值查找:4,按下標查找:2
Array: size = 10 , capacity = 10
[10, 0, 1, 5, 3, 4, 5, 6, 7, 8]
Array: size = 9 , capacity = 10
[10, 1, 5, 3, 4, 5, 6, 7, 8]

實現動態數組
思路:在添加元素和刪除元素當中增加一個resize方法,可以修改size,

  1. resize()將舊的數組元素添加到新數組當中
  2. 進行擴容;每次可以擴容兩倍int size裏面設置擴容大小
if(size == data.length)
    resize(2 * data.length);

resize方法

 private void resize(int resize) {
        E[] newData = (E[]) new Objects [resize];
        for (int i = 0; i < data.length; i++) {
            newData[i] = data[i];
        }
        data = newData;
    }

測試

//默認大小爲10,如果添加20個元素會自動擴容兩次
  for (int i = 0; i < 20; i++) {
        arrayList.lastAdd(i);
    }
    System.out.println(arrayList);
//Capacity變成40實現兩次擴容
Size = 29,Capacity = 40
[10,1,2,3,4,5,6,7,8,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]//進行兩次擴容

練習

1.用動態數組解決數據存放的問題
編寫一段代碼,要求輸入一個整數N,用動態數組A來存放2~N之間所有5或7的倍數,輸出該數組。

示例:

輸入:
N = 100 

輸出:
5 7 10 14 15 20 21 25 28 30 35 40 42 45 49 50 55 56 60 63 65 70 75 77 80 84 85 90 91 95 98 100

思路:直接遍歷從2~n的整數,取出其中能被5和7整除的整數

public void fiveOrSevenMultiple(int n){
    for (int i = 2; i < n+1; i++) {
        if(i%5 == 0 || i%7 == 0){
            lastAdd(i);
        }
    }
}
        arrayList.fiveOrSevenMultiple(100);
        System.out.println(arrayList);

結果:
Size = 32,Capacity = 40
[5,7,10,14,15,20,21,25,28,30,35,40,42,45,49,50,55,56,60,63,65,70,75,77,80,84,85,90,91,95,98,100]

2.託普利斯矩陣問題

託普利斯矩陣問題就是沿着矩陣的反對角線對稱的矩陣,用Java判斷一個矩陣是否爲託普利斯矩陣。
實現思路,1.先遍歷矩陣行列的長度,2.判斷矩陣的[i][j]與[i+1][j+1]是否相等

public boolean topliciMatix(int [] [] matrix){
        for (int i = 0; i < matrix.length-1; i++) {
            for (int j =0;j<matrix.length[0];j++){
                if(matrix[i][j] == matrix[i+1][j+1]){
                    return true;
                }
            }
        }
        return false;
    }
int [][]commonmartix={{1,2,3},{2,3,4},{5,6,7}};
    System.out.println(arrayList.topliciMatix(commonmartix));
int [][]toplicimartix = {{1,2,3},{5,1,2},{9,5,1}};
    System.out.println(arrayList.topliciMatix(toplicimartix));

//結果
false
true

3.三數之和
給定一個包含n個整數的數組nums,判斷nums中是否存在三個元素a,b,c,使得a+b+c =0?找出所有滿足條件且不重複的三元組。
例如, 給定數組 nums = [-1, 0, 1, 2, -1, -4]
結果滿足要求的三元組集合爲:

[
  [-1, 0, 1],
  [-1, -1, 2]
]

算法如下:

public static List<List<Integer>> threeSum(int[] nums) {
        if (nums.length < 3) return Collections.emptyList();
        List<List<Integer>> res = new ArrayList<>();
        int minValue = Integer.MAX_VALUE;//找到數組中最小值
        int maxValue = Integer.MIN_VALUE;//找到最大值
        int negSize = 0, posSize = 0;//negSize爲數組中負數的個數posSize爲數組中正數的個數
        int zeroSize = 0;//數組中爲0的個數
        for (int v : nums) {
            if (v < minValue) minValue = v;
            if (v > maxValue) maxValue = v;
            if (v > 0) posSize++;
            else if (v < 0) negSize++;
            else zeroSize++;
        }
        if (zeroSize >= 3) res.add(Arrays.asList(0, 0, 0));//輸出 三個 0 的情況
        if (negSize == 0 || posSize == 0) return res;
        //此時minValue一定爲負數,maxValue一定爲正數
        //如果maxValue > -2*minValue,那麼大於 -2*minValue的元素肯定不會是答案,可以排除掉,所以更新maxValue
        if (minValue * 2 + maxValue > 0) maxValue = -minValue * 2;
            //同理更新minValue
        else if (maxValue * 2 + minValue < 0) minValue = -maxValue * 2;
        //自己構建一個hashmap,值表示元素重複次數,注意java數組默認值爲 0
        int[] map = new int[maxValue - minValue + 1];
        int[] negs = new int[negSize];
        int[] poses = new int[posSize];
        negSize = 0;
        posSize = 0;
        for (int v : nums) {
            if (v >= minValue && v <= maxValue) {//只保留在[minValue,maxValue]區間內的元素
                if (map[v - minValue]++ == 0) {//計數加去重
                    if (v > 0) poses[posSize++] = v;//poses數組存所有去重後的正值
                    else if (v < 0) negs[negSize++] = v;//negs數組存所有去重後的負值
                }
            }
        }
        //正負數兩數組排序
        Arrays.sort(poses, 0, posSize);
        Arrays.sort(negs, 0, negSize);
        int basej = 0;
        for (int i = negSize - 1; i >= 0; i--) {//負數數組從後往前遍歷
            int nv = negs[i];//nv爲當前負數值
            //minp = -nv/2,相當於三元組中另外兩元素的平均值,即爲另兩個元素中較小值的上界,較大值的下界
            int minp = (-nv) >>> 1;
            //定位到正數數組中值剛好小於平均值的元素
            while (basej < posSize && poses[basej] < minp) basej++;
            for (int j = basej; j < posSize; j++) {//正數數組從大於等於平均值的元素開始遍歷
                int pv = poses[j];//pv 爲當前正數值
                int cv = 0 - nv - pv;//cv 爲要尋找的另一個值
                //目標值 cv 應該在 [nv,pv] 當中
                //如果不限制cv<=pv,當nv爲奇數時,有可能會重複輸出
                if (cv >= nv && cv <= pv) {
                    if (cv == nv) {
                        if (map[nv - minValue] > 1)//兩個相同的負數和一個正數的情況
                            res.add(Arrays.asList(nv, nv, pv));
                    } else if (cv == pv) {
                        if (map[pv - minValue] > 1)//兩個相同的正數和一個負數的情況
                            res.add(Arrays.asList(nv, pv, pv));
                    } else {
                        if (map[cv - minValue] > 0)//三個不同元素的情況
                            res.add(Arrays.asList(nv, cv, pv));
                    }
                } else if (cv < nv) break;//如果 cv 小於 nv了,表明這種情況會在後面尋找,爲避免重複輸出,跳出循環
            }
        }
        return res;

測試

		int [] nums = {-1, 0, 1, 2, -1, -4};
        System.out.println(threeSum(nums));
		結果
		[[-1, 0, 1], [-1, -1, 2]]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章