阅读 148

数据结构之数组与经典面试题(二)

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个。=> in(一维的长度)+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 需要添加的元素
     */@Overridepublic void add(Object element) {//1、判断数组是否需要扩容ensureCapacityInternal();//2、把element添加进入数组中elementData[size] = element;//3、更新size的值size++;}/**
     * 根据索引获取元素值
     *
     * @param index 索引值
     * @return 数组中index索引对应的元素值
     */@Overridepublic Object get(int index) {//1、判断索引是否合法,合法的取值范围:【0,size-1】rangeCheck(index);//2、根据索引获取对应的元素值return elementData[index];}/**
     * 根据索引删除元素
     *
     * @param index 索引值
     */@Overridepublic 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 需要插入的元素
     */@Overridepublic 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;}}@Overridepublic 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 - 1int 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));}}




文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