java二维数组高纬低纬_2018-05-17 第十一天
一、數組
(一)數組的優缺點:
優點:1:數組通過下標訪問元素的效率很高。指定下標n的元素的地址:首地址+n*元素類型字節數。
2:數組可以保存若干個元素的值。
缺點:1:數組的長度是不能更改的。
2:數組進行元素的刪除和插入操作的時候,效率比較低。需要移動大量的元素。
3:數組元素的類型只能是一種。
4:數組通過內容查找元素的效率是比較低的。
5:數組的元素是連續分配的,那么必須在堆內存中找到連續的指定內存空間才能容納數組的所有的數據。對內存要求稍微多一些。
6:數組沒有提供任何的封裝,所有對元素的操作,都是通過自定義方法來實現的。對數組元素的操作比較麻煩。
java 提供了一整套的用于管理對象的容器。集合框架 collection framework??梢杂行Ы鉀Q這些缺點。
(二)java.util.Arrays 工具類
jdk 提供了一個工具類:專門用于處理數組的工具類。
//一定記得導入Arrays。
import java.util.Arrays;
public class Arrays extends Object
此類包含用來操作數組(比如排序和搜索)的各種方法
常用方法:
static int binarySearch(byte[] a, byte key)
使用二分搜索法來搜索指定的byte 型數組,以獲得指定的值。
static int binarySearch(byte[] a, int fromIndex, int toIndex, byte key)
使用二分搜索法來搜索指定的byte 型數組的范圍,以獲得指定的值。
static boolean[] copyOf(boolean[] original, int newLength)
復制指定的數組,截取或用false 填充(如有必要),以使副本具有指定的長度。
static void sort(byte[] a)
對指定的byte 型數組按數字升序進行排序。
static String toString(boolean[] a)
返回指定數組內容的字符串表示形式。
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
從指定源數組中復制一個數組,復制從指定的位置開始,到目標數組的指定位置結束。
(三)main方法傳遞參數(了解):
main 方法的 字符串數組 參數的作用:
可以用來接收控制臺在解釋執行的時候,輸入的一系列的字符串內容。多個字符串對象可以使用空格分隔輸入即可。
public class TestString{
public static void main(String[] args){
for(String str : args){
print(str);
}
String str = "";
String[] strs = {"123","123","123","123","123","123"};
}
public static void print(String str){
System.out.println(str);
}
}
(四) 變參
變參方法:在jdk1.5 之后提供的功能。
語法:參數列表(接收的數據的類型 ... 變量名)
例子(boolean ... values)
變參參數的特點:
1:變參參數可以接收的參數的數量[0-N]
2: 如果有定參的方法,有變參的方法,那么優先匹配定參的方法。
3:一個方法最多只能有一個變參參數,而且必須在參數列表的末尾。
4:方法在處理變參參數的時候,就當數組來處理即可。底層使用數組實現的。
5:變參參數既可以接收 數據類型若干個實參的值,還可以接收一個該類型的數組。
例:
需求:使用變參實現:寫一個方法,可以接收任意個int類型的參數,將這若干個數據中的最大值返回。
//變參方法
public class TestChangeArgs{
public static void main(String[] args){
System.out.println(max());
System.out.println(max(1));
System.out.println(max(2,5));
System.out.println(max(3,4,8));
System.out.println(max(2,5,67,89));
System.out.println(max(32,54,67,7,56,45,34));
int[] arr = {45,34,32,54,76};
System.out.println(max(arr));
}
public static int max(int a, int b){
System.out.println("2個參數的方法");
return a > ?b ? a : b;
}
public static int max(int a, int b ,int c){
System.out.println("3個參數的方法");
return a > ?b ? (a > c ? a : c) : (b > c ? b : c);
}
//如果有方法可以接收參數的數量是任意個[0--n]?
public static int max(int ... values){
System.out.println("變參參數的方法");
if(values == null)return -1;
if(values.length == 0)return -2;
int max = values[0];
for(int i = 1;i< values.length;i++){
if(values[i] > max){
max = values[i];
}
}
return max;
}
public static void test(int a, int ... values){
}
}
(五)多維數組
一維數組:int[] values = new int[10];
二維數組:本質上還是一維數組
int[] array;
int[][] array;
初始化的方式:
動態的:int[][] array = new int[7][9];//代表了這個數組是一個7個元素的一維數組,每個一維數組的元素又是一個一維數組,最終的一維數組的元素的個數是9個。
其他樣式:int[][] arr = new int[1][1];
int[] arr[] ?= new int[1][2];
int [][]arr = new int[2][3];
int arr[][] = new int[2][5];
靜態方式:int[][] array1 = new int[][]{
{1,34,5,65,89},
{1,34,5},
{1,65},
{1,34,5,65,5,4,43,23}
};
int[][] array1 = {
{1,34,5,65,89},
{1,34,5},
{1,65},
{1,34,5,65,5,4,43,23}
};
//多維數組
import java.util.Arrays;
public class TestArray6{
public static void main(String[] args){
//高緯 代表的是有幾個一維數組,低緯的數值代表的是每一個一維數組的元素的個數。
int[] array[] = new int[3][];
System.out.println(Arrays.toString(array));
//可以將每個一維數組的長度控制的不同。單獨進行空間的分配。
array[0] = new int[3];
array[1] = new int[6];
array[2] = new int[1];
System.out.println(Arrays.toString(array));
System.out.println(array.length);//3
System.out.println(array[1].length);//6
int[][] array1 = new int[][]{
{1,34,5,65,89},
{1,34,5},
{1,65},
{1,34,5,65,5,4,43,23}
};
System.out.println(array1.length);//4
System.out.println(array1[2].length);//2
}
}
多維數組內存圖:
例1:
//使用二維數組中的元素,存儲九九乘法表的結果,最后在將結果打印實現九九乘法表的效果。
public static void test(){
//先對二維數組進行高緯空間的分配。
final int LEN = 9;
int[][] nine = new int[9][];
//然后在對每個一維數組進行單獨的空間的分配。
for(int i=0;i
nine[i] = new int[i+1];
}
//在使用for 循環 將結果打印。
for(int i=1;i<=LEN;i++){
for(int j=1;j<=i;j++){
//使用數組元素保存
nine[i-1][j-1] = j * i;
System.out.print(j+"*"+i+"="+nine[i-1][j-1]+"; ");
}
System.out.println();
}
}
例2:偏算法,可以了解了解
//螺旋數組
public class TestArray11{
public static void main(String[] args){
int count = 6;
int[][] ints = test(count);
for (int i = 0; i < count; i++) {
for (int j = 0; j < count; j++) {
System.out.print(ints[i][j] + "\t");
}
System.out.println();
}
}
private static int[][] test(int count){
int[][] ints = new int[count][count];
final int RIGHT = 0;
final int DOWN = 1;
final int LEFT = 2;
final int UP = 3;
int dir = RIGHT;
int curRow = 0;
int curCol = 0;
for (int i = 1; i <= count * count; i++) {
switch(dir){
case RIGHT:
if(curCol < count){
if(ints[curRow][curCol] == 0){
ints[curRow][curCol] = i;
curCol ++;
}else{
curCol --;
dir = DOWN;
if(ints[curRow + 1][curCol] != 0){
return ints;
}else{
curRow ++;
ints[curRow][curCol] = i;
curRow ++;
}
}
}else{
curCol --;
dir = DOWN;
if(ints[curRow + 1][curCol] != 0){
return ints;
}else{
curRow ++;
ints[curRow][curCol] = i;
curRow ++;
}
}
break;
case DOWN:
if(curRow < count){
if(ints[curRow][curCol] == 0){
ints[curRow][curCol] = i;
curRow ++;
}else{
curRow --;
dir = LEFT;
if(ints[curRow][curCol-1] != 0){
return ints;
}else{
curCol --;
ints[curRow][curCol] = i;
curCol --;
}
}
}else{
curRow --;
dir = LEFT;
if(ints[curRow][curCol-1] != 0){
return ints;
}else{
curCol --;
ints[curRow][curCol] = i;
curCol --;
}
}
break;
case LEFT:
if(curCol >=0){
if(ints[curRow][curCol] == 0){
ints[curRow][curCol] = i;
curCol --;
}else{
dir = UP;
curCol ++;
if(ints[curRow - 1][curCol] != 0){
return ints;
}else{
ints[--curRow][curCol] = i;
curRow --;
}
}
}else{
curCol ++;
dir = UP;
if(ints[curRow - 1][curCol] != 0){
return ints;
}else{
ints[--curRow][curCol] = i;
curRow --;
}
}
break;
case UP:
if(curRow >=0){
if(ints[curRow][curCol] == 0){
ints[curRow][curCol] = i;
curRow --;
}else{
dir = RIGHT;
curRow++;
if(ints[curRow][curCol+1] != 0){
return ints;
}else{
ints[curRow][++curCol] = i;
++curCol;
}
}
}else{
curRow ++;
dir = RIGHT;
if(ints[curRow][curCol+1] != 0){
return ints;
}else{
ints[curRow][++curCol] = i;
++curCol;
}
}
break;
}
}
return ints;
}
}
二、遞歸
概念:遞歸調用:方法直接或者間接的調用自身的過程。
void a(int n){
//a(n-1);
b(n-1);
}
void b(int n){
a(n-1);
}
什么樣的問題可以使用遞歸調用來解決?
1:一個問題可以被分解為若干個子問題。
2:子問題的解決方案和問題的解決方案一致。
3:最終問題的解決依賴于子問題的解決。
例1:
//求n 的階乘。
n!:n*(n-1)*(n-2)*...2*1;
1:一個問題可以被分解為若干個子問題。
2:子問題的解決方案和問題的解決方案一致。
3:最終問題的解決依賴于子問題的解決。
5! = 5 * 4 !
4! = 4 * 3!
3! = 3 * 2!
2! = 2 * 1!
1! = 1;
//求n 的階乘 ?時間復雜度 ?T(n) = O(n); ?空間復雜度 S(n) = O(n)
public static int fac(int n){
int result = 0;
if(n == 1){
result = 1;
}else{
result = n * fac(n-1);
}
return result;
}
例2:
//斐波那契數列 ?前兩個數都是1,從第三個數開始,是前兩個數之和
//1,1,2,3,5,8,13。。。。 T(n) = O(n);
//求第n 個位置上的斐波那契數列的值
public static int febo(int n){
if(n == 1 || n == 2){
return 1;
}else{
return febo(n-1) + febo(n-2);
}
}
遞歸調用的優缺點:
優點:代碼簡單,思路比較簡單。
缺點:對棧內存的消耗比較大,如果控制不好,那么就會造成棧內存溢出。
遞歸調用的過程中,必須在某些情況下存在自己不調用自己的情況。以保證程序可以在合適的時候正確返回。
三、算法(algorithm )(了解)
是指令的集合,是為解決特定問題而規定的一系列操作。
簡單的說,算法就是計算機解題的過程。
舉例:如何求0+1+2+3+...10000=?
算法1:依次相加 ?while do-while ?for
算法2:高斯解法:首尾相加*50 ???(1+10000)*10000/2 ???100*101/2
算法3:使用遞歸實現: sum(100) = sum(99)+100 ??sum(99)= sum(98)+99 ..... ??sum(2) = sum(1)+2 ??sum(1) = 1
評價算法優劣的依據:復雜度(時間復雜度和空間復雜度)
時間復雜度是指執行算法所需要的計算工作量
空間復雜度是指執行這個算法所需要的內存空間
(一)時間復雜度(Time Complexity))定義
時間頻度:
一個算法執行所耗費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。
但我們不可能也沒有必要對每個算法都上機測試。
一個算法花費的時間與算法中語句的執行次數成正比例,哪個算法中語句執行次數多,它花費時間就多。
一個算法中的語句執行次數稱為語句頻度或時間頻度,表示為T(n),n表示問題的規模
時間復雜度
但有時我們想知道它變化時呈現什么規律,想知道問題的規模,而不是具體的次數,此時引入時間復雜度。
一般情況下,算法中基本操作重復執行的次數是問題規模n的某個函數,用T(n)表示,
若有某個輔助函數f(n),使得當n趨近于無窮大時,T(n)/f(n)的極限值為不等于零的常數,則稱f(n)是T(n)的同數量級函數。
記作T(n)=O(f(n)),稱O(f(n)) 為算法的漸進時間復雜度,簡稱時間復雜度。
T(n)=O(f(n))
或者說:時間復雜度就是時間頻度去掉低階項和首項常數。
注意:時間頻度與時間復雜度是不同的,時間頻度不同但時間復雜度可能相同。
比如:某兩個算法的時間頻度是T(n) = 100000n2+10n+6 ???T(n) = 10n2+10n+6 ??T(n) = n2
但是時間復雜度都是T(n) = O(n2)
總結:隨著n 的增大,如果兩個頻度的函數的結果是無限接近的,那么這兩個算法的時間復雜度是相同的。
時間復雜度考量的是算法的變化的趨勢。
最壞時間復雜度和平均時間復雜度
最壞情況下的時間復雜度稱最壞時間復雜度。一般不特別說明,討論的時間復雜度均是最壞情況下的時間復雜度。
這樣做的原因是:最壞情況下的時間復雜度是算法在任何輸入實例上運行時間的上界,這就保證了算法的運行時間不會比任何更長。
在最壞情況下的時間復雜度為T(n)=O(n),它表示對于任何輸入實例,該算法的運行時間不可能大于O(n)。
平均時間復雜度是指所有可能的輸入實例均以等概率出現的情況下,算法的期望運行時間。鑒于平均復雜度
第一,難計算
第二,有很多算法的平均情況和最差情況的復雜度是一樣的。
所以一般討論最壞時間復雜度
比如我要求你在字典里查同一個字,告訴我這個字在字典的那一頁。
如果一頁一頁的翻,你需要多少時間呢?
最優的情況就是這個字在第一頁,
最壞的情況就是這個字是整本字典的最后一個字。
所以即使我故意為難你,你也不會花費比找整本字典最后一個字還長的時間。
當然,此時聰明的你就會想用部首、筆畫等去查,才不要傻乎乎的一頁一頁翻,
此時的你就會擇優選擇,因為此時你最壞得情況就是我給你部首筆畫最多、除部首外筆畫最多的一個超級復雜的一個字,但顯然比翻整本字典快得多。
為了進一步說明算法的時間復雜度,我們定義Ο、Ω、Θ符號。
Ο(歐米可榮)符號給出了算法時間復雜度的上界(最壞情況<=),比如T(n) =O(n2)
Ω(歐米伽)符號給出了時間復雜度的下界(最好情況>=),比如T(n) =Ω(n2)
而Θ(西塔)給出了算法時間復雜度的精確階(最好和最壞是同一個階=),比如T(n) =Θ(n2)
時間復雜度計算
根本沒有必要計算時間頻度,即使計算處理還要忽略常量、低次冪和最高次冪的系數,所以可以采用如下簡單方法:
⑴ 找出算法中的基本語句;
算法中執行次數最多的那條語句就是基本語句,通常是最內層循環的循環體。
⑵ 計算基本語句的執行次數的數量級;
只需計算基本語句執行次數的數量級,這就意味著只要保證基本語句執行次數的函數中的最高次冪正確即可,
可以忽略所有低次冪和最高次冪的系數。這樣能夠簡化算法分析,并且使注意力集中在最重要的一點上:增長率。
⑶ 用大Ο記號表示算法的時間性能。
將基本語句執行次數的數量級放入大Ο記號中。
總結:先找出基本的執行單元的語句。然后算出語句的執行的頻度,去掉低階項,常數項,去掉最高階的系數。
T(n) = O(f(n));
T(n) = O(n^2)
時間復雜度舉例
一個簡單語句的時間復雜度為O(1)。
int count=0;
100個簡單語句的時間復雜度也為O(1)。(100是常數,不是趨向無窮大的n)
int count=0;
如果一個算法隨著問題規模的增大,執行的基本語句的次數都是一個定值,那么時間復雜度都是O(1)
T(n) = O(1);
一個循環的時間復雜度為O(n)。
int n=8, count=0;
for (int i=1; i<=n; i++)
count++;
T(n)=O(n)
時間復雜度為O(log2?n)的循環語句。
int n=8, count=0;
for (int i=1; i<=n;i*=2)
count++;
n=2 ??2
n=4 ??3
n=8 ??4
n=16 5
230=1024*1024*1024 = 1000*1000*1000=10億
時間復雜度為O(n2)的二重循環。
int n=8, count=0;
for (int i=1; i<=100n; i++)
for (int j=1; j<=10n; j++)
count++;
時間復雜度為O(nlog2n)的二重循環。
int n=8, count=0;
for (int i=1; i<=n; i*=2)
for (int j=1; j<=n; j++)
count++;
時間復雜度為O(n2)的二重循環。
int n=8, count=0;
for (int i=1; i<=n; i++)
for (int j=1;j<=i; j++)
count++;
1+2+3+4....+n=(1+n)*n/2
需要復雜些數學運算:1+2+3+.....+n=(n+1)*n/2 ?時間復雜度是 O(n2)
后面講解查找和排序算法時會大量的設計時間復雜度,作為選擇查找和排序算法的重要依據
常用的時間復雜度級別
常數階O(1)
對數階O(log2n)
線性階O(n)
線性對數階O(n*log2n)
平方階O(n2)
立方階O(n3)
...
k次方階O(nk)
指數階O(2n)
階乘階O(n!)
上面各種時間復雜度級別,執行效率越來越低。
大家發現對數階O(log2n)和線性階O(n)的效率差異了嗎,當n=10的8次方(1億)時,執行此時一個是1億次,一個是8次。
所以編寫算法時一定要注意時間復雜度的選擇。
空間復雜度計算:
表示方法
S(n) = O(f(n));
固定的變量的個數
S(n) = O(1);
例://1-n的累加和。
n 就是問題的規模。
1:使用while 循環 sum +=i
T(n) = n;
T(n) = O(n).
2:高斯算法 ?(1+n)*n/2
T(n) = 1;
T(n) = O(1);
總結
以上是生活随笔為你收集整理的java二维数组高纬低纬_2018-05-17 第十一天的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: led控制器java_TM1668 Le
- 下一篇: python在匿名函数作和_跟光磊学Py
