Day 5 : 循环问题、数组

  1. 循环问题
  2. 数组

1. 循环问题

1.1. 循环问题

1.1.1. 循环问题

在实际应用中,当碰到需要多次重复的执行一个或多个任务的情况时,考虑使用循环来

解决,在前面所介绍的3种循环(while、do-while、for)中,一般情况下,for循环使用得最多,而对于for循环结构,一定要分析出需要解决业务的三个部分:

  1. 循环变量初始状态
  2. 循环条件
  3. 循环变量的改变

分析好了上面的三个部分,for语句的结构也就定义好了,其它的问题只在于填写不同

的循环体来解决不同的业务问题而已。

1.1.2. 循环问题定义------“当”循环

如果业务可以转换为“当……“这样的句式时,优先选择while语句来实现。看下面的需求:假设年存款利率为3%,本金为10000,问存款总额超过12000时,收益具体是多少?

分析这个需求,可以转化为下面的理解:“当“存款总额小于12000时,以3%的利率增长,那么条件就是total<12000,这种”当“句式优先考虑使用while语句实现,简易代码如下:

    ……
while( 条件 ) {
total += ( total * 0.03 ) ;
}
……

1.1.3. 循环问题定义------“直到”循环

如果业务可转换为”直到……”这样的句式时,优先选择do-while语句来实现。看下面的需求:在验证身份时必须提供密码并核对,密码不正确则继续输入密码。分析这个需求,可以转化为下面的理解:获取密码,”直到”输入的值为123456,那么条件就是! ”123456”.equals(inputPwd),这种“直到……“句式优先考虑使用do-while语句实现,简易代码如下:

……
do {
……
} while(! ”123456”.equals(inputPwd));
……

1.1.4. 循环问题定义------固定次数循环

如果业务中可以获取到一个确切的循环次数时可以考虑使用for循环来实现,看下面的需求:求1-100的和、累加10次输入的数字的和、录入3名学员信息、存储5门课程成绩……,上面的需求都是可以明确确切的循环次数,故而优先用for循环。

2. 数组

2.1. 什么是数组

首先明确,数组是一个很重要的内容,非常重要。

前面介绍的if结构、循环,解决的都是算法问题。那什么是算法?所谓算法就是流程,像取钱怎么取?插卡,输入密码,输入要取钱的金额,确定。那这个过程,第一步怎么做,第二步怎么做,判断还是循环,这就是算法。

Pascal之父Nicklaus Wirth说过一句话并因此而得了图灵奖,这句很经典的话就是,程序即为:算法+数据结构,所谓数据结构,简单的说就是把数据按照特定的某种结构来保存,设计合理的数据结构是解决问题的前提条件。今天讲的数组,就是最基本的、用得最多的一种数据结构。试想下,存储一个学员的成绩,可以声明一个整型变量score来存储,声明20个学员的考试成绩呢?存储50个随机数呢?存储1万个帐号呢?声明太多的变量,显然很繁琐,并且不适合整体的操作。像这种情况,可以使用数组这种数据结构来解决。

数组为相同数据类型的元素组成的集合,数组元素按线性顺序排列,所谓线性顺序是指除第一个元素外,每一个元素都有唯一的前驱元素;除最后一个元素外,每一个元素都有唯一的后继元素(“一个跟一个”),可以通过元素所在位置的顺序号(下标)做标识访问每一个元素(下标从0开始,最大到元素个数-1),数组结构如下图 - 2所示:

图- 2

从上图中可以看出,a[0]即代表第1个元素,a[1]代表第二个元素,假设数组有5个元素,则最后一个元素即为a[5-1]。

2.2. 数组的定义

2.2.1. 定义基本类型数组

声明数组的语法为: 数据类型[] 数组名 = new 数据类型 [ 大小 ] ;示例代码如下:

int [] arr = new int[10] ;

