1.7Java數組的常見操作和實體的屬性

對數組操作最基本的動作就是 : 存,取
核心思想:對角標的操作

int[] arr = {89,35,56,75};
1.遍歷:
數組的長度:arr.length
數組的最大角標:數組的長度 - 1

for(int i=0; i < arr.length; i++)   //對角標正向的操作
{
    System.out.println("arr[" + i + "] = " + arr[i]);   
}
for(int i = arr.length-1; i >= 0; i--)   //對角標反向的操作
{
    System.out.println("arr[" + i + "] = " + arr[i]);   
}

2.最值:
思路:定義變量記錄較大的值或者 較大值的角標,然後遍歷數組比較。

static int max(int[] arr)
    {
        int maxElement = arr[0];       //首個元素作爲初始化值
        for(int i=1; i < arr.length; i++) 
        {
            if(arr[i] > maxElement)
                maxElement = arr[i];
        }
        return maxElement;    
    }

static int max(int[] arr)
    {
        int maxIndex = 0;              //角標作爲初始化值
        for(int i=1; i < arr.length; i++) 
        {
            if(arr[i] > arr[maxIndex])
                 maxIndex = i;
        }
        return arr[maxIndex];     
    }

(選擇排序和冒泡排序 面試 用,開發的時候直接用Arrays.sort(arr); ,在類java.util.*中,默認從小到大排序。其他語言不一定有,還是要自己實現 )

3.選擇排序:從左到右依次選出後面的最小或者最大的值。是從前面開始完成。
分析

static void selectSort(int[] arr)
{
    for(int i = 0; i < arr.length-1; i++)   //-1是因爲最後一次循環多餘
    {
               for(int j = i+1; j< arr.length; j++)   //=i+1 是因爲選擇排序不再和前面的元素比較了,前面的元素已經排好了。
        {
                if(arr[i] > arr[j])
            {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j]  = temp;
            }
        }
    }
    return arr;
}

4.冒泡排序:兩兩相鄰比較,把最大或者最小的冒泡到最後。是從最後開始完成。

static void bubbleSort(int[] arr)
{
    for(int i = 0; i < arr.length-1; i++)      //-1是因爲最後一次循環多餘
    {
        for(int j = 0; j < arr.length-1-i; j++)      //-1是因爲後面的j+1 也要小於 arr.length,
                                                               //-i是因爲每往後循環一次,後面排好的元素就多一個,比較的次數也相應減少一次
        {
                if(arr[j] < arr[j+1])
            {
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1]  = temp;
            }
        }
    }
}
//簡化版:
static void bubbleSort(int[] arr)
{
        for(int i = arr.length-1; i > 0 ; i--)   
    {
            for(int j = 0; j < i; j++)        //利用i的變化簡化內循環   
        {
                if(arr[j] < arr[j+1])
            {
                swap(arr, j, j+1);       //代碼複用
                /*int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1]  = temp;*/
            }
        }
    }
}
//排序位置置換代碼提取
static void swap(int[] arr, int a, int b)      //必須帶入數組的地址
{
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
}

5.排序性能問題:
1.選擇排序:幾次比較換位才確定一個最值,效率低。
解決思路:比較但是不直接換位,通過變量記錄最值的角標和對應的值,最後把變量的值一次賦值給前面的元素。此時只進行了一次換位,中間過程原實體的數據是不變的。

寫的過程中犯的錯:
沒有記錄比較過程中的最值的中間值,導致每一次都是和外循環的第一個元素比較,
互換的只是最後一個比首元素小的元素,不是最小的元素。
代碼:

static void selectSort(int[] arr)
{
    for(int i = 0; i < arr.length-1; i++)    
    {      
            int index = i;   //記錄最值的角標  
            int num = arr[i];  //記錄最值,初始化爲第一個參與比較的元素,參與內循環
        for(int j = i+1; j< arr.length; j++)   
        {
            if(num > arr[j])        //通過最值變量依次參與比較,找到更小的值
                 index = j;     //更新最值角標,找到最終的最值角標,參與最後的換位
                 num = arr[j];  //更新最值,參與下次循環比較
        }
        if(i != index)
        swap(arr,i,index);    //將找到的最值與原實體最值的位置位置。選擇排序,是從最前開始排序。
    }
}

2.冒泡排序:同樣的道理,
優化:通過變量記錄最值的角標和對應的值,最後把變量的值一次賦值給後面的元素。減少換位次數。
代碼:

static void bubbleSort(int[] arr)
{
        for(int i = 0; i < arr.length-1; i++)    
    {
            int index = arr.length -1-i;             //記錄最值的角標  
            int num = arr[0];                               //記錄最值,初始化爲第一個參與比較的元素,參與內循環
            for(int j = 0; j < arr.length-1-i; j++)                                                                                       
        {               
                if(num < arr[j+1])
            {
                index = j+1;
                num = arr[j+1];
            }
        }
        if(index != arr.length -i)       
        swap(arr,arr.length-1-i,index);    //將找到的最值與原實體最值的位置位置。冒泡是從最後開始排序。
    }
}

