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)等等…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值