上面的示例代码中,int[]为数组类型,表示数组中的每一个元素为int类型;数组也是在内存中用于存储数据的,并且是存储一组数据,同样需要一个对它的引用,该引用即为arr,arr称为数组类型变量(引用);new为特定的声明数组的关键字,后面会详细讲解,现在先记住。数组的声明必须要有元素个数,10即为数组中元素的个数,也称为数组长度。总结下来, 定义基本类型数组的要点包括:

  1. 确切的数据类型:用于开辟空间大小
  2. 整体的数组名字:用于对数据的引用
  3. 不能缺少的“ [ ] ”

注意在定义数组时使用的new关键字, 正是因为new语句,才使得数组分配到了指定大小的空间(后面详细讲解)。

声明数组的时候,int[] arr 与 int arr [] 两种写法均可。常用方式为int[] arr。

声明数组时不规定数组长度(可以看到声明时仅指定了int[],未指定长度),new关键字分配空间时需指定分配的空间大小(new int[10])。

2.3. 数组的初始化

2.3.1. 初始化数组

基本类型 (数据元素为基本类型)的数组创建后,默认为其数组元素设置了初始值,元素的初始值如下所示:byte、short、char、int、long为0; float和double为0.0; boolean为false。注意,此处强调的是基本类型数组的默认值,后期会介绍数据元素为非基本类型的,它的默认初始值与基本类型不同。

在程序中很多时候需要手动设置初始值,可以在数组声明的同时进行初始化,如下代码所示:

int [ ] arr = { 10,23,30,-10,21 } ;

上面的代码中,元素的个数即为数组的长度。但是此种写法只能用于声明时的初始化,不能用于先声明后赋值的情况,例如,下面的代码会有编译错误:

int [ ] arr;
arr = { 10,23,30,-10,21 } ;

对于已声明的数组,可以通过下面的方式对数组类型变量进行初始化:

int[] arr;
arr = new int[]{ 10,23,30,-10,21 };

注意:new之后的[]中不可以写长度,而元素的个数就是数组的长度。

2.4. 数组的访问

2.4.1. 获取数组的长度

在程序中,调用数组的length属性可以获取数组的长度,如下代码所示:

int[] arr = new int[]{ 3,6,8,9 };
int len = arr . length ;
System.out.println(“数组长度为:” + len);

上面的代码中,len即为数组的长度,输出结果为:“数组长度为:4”。

2.4.2. 通过下标访问数组元素

若想访问数组中的元素,需要通过下标的方式,需要注意的是,数组的下标从0开始,最大到length-1,代码如下所示:

int[ ] arr = new int[]{ 4,5,6,8};
int temp = arr [ 2 ]; //获取第3个元素,即为6
//交换数组下标为2和3的两个相邻元素的值,交互后的结果为:4,5,8,6
int temp = arr [ 2 ] ;
arr [ 2 ] = arr [ 3 ] ;
arr [ 3 ] = temp ;

2.4.3. 遍历数组元素

在实际的应用中,常常需要对数组整体进行操作,最常见的方式即为遍历数组元素,通常可选择for循环语句,循环变量作为访问数组元素的下标,即可访问数组中的每一个元素,下面的代码使用循环方式将数组的每一个元素赋值为100。

int[] arr = new int[10];
for ( int i = 0 ; i < arr.length ; i ++ ){
arr [ i ] = 100;
}

注意:循环的计数器的变化范围从0到数组长度– 1,可通过写成“小于长度”这样的条件来防止下标越界(超出范围)。

上面的代码为循环对数组元素赋值,下面两段代码为使用循环方式分别正序、逆序输出数组元素数据:

int [ ] arr = new int [ 5 ] {10,20,30,40,50 } ; //正序输出
for ( int i=0; i< arr.length; i++) {
System.out.println ( arr[ i ] ) ;
}
int [ ] arr = new int [ 5 ] {10,20,30,40,50 } ; //逆序输出
for ( int i = (arr.length -1) ; i >= 0 ; i - - ) {
System.out.println ( arr[ i ] ) ;
}