//優化簡化版:
static void bubbleSort(int[] arr)
{
        for(int i = arr.length-1; i > 0 ; i--)   
    {
            int index = i;
            int num = arr[0];
            for(int j = 0; j < i; j++)        //利用i的變化簡化內循環   
        {
                if(num < arr[j+1])
            {
                index = j+1;
                num = arr[j+1];
            }
        }
        if(index != i)
            swap(arr,i,index);
    }
}

(二分查找代碼 面試 用,Java開發的時候直接用Arrays.binarySearch(arr,57); ,在類java.util.*中。其他語言不一定有,還是要自己實現。 )
關於Arrays.binarySearch() :
1.元素存在時,返回的是元素的角標,即mid。
2.當查找的元素不存在時,返回的是 - 插入點 - 1( - min -1)。返回負數是因爲區分元素不存在時插入點,-1是防止元素不存在而插入點爲0時,這時-1變成負數用以說明元素不存在。
3.如果折半查找的元素在數組裏有重複的,則返回哪個元素的角標視所處位置而定。

6.折半查找:前提數組是有序的。最終確定中間元素等於目標元素的角標。

折半查找

/*static int halfSearch(int[] arr, int x)
    {
        int min = 0;
        int max = arr.length -1;
        int mid = (min + max) / 2;
        while(x != arr[mid])
        {
            if(min > max)            //元素不存在
                return -1;
            else if(x > arr[mid])
                min = mid + 1;
            else
                max = mid - 1;
            mid = (min + max) / 2;
        }
        return mid;
    }
}*/
//另一種表示:簡化點
static int halfSearch(int[] arr, int x)
    {
        int min, max, mid;
        int min = 0;
        int max = arr.length -1;
        while(min < max)       //元素存在
        {
            mid = (min + max) >>1;    //右移
            if(x == arr[mid])
                return mid;
            else if(x > arr[mid])
                min = mid + 1;
            else
                max = mid - 1;
        }
        return -1;    //Arrays.binarySearch() 返回的是 - 插入點 - 1( -min-1)

    }
}

面試題:
給定一個有序的數組,如果往該數組中存儲一個元素,並保證這個數組還是有序的,那麼這個元素的存儲的角標如何獲取。

static int getIndex(int[] arr, int x)
    {
        int min, max, mid;
        int min = 0;
        int max = arr.length -1;
        while(min < max)       //元素存在
        {
            mid = (min + max) >>1;    //右移
            if(x == arr[mid])
                return mid;       //返回元素角標
            else if(x > arr[mid])
                min = mid + 1;
            else
                max = mid - 1;
        }
        return min;    //元素不存在時,返回插入點。Arrays.binarySearch() 返回的是 - 插入點 - 1( -min-1)
    }
}

7.應用:進制轉換:

Demo:

//位轉換,8次。如何根據不同的數減少循環次數,是個問題。

class  toHexDemo
{
    public static void main(String[] args) 
    {
        toHex(0);
        toBin(-2147483648);
    }

    static void toHex(int num)
    {      //開發思想:數據一多,就存儲起來,在進行操作。

            int[] hex = new int[8];       //定義一個臨時數組,按一定順序存放十六進制的位值,大於10的最後輸出的時候再進行格式輸出
            int x = 7;                                  //找出十六進制開始第一個不爲0的角標,再進行遍歷輸出。(也就是消去了開始的無效0)
                                                                    //默認爲7,是爲了避免當輸入的十進制爲0的時候,沒有不爲0 的數,則直接輸出最後一位0
                                                                    //即0的十六進制數爲0

            for(int i = 0; i < 8; i++)     //位轉換,8次。如何根據不同的數減少循環次數,是個問題。
            {
                int n = num>>>(4*i)&15;   //移位用>>>比較好,負數不用補有效位1
                hex[7-i] = n;                 //得到的十六進制數字倒序存入數組
            }

            for(int i = 0; i < 8; i++)     //找到x的具體值
            {
                    if(hex[i] != 0)
                    {
                        x = i;
                        break;
                    }
            }

            System.out.println(num + "\t對應的十六進制表現形式是:");

            for(int i = x; i < 8; i++)     //輸出對應的完整的有效十六進制數。
            {

                    if(hex[i] < 10)
                        System.out.print(hex[i]);
                    else
                        System.out.print((char)(hex[i] - 10 + 'A'));// 也可以(char)(n+55),把數值轉換成十六進制對應的字母。

                    //或者使用數組查表法
                    //即char[] chs = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
                    //System.out.print(chs[hex[i]]);

                    /* 解釋:
        0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
        0,1,2,3,4,5,6,7,8,9,A,      B,     C,     D,     E,     F

        什麼時候使用數組呢?
        如果數據出現了對應關係,而且對應關係的一方是有序的數字編號。並作爲角標使用,
        這時就必須想到用數組。

        就可以將這些數據存儲到數組中。
        根據運算的結果作爲角標直接去查數組中對應的元素即可。

        (當對應關係的一方不是有序的數字編號時,使用的是Map集合。)
*/
            }
            System.out.println();
    }



//同理轉換二進制:
    static void toBin(int num)
    {
            int[] bin = new int[32];
            int x = 31;

            for(int i = 0; i < 32; i++)
            {
                    int n = num>>>(1*i)&1;
                    bin[31- i] = n;
            }

            for(int i =0; i < 32; i++)
            {
                    if(bin[i] != 0)
                    {
                            x = i;
                            break;
                    }
            }

            System.out.println(num + "\t對應的二進制表現形式是:");

            for(int i=x; i<32; i++)
            {
                    System.out.print(bin[i]);
            }
            System.out.println();
    }


}