2.5. 数组的复制

2.5.1. System.arraycopy方法用于数组复制

若想实现数组的复制,可以使用System.arraycopy( )方法,其结构如下:

public static void arraycopy(Object src, int srcPos,Object dest, int destPos, int length)

如上代码的,每一个参数的意义见下列表:

  • src:源数组
  • srcPos:源数组中的起始位置
  • dest:目标数组
  • destPos : 目标数组中的起始位置
  • length:要复制的数组元素的数量

通过下面的代码,可实现数组的复制:

int[ ] a = { 10 ,20 ,30 ,40 ,50 };
int[ ] a1 = new int[ 6 ] ;
System.arraycopy( a , 1 , a1 , 0 , 4 ); 结果:20,30,40,50

如上方法的意义可以理解为:将a数组的从下标1开始的4个元素复制到a1数组中,a1数组从下标0位置开始赋值。程序执行完后,a1的值为20,30,40,50,0,0。其交互效果如图 – 3所示:

图- 3

2.5.2. Arrays.copyOf方法用于数组复制

使用java.util.Arrays类的copyOf方法可实现数组的复制,其结构如下所示:

类型[ ] newArray = Arrays.copyOf ( 类型[ ] original , int newLength )

Arrays.copyOf()方法示例代码如下所示:

int [ ] a = { 10,20,30,40,50 } ;
int [ ] a1 = Arrays . copyOf ( a, 6 );

上段代码执行后,a1的结果为:10 20 30 40 50 0,分析其执行过程为:声明一个整型数组,数组变量名称为a,赋初始值为10 20 30 40 50,声明整型数组a1,将a数组数据复制到a1数组,设置其为6个长度,因a数组只有5个元素,所以最后一位补0。故而输出结果为10 20 30 40 50 0。总结出Arrays.copyOf()方法的特点如下列表所示:

  • 生成的新数组是原始数组的副本;
  • newLength小于源数组,则进行截取;(自己通过代码演示效果);
  • newLength大于源数组,则用0或 null进行填充;

2.5.3. 数组的“扩容”

Java语法规定,数组的长度在创建后是不可改变的,这点需要明确。而所谓的扩容实际上是指创建一个更大的新数组并将原有数组的内容复制到其中。可以通过Arrays.copyOf()方法,简便的实现数组的扩展,代码如下:

int [ ] a = { 10,20,30,40,50 } ;
a = Arrays . copyOf ( a, a.length+1 );

上段代码执行后,输出a数组的数据为:10,20,30,40,50,0。此时a数组的长度为6,实现了所谓的“扩容”。

2.6. 数组排序

2.6.1. 数组的排序

对数组所施加的算法有很多,其中最常用的即为排序算法。所谓排序,是指将数组元素按照从小到大或从大到小的顺序重新排列,当数组元素数较多时, 排序算法的优劣至关重要,因为它将直接影响程序的执行效率,一般情况下,通过排序过程中数组元素的交换次数来衡量排序算法的优劣。

常用排序算法有:插入排序、冒泡排序、快速排序等。今天介绍的是冒泡排序。

2.6.2. 数组冒泡排序算法

冒泡排序是一个非常经典的排序算法,它的排序原则为:比较相邻的元素,如果违反最后的顺序准则(从大到小或是从小到大),则交换。可以简化理解为:第一次找到所有元素中最大(或最小)的放在最后一个位置上,不再变动;第二次找到剩余所有元素中最大(或最小)的放在倒数第二个位置上,不再变动,以此类推,直到排序完成。在进行比较时既可以采用“下沉”的方式,也可以使用“上浮”的方式实现。

冒泡排序逻辑如下图– 1所示。

图- 1

下面对如上示例进行详细分析,需求:初始序列为89,50,84,57,61,20,86,升序排(小的在前,大的在后);

第一轮第一次,89与50对比,交换位置,结果:50,89,84,57,61,20,86

第一轮第二次,89与84对比,交换位置,结果:50,84,89,57,61,20,86

第一轮第三次,89与57对比,交换位置,结果:50,84,57,89,61,20,86

第一轮第四次,89与61对比,交换位置,结果:50,84,57,61,89,20,86

第一轮第五次,89与20对比,交换位置,结果:50,84,57,61,20,89,86

第一轮第六次,89与86对比,交换位置,结果:50,84,57,61,20,86,89

将89冒出来了,现在序列为:50,84,57,61,20,86,89

第二轮第一次,50与84对比,位置不换

第二轮第二次,84与57对比,交换位置,结果:50,57,84,61,20,86,89

第二轮第三次,84与61对比,交换位置,结果:50,57,61,84,20,86,89

第二轮第四次,84与20对比,交换位置,结果:50,57,61,20,84,86,89

第二轮第五次,84与86对比,位置不换

将86冒出来了,现在序列为:50,57,61,20,84,86,89

第三轮第一次,50与57对比,位置不换

第三轮第二次,57与61对比,位置不换

第三轮第三次,61与20对比,交换位置,结果:50,57,20,61,84,86,89

第三轮第四次,61与84对比,位置不换

将84冒出来了,现在序列为:50,57,20,61,84,86,89

第四轮第一次,50与57对比,位置不换

第四轮第二次,57与20对比,交换位置,结果:50,20,57,61,84,86,89

第四轮第三次,57与61对比,位置不换

将61冒出来了,现在序列为:50,20,57,61,84,86,89

第五轮第一次,50与20对比,交换位置,结果:20,50,57,61,84,86,89

第五轮第二次,50与57对比,位置不换

将57冒出来了,现在序列为:20,50,57,61,84,86,89

第六轮第一次,20与50对比,位置不换

将50冒出来了,现在的序列为:20,50,57,61,84,86,89

通过上面的分析总结出如下几点,找出规律,通过程序即可完成冒泡算法的实现。

  • 若数组元素数为7, 则排序过程需要经历6轮,因为有1个元素是不需要比较的。
  • 若数组元素数为7,第1轮比较6次,第2轮比较5次,依次类推,第6轮只比较1次。