最終程序源代碼:

class  HexConverter
{
    public static void main(String[] args) 
    {
        //輸入優化
        int hexFront =16;
        int hexAfter = 10;
        String numFront = "8FFFFFFF";

        System.out.println(hexFront + "進制\t\t轉換\t\t" + hexAfter + "進制\n");
        System.out.println(numFront + "\t\t\t\t" + hexConverter(hexFront, hexAfter, numFront));
    }

    static String hexConverter(int hexFront, int hexAfter, String numFront)
    {
            if(hexFront == 10)
                return decTo(hexAfter, numFront);
            else if(hexAfter == 10)
                return toDec(hexFront, numFront);
            else
                return decTo(hexAfter, toDec(hexFront, numFront));
    }

//十進制轉換其他進制,算法是位運算,可直接處理負數,負數的二進制是對應正數二進制取反加一。

//實際開發:用Integer.toBinaryString(-6)等等...

    static String decTo(int hexAfter, String numFront)
    {
            //需要優化:判斷字符串是否是數字,是否超出被轉換數類型最大範圍。這裏爲int

            int num = Integer.parseInt(numFront);

            StringBuffer sb = new StringBuffer();

            //限制:進制數爲常見的2的冪方,1,2,4,8,16,32...,保證位運算位數爲整數
            //解決辦法:想取消這個限制,可以考慮短除法思想,重寫算法,

            int byteNum = (int)(Math.log((double)hexAfter)/Math.log((double)2));  //位運算位數
            int resultNum =(int) (Math.ceil(32/byteNum));   //結果位數

            int x = resultNum -1;          //找出第一個不爲0的角標

            for(int i = 0; i < resultNum; i++)
            {
                    int n = num>>>(byteNum*i)&(hexAfter-1);
                    if (n < 10)
                        sb.append(n);
                    else
                        sb.append((char)(n- 10 + 'A'));    //可以考慮使用查表法進行對應轉換。               
            }

            sb.reverse();
            for(int i =0; i < sb.length(); i++)     //求出第一個不爲0的角標 x
            {
                if(sb.charAt(i) != '0')
                {
                    x = i;
                    break;
                }
            }
            return sb.delete(0,x).toString();
    }

//其他進制轉換爲十進制,算法不是按位運算,被轉換數始終認定爲正數
    static String toDec(int hexFront, String numFront)
    {
        //前提:  輸入的數前面不是0開頭,被轉換數不能超出轉換數類型最大範圍。這裏爲int
           int num = 0;

            for(int i = 0; i < numFront.length(); i++)
        {
            char ch = numFront.charAt(numFront.length()-1-i);
            if(ch >= 'A' && ch <= 'Z')
                num += (ch -'A' + 10)*(Math.pow(hexFront,i));       //傻逼了,hexFront^0 是位異或運算,不是次方運算。
            else
                num +=(ch -'0')*(Math.pow(hexFront,i));

        }   

        if(num == 2147483647 && !numFront.equals("01111111111111111111111111111111")&& !numFront.equals("17777777777")&& !numFront.equals("7FFFFFFF"))
            return "被轉換數超出轉換數類型範圍,精度丟失!";
        return String.valueOf(num);
    }
}

8.小結:語言有的功能直接用,沒有的搞懂原理自己造。
開發用的:
1.排序:開發的時候直接用Arrays.sort(arr); ,在類java.util.*中,默認從小到大排序。其他語言不一定有,還是要自己實現
2.查找:開發的時候直接用Arrays.binarySearch(arr,57); ,在類java.util.*中。其他語言不一定有,還是要自己實現。
3.進制轉換:實際開發:用Integer.toBinaryString(-6)等等…

發佈了36 篇原創文章 · 獲贊 0 · 訪問量 4587
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章