通过如上的分析,写出冒泡排序算法如下所示:

    int[] arr = {89,50,84,57,61,20,86};
    for(int i=0;i<arr.length-1;i++){
        for(int j=0;j<arr.length-1-i;j++){
            if(arr[j]>arr[j+1]){
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
}
}

2.6.3. Arrays.sort方法用于数组排序

JDK提供的Arrays.sort()方法封装了数组的排序算法,如下述代码所示:

int[ ] arr = { 49, 81, 1, 64, 77, 50, 0, 54, 77, 18 };
Arrays.sort( arr ) ;
for(int i=0; i<arr.length; i++) {
    System.out.println(arr[i] );
}

分析上面的代码,输出结果为:0 1 18 49 50 54 64 77 77 81。可以看到,借助于Arrays.sort()方法实现了升序排列。

时间: 2024-10-24 20:01:06

Day 5 : 循环问题、数组的相关文章

Java--分支语句、循环、数组、控制台输入语句、常用数学函数

**-----本章节-----** 1.分支语句 2.循环 3.数组 4.控制台输入语句 5.部分常用的数学函数 ============================================================== 一分支语句 1.概念 (1)分支语句又称条件语句条件语句使部分程序可根据某些表达式的值被有选择地执行. (2)Java编程语言支持双路 if和多路 switch 分支语句. ===========================================

AWK中for循环调用数组解释

以前对于awk中的for循环调用数组一直不是很清晰,通过这个例子你将会对这种方法非常明白. #!/bin/sh echo"" | awk ' BEGIN { a[1]="123" a[2]="456" a[3]="789" } END{ for(i in a) { print i,a[i] } }' 结果:

约瑟夫问题 算法很简单保证每隔人都能看懂用数组实现 利用循环删除数组中的元素

#include<iostream> using namespace std; const int size = 1000; void ArrDel() { int arr[size]; //循环结束标志,一直循环到数组中只剩下最后一个元素结束 int currentNum = size; int count = 0; for (int k = 0; k < size; k++) { arr[k] = k; } //currentNum==1表示数组中只剩下最后一个元素 是循环结束的标志

使用sort加个简单的算法,不循环整个数组而删除数组内的某些元素。

昨天遇到一个这样的场景: 有一个不分页的商品列表,里面可能有上千条数据(而且可能是静态数据)甚至更多,这里有个删除功能,需要我们删除其中的一些商品. 这时我的第一反应就是,数据过多不能循环整个数组,只有获取到它们的索引,然后循环得到的索引,使用数组的splice()方法对它进行删除.并且我这样做了,但是发现了一个致命的bug. bug的原因是这样的: 我先得到了一组索引(就是我所需要删除的商品的索引),然后循环了这组索引,在每次循环的时候我执行了splie()方法,但是由于splice方法执行后

*使用while循环遍历数组创建索引和自增索引值

package com.chongrui.test; /* *使用while循环遍历数组 *  *  * */ public class test { public static void main(String[] args) {        // TODO Auto-generated method stub           String[] aves = new String[]{"白路","丹顶鹤","百灵"};//创建鸟类数组  

用循环与数组模拟双色球彩票中奖

String ji="机选"; String zi="自选"; System.out.println("请问机选还是自选?"); String my=wx.next(); int []a=new int[7];//用户买的号码记录的数组 //自选时的用户彩票 if(my.equals(zi)){ for(int i=0;i<a.length;i++){ //蓝球的输入 if(i==6){ System.out.println("请

swift基本用法-for循环遍历,遍历字典,循环生成数组

// Playground - noun: a place where people can play import UIKit //------------------------------------------------------------------------------ // 1. for // 传统的for循环方式在swift中同样支持 var num = 0 for(var i = 0; i < 10 ; i++) { num += i } num //---------

循环一维数组求最大子数组

题目: 随机出一个一维数组,设该数组为循环数组,求其最大小子数组. 一.设计思路 求最大子数组,就求出最大的连续正子数组. 将数组分为全负和有非负值两种情况.全负求出最大值即可. 在有非负值的情况下,先判断该随机数组的首尾是否相连,即首尾是否都大于等于零.如果首尾相连,则将该一维数组分为首.中.尾三部分,先求出首尾和S1,再求中间最大连续正子数组和S,令S1和S与maxS相比较,求出最大子数组:如果首尾不相连,则直接借鉴前一种情况中部的算法,求最大正子数组S. 二.源代码 1 //刘双渤,刘洪阳

一维循环的数组求出最大子数组的和

题目是:一维循环的数组求出最大子数组的和 老师刚给出这个题目时 ,求出一维子数组的最大子数组的和,当时我就想原来已经做过一个求出一维数组的最大子数组的和,能不能在此基础上延伸一下,于是我就想怎样利用原来的算法,后来我就想既然是还是求出最大子数组的和肯定原来的东西可以利用. 我想既然是循环,无外乎就是这个数组进行两遍,所以我感觉这样就可以再在这个数组后面申请一个和它长度相同,数的大小和顺序和它一样的数组,这样就起到了循环的目的,于是我就这样进行了,然后再调用原来的方法,这样就可以求出最大子数组的值

8.17 课堂练习代码,循环与数组

/* 打印出所有的“水仙花数”,所谓“水仙花数”是指一个三位数,其各位数字立方和等于该数本身. 例如:153是一个“水仙花数”,因为153=1的三次方+5的三次方+3的三次方. */ #include <stdio.h> void main() { int num,ge,shi,bai; for(num = 100; num < 1000; num++) { ge = num % 10; shi = num / 10 % 10; bai = num / 100; if(ge*ge*ge