## 彻底掌握数据结构之数组&算法(java)

彻底掌握数据结构之数组&算法(java)

这一篇博客主要学习数组结构和对应的算法。总所周知,数据结构是一种打包数据的容器,数组是所有打包容器的材料,而算法给打包提供了对应的方式,这两者相辅相成。我从一维数组开始,通过实例,逐次用n维数组打包数据。
1.一维数组
首先我们复习一下一维数组的基础,在java语言中,一维数组的声明方式如下:
数据类型[] 数组名=new 数据类型[元素个数];
了解了基本构造,我们便开始通过一个例子讲透一维数组:
【范例一维数组】
题:请使用一维数组查找并存储范围为1到MAX内的所有质数,所谓质数(prime number)是指不能被1和它本身以外的其他整数所整除的整数。
解:在这道题中,我们需要存储1到300所有数据,并且查找出所有质数。
编程之前我们首先得解决两个问题,如何存储1到300间的所有数据呢?以及如何筛选出所有质数?
我依次解答:
①因为是一维数组的范例,在这里我们肯定是用一维数组存储所有数据。考虑到需要筛选,我们可以用boolean类型的一维数组存储数据,设置数组大小为MAX(MAX=300),这样相当于把1到300所有数据以下标的形式存储到了数组中。(有可能有些同学会说这样下标是从0~299并不是1到300,因为本题只要求存储并且查找所有质数,0和300都不是质数最终都会被剔除掉,所以我们并不用在意。这种边界问题可以根据情况忽略)
②选择了打包容器,现在我们需要找到对应的算法筛选出所有质数。我们这里选用的迭代算法,通过层层剔除掉非质数来筛选出最后的质数。创建一个布尔类型数组prime,我们设置prime[非质数]=true,prime[质数]=false。通过迭代来将所有的非质数下标位置的值设置为true,剩下的false值的下标便是质数。
解决了两个关键问题,我们便可以开始写具体代码了。代码如下:

package 数组;
//请使用一维数组查找并存储范围为1到MAX内的所有质数,所谓质数是指不能被1和它本身以外的其他整数所整除的整数
public class 一维数组的应用_求质数 {
	public static void main(String[] args) {
		final int MAX=300;
		//false为质数,true为非质数
		//声明后若没有给定初值,其默认值为false
		boolean prime[]=new boolean[MAX];
		prime[0]=true;//0为非质数
		prime[1]=true;//1为非质数
		int num=2,i;
		//将1~MAX中不是质数的逐一过滤掉,以此方式找到所有
		while(num<MAX) {
			if(!prime[num]) {
				for(i=num+num;i<MAX;i+=num) {
					prime[i]=true;//设定为true,此数代表非质数
				}
				
			}
			num++;
		}
		//每次迭代筛选的数字
		//2(开始数字,不被设置为true):4,6,8,10,12...300(被设置为true)
		//3:6,9,12,15,18...300
		//4:6,8,10,12,14...300
		//5:10,15,20,25...300
		//6:12,18,24,30...300
		//...
		//75:150...225...300
		//...
		//150:300
		//150(包括150)之后的均不筛选
		//打印1~MAX间的所有质数
		System.out.println("1到"+MAX+"间的所有质数:");
		for(i=2,num=0;i<MAX;i++) {
			if(!prime[i]) {
			System.out.print(i+"\t");
				if(num%10==0) {
				System.out.println();
			}
			num++;
			}
		}
		System.out.println("\n质数总数="+num+"个");
	}

}

运行结果如下:
在这里插入图片描述
2.二维数组
二维数组(Tow-dimension Array)可视为一维数组的扩展,都是用于处理数据类型相同的数据,差别只在于维数的声明。例如,一个含有m*n个元素的二维数组A[m][n],m代表行数,n代表列数。例如,A[4][4]数组中各个元素在直观平面上的图示如下:
在这里插入图片描述
二维数组在计算机的数据存储方式可以看成一张有行有列表格,而一维数组存储方式只是一条线性表。
在Java语言中,二维数组的声明方式如下:
数据类型[][] 变量名称=new 数据类型[第一维度长度][第二维度长度];(这里的第一维度长度代表行数,第二维度长度代表列数)
接下来我们通过一个范例来理解二维数组打包数据的方便之处:
【范例二维数组】
请设计一个Java程序,使用二维数组来存储生产的随机数。随机生成时还需要记录随机数重复的次数,请使用二维数组的索引值特性及while循环机制进行反向检查,以及找出重复次数最多的六个随机数。
解:一维数组实际上有两个位置存储变量,一个是下标处,一个是值处。那么二维数组的每一行同样也能存储两个变量,二维数组的每一行就是一个一维数组。
在这个题中,我们设置41列两行,每一行,用列下标来存储随机数,用列对应的值来存储次数。打乱第一行列下标和值对应关系,将数据进行升序排序,然后用最大的6个值分别和第二行的值进行一一匹配,从而找到最大的次数对应的下标(下标就是相应的随机数)。在这里我们仅需要使用遍历枚举算法,一个一个检查。

package 数组;

import java.util.Arrays;

//多维数组的应用
public class 二维数组_记录随机数 {
public static void main(String[] args) {
	//变量声明
	int intCreate=1000000;//产生随机数的次数
	int intRand;		  //产生的随机数号码
	int[][] intArray=new int[2][42];//存放随机数的数组
	//讲产生的随机数存放到数组中
	while(intCreate-->0)//这里的intCreate-->0等价与--intCreate>0,意思是循环n次
	{
		intRand=(int)(Math.random()*42);//生成取值范围为0到41的随机整数数,不包括42(Math.random()生成随机数的范围是 0 到 1 之间的 ,当然,不包括临界值,取不到1,可以取到0),
										//因为转化为int类型去除小数点后数字,41.小数被舍去
		intArray[0][intRand]++;//生成intRand随机数后,在纵坐标为intRand横坐标为0处的数值加1,表示随机数字出现次数
		intArray[1][intRand]++;//这一行代码同上一行代码作用一样,相当于把次数存储了两次,这样做是为了方便之后的查询
	}
	//对intArray数组第0行数据进行升序排序,这样做虽然把数据排序了,但是也打乱了intRand下标和次数的对应关系,不过没关系,我们在第1行仍然存储着intRand对应着的次数
	Arrays.sort(intArray[0]);
	//找出重复次数最多的6个随机数,从后向前查找
	for(int i=41;i>(41-6);i--) {
		//在第1行中检查和最大的六个数据相同的数据,找到对应的下标,这样便找到出现次数最多的几个下标号码
		for(int j=41;j>=0;j--) {
		if(intArray[0][i]==intArray[1][j]) {
			//当次数匹配时打印输出
			System.out.println("随机数"+(j+1)+"出现"+intArray[0][i]+"次");
			intArray[1][j]=0;//将找到的随机数对应的重复次数归0,方便下一个数据匹配时查询
			break;//退出内循环,继续外循环
			}
		
		}
	}
	
}
}

运行结果如下:
在这里插入图片描述
【范例二维数组之冒泡排序】
本来关于算法想另起一篇专项的博客,但是想到在数据结构这一部分算法同样是可以适用。这两者本来就是不可分割的一部分,相对来讲数据结构更基础。所以在基础部分我打算加入一些简单的算法,这样在以后讲算法专项的时候也能做到首尾呼应。
排序算法中的“冒泡排序”一般是我们第一个学的排序算法。这是最经典和最简单的排序算法。它是我们入门排序算法的重要基础,今天我们将要突破冒泡排序算法关键,成功入门计算机排序世界!
排序算法作用:给数据进行从小到大排序或者从大到小排序
(这里给大家提示一下,既然现在排序算法是给数据排序的,那么前提是不是我们得先存储好数据?所以我们再次领悟到了数据结构是算法基础)
“冒泡排序”算法:使大的数据一个一个排到数据后端,或者小的数据一个一个排到数据前端。(这里前后可以随意变化,只要你掌握透彻)
先上一张动态图片:
在这里插入图片描述
冒泡排序算法细讲:
冒泡排序算法主要针对于一维数组,其核心思想是从前到后(或者从后到前,一般是从前到后用)逐一两两之间比较大小,把最大的数一步一步移到最后。类似于找出最大数,只不过这里是移动最大数的位置。
c++代码如下:

int len=sizeof(array)/sizeof(array[0]);
for(int index=0;index+1<len-1;index++){//为了不越界,index+1需要小于len,也都能比较完
    if(array[index]>array[index+1]){//如果本位置的数大于后一个位置的数,交换两数位置
        swap(array[index],array[index+1]);//c++中可以直接用swap()函数交换
        }
    }

如果是用的Java,我们就得手动交换了,Java太高级,这种低端的交换没有配API,我把代码写上。

int len=array.length;
for(int index=0;index<len-1;index++){
    if(array[index]>array[index+1]){//如果本位置的数大于后一个位置的数,交换两数位置
           int temp=array[index];array[index]=array[index+1];array[index+1]=temp;//手动交换,放哪里都能用
        }
    }

现在我们已经学会了把一个最大数字移动到一维数组的最右端,接下来,我们知道把数组中的一个最大数移动到最后是完成不了全部从小到大排序的。所以我们开始下一轮“冒泡”,把剩下的数中的最大的数也移动到剩下的数的最右边。依次规律直到剩下的数只有一个就完成了所有排序。
讲完了原理,我来问一问同学一个数学问题,长度为n的数组,一共会有多少轮?
猜你已经想明白了,首先第一轮有n个数,第二轮剩下n-1个数,第三轮剩n-2个数…一直到第n-2轮剩下2个数,到n-1轮剩1个数时比较完成。如果你看成一直比较到没有剩的数字就有n轮,但是其实只剩一个数字时就已经好了,所以准确的说总共有n-1轮次。(分析轮次有多少不就是为了在之前第一轮排序中的算法外面再加一个外循环嘛)
分析完了计算原理,我们通过具体的代码实现:因为c++和Java循环语法一样,我就直接写c++了。同学们可以转化成自己的语言。

#include<iostream>
#define N 5
using namespace std;
void BubSort_test(int a[]){
    cout<<"正向排序"<<endl;
    for(int i=0;i<N;i++){//看这,外循环直接给了n次,多一次没关系,反正又不会移动
        for(int j=0;j+1<N-i;j++){//这里为了N-i其实就是不把最后的数放在比较范围了,只比较剩下的数字。i是从0开始的,第一轮冒泡就是全体比较。
            if(a[j]>a[j+1]){
                swap(a[j],a[j+1]);
            }
        }
        cout<<"第"<<i+1<<"轮冒泡排序:"<<endl;
        for(int i=0;i<N;i++){
            cout<<a[i]<<" ";
        }
        cout<<endl;
    }
}
void BubSort_testr(int a[]){
    cout<<"反向排序"<<endl;
    for(int i=0;i<N;i++){
        for(int j=N-1;j>i;j--){
            if(a[j]<a[j-1]){
                swap(a[j],a[j-1]);
            }
        }
        cout<<"第"<<i+1<<"轮冒泡排序:"<<endl;
        for(int i=0;i<N;i++){
            cout<<a[i]<<" ";
        }
        cout<<endl;
    }
}
int main(){
    int a[N]={5,4,3,2,1};
    BubSort_test(a);
    BubSort_testr(a);
}

结果如下:
在这里插入图片描述
冒泡算法就是这么用的,仔细想明白是不难的。接下来我们就要进入正题了,不知道你们有没有想过作者怎么在二维数组的位置讲一维数组排序?显然,我们的小目标是给二维数组“冒泡”!
其实吧,把二维数组转化成一维数组就行!
关键点在于如何转化,设二维数array1组行数为row,列数为col。一维数组为array2,array1[i][j]=array2[i×col+j]; 成功转化!我们把二维数组值赋给一维数组排序后,再赋值回来就行,肯定有小可爱想一维数组怎么赋值给二维数组呢?
…(给你的思考的时间)。好,揭晓答案了啊!array2[i×col+j]=array1[i][j];反过来赋值就行嘿嘿。
示例代码如下(c++版本):

#include<iostream>
using namespace std;
int main(){
int array1[2][3]={{6,5,4},{3,2,1}};//二行三列的二维数组
int array2[6];//六个元素的一维数组
for(int i=0;i<2;i++){
    for(int j=0;j<3;j++){
        cout<<array1[i][j]<<" ";
    }
   }
for(int i=0;i<2;i++){
    for(int j=0;j<3;j++){
            array2[i*3+j]=array1[i][j];
    }
}//二维数组转化为一维数组
for(int i=0;i<6;i++){
    for(int j=0;j+1<6-i;j++){
        if(array2[j]>array2[j+1]){
            int temp=array2[j];array2[j]=array2[j+1];array2[j+1]=temp;//交换
        }
    }
}
for(int i=0;i<2;i++){//一维数组转化为2维数组
    for(int j=0;j<3;j++){
        array1[i][j]=array2[i*3+j];
    }
}
cout<<endl;
for(int i=0;i<2;i++){//输出排序后的2维数组
    for(int j=0;j<3;j++){
        cout<<array1[i][j]<<" ";
    }
   }
}

运行结果如下:
在这里插入图片描述

3.三维数组(给同学们道歉,之前写的数组赋值顺序不正确,现在已经修改)
高中我们学过,点构成线,线构成面,面构成体。那么同样的道理,数据点连成线构成一维数组,一维数组线构成二维数组面,二维数组面构成三位数组体。如果数组为三维数组时,我们可以看作是一个立方体。
在这里插入图片描述

在这里我们需要注意二维数组的起始点是左上角因为行数增加二维数组指针向下移动,列数增加二维数组指针向右移动。三位数组的起始点也是左上内测顶点, X增加向右移动,Y增加向前移动,Z增加向下移动。二维数组的每一个元素占一个小方框,三维数组的每一个元素占一个小方格。
【范例三维数组】
这道题之前我们先说明数组赋值方式:
一维数组:
{元素1(x=0),元素2(x=1),元素3(x=2)…}
一维数组从左向右依次赋值
二维数组:
{
{元素1(x=0,y=0),元素2(x=0y=1)},{元素1(x=1,y=0),元素2(x=1,y=1)
},{元素1(x=1,y=0),元素2(x=1,y=1)}
}
二维数组先填满第一行,再填满第二行,然后填满第三行。。。直到填满整个面。
三维数组:
{
{{元素1(x=0,y=0,z=0),元素2(x=0,y=1,z=0)},{元素1(x=1,y=0,z=0),元素2(x=1,y=1,z=0)}},
{{元素1(x=0,y=0,z=1),元素2(x=0,y=1,z=1)},{元素1(x=1,y=0,z=1),元素2(x=1,y=1,z=1)}},
{{元素1(x=0,y=0,z=2),元素2(x=0,y=1,z=2)},{元素1(x=1,y=0,z=2),元素2(x=1,y=1,z=2)}}
}
从三维数组的赋值我们可以看出,三维数组赋值顺序是从立方体顶面开始,从一行开始从左到右先填满第一行立方体再填满第二行立方体,当顶面立方体填完之后向下移动一个面再继续填满第1行立方体然后填满第二行立方体直到填满第二面所有立方体再向下移动一个面,以此类推…
假设一个三维数组元素内容如下:
int num[][][]={
{{33,45,67},{23,71,56},{55,38,66}},
{{21,9,15}),{38,69,18},{90,101,89}}
}
请设计一个Java程序,利用三重嵌套循环来找出此2×3×3(3行3列2纵)三维数组中所存储数值中的最小值。
解:通过这一个题我们需要掌握三维数组的遍历顺序,三维数组的遍历顺序和赋值顺序是一样的。并且我们要知道数组三个下标代表的含义num[X][Y][Z];同理,在二维数组中的下标含义:num[X][Y];
在接下来的程序中,我们将运用三层循环遍历出三维数组中所有数据,并且找到最小值。在之前我提醒同学们,在循环嵌套中先运行最底层循环再运行外层循环,所以Y的遍历放在最底层循环,Z的遍历放在最外层循环,X的遍历放在中层循环。代码如下:

package 数组;
//找出三维数组中存储数值中的最小值
public class 三维数组_找最小值 {
	public static void main(String[] args) {
		int num[][][]= {{{33,45,67},{23,71,56},{22,38,66}},{{21,9,15},{38,69,18},{90,101,89}}};//声明三维数组
		int min=num[0][0][0];//设置min为num数组的第一个元素
		System.out.print("数组元素一共有:");
		for(int i=0;i<2;i++) //i遍历Z坐标
		{
			for(int j=0;j<3;j++)//j遍历Y坐标
			{
				for(int k=0;k<3;k++)//k遍历X坐标
				{
					System.out.print(num[i][j][k]+"\t");
					if(min>=num[i][j][k]) {
						min=num[i][j][k];//使用三层循环找出最小值
					}
				}
			}
		}
		System.out.print('\n');
		System.out.println("最小值="+min);
	}
}


运行结果:
在这里插入图片描述
4.n维数组
有了一维、二维、三维数组,当然也可能有四维、五维或更多维数的数组。不过因为受限于计算机内存,通常程序设计语言中数组声明都会有维数的限制。所以我们把三维以上的数组归纳为n维数组。在Java语言中n维数组的声明方式如下:
数据类型[][][]…[] 变量名=new 数据类型[第一维长度][第二维长度]…[第n维长度];
因为n维数组在实际编程中使用不多,这里就讲解一个简单的地址计算范例:
【n维数组简单范例】
在4维数组A[4][6][5][3]中,且阿尔法=200,d=1.并已知是以列为主排列(Column-major),求A[3,1,3,1]地址。
答:由于本题中原本就是数组的简单表示法,所以不需要转换,直接带入计算公式:
Loc(A[3][1][3][1])=200+(1-1)×5×6×4+(3-1)×6×4+(1-1)×4+3-1=250
5.数组数据结构大boss之矩阵
矩阵本质上是一个二维数组,学习矩阵的运算实际上就是学会使用二维数组之间的运算,接下来我们来一个一个学习二维数组之矩阵运算。
(1)矩阵相加
矩阵的相加运算较为简单,前提是相加的两个矩阵对应的行数与列数都必须像等,而相加后矩阵的行数与列数也是相同的。如Amxn+Bmxn=Cmxn。下面我们来实际看一个矩阵相加的的例子。
【范例矩阵相加】
请设计一个Java程序通过二维数组来实现{{1,3,5},{7,9,11},{13,15,17}}和{{9,8,7},{6,5,4},{3,2,1}}相加,并得到结果。
分析:矩阵相加实际上只要将矩阵对应元素相加就可以了。代码如下:

package 数组;

public class 矩阵相加 {
	//先定义一个矩阵相加函数
	public static void MatrixAdd(int arrA[][],int arrB[][],int arrC[][],int dimX,int dimY) {//分别传入三个矩阵和矩阵行数、列数
		int row,col;//定义用于赋值用的变量行数和列数
		if(dimX<=0||dimY<=0) {
			System.out.println("矩阵维数必须大于0");
			return;
		}
		for(row=1;row<=dimX;row++) {
			for(col=1;col<=dimY;col++) {
				arrC[row-1][col-1]=arrA[row-1][col-1]+arrB[row-1][col-1];
			}
		}
	}
	public static void main(String[] args) {
		int i;
		int j;
		final int ROWS=3;
		final int COLS=3;
		int[][] A= {{1,3,5},{7,9,11},{13,15,17}};
		int[][] B= {{9,8,7},{6,5,4},{3,2,1}};
		int[][] C=new int[ROWS][COLS];
		System.out.println("[矩阵A的各个元素]");//输出矩阵A的内容
		for(i=0;i<3;i++) {
			for(j=0;j<3;j++) {
				System.out.print(A[i][j]+"\t");
			}
			System.out.println();
		}
		System.out.println("[矩阵A的各个元素]");//输出矩阵B的内容
		for(i=0;i<3;i++) {
			for(j=0;j<3;j++) {
				System.out.print(B[i][j]+"\t");
			}
			System.out.println();
		}
		MatrixAdd(A,B,C,3,3);//矩阵A,B相加得到和C
		System.out.println("[矩阵C的各个元素]");//输出矩阵C的内容
		for(i=0;i<3;i++) {
			for(j=0;j<3;j++) {
				System.out.print(C[i][j]+"\t");
			}
			System.out.println();
		}
		
	}
}

运行结果如下:
在这里插入图片描述
(2)矩阵相乘
两个矩阵A与B的相乘受到某些条件的限制。首先A为m×n的矩阵,B就必须为n×p的矩阵。即相乘矩阵1的列数必须等于相乘矩阵2的行数。相乘结果为m行p列的新矩阵3。即和矩阵1行数相等,和矩阵2列数相等。
【范例矩阵相乘】
请设计一个Java程序来实现两个可自行输入矩阵维数的矩阵相乘过程,并显示输出结果。
分析:设矩阵A[3][3]×B[3][3]=B[3][3].其中B[0][0]=A[0][0]×B[0][0]+A[0][1]×B[1][0]+A[0][1]×B[0][2]。从这里可以看出,新矩阵的第0行0列元素是矩阵A0行所有元素与矩阵B第0列所有元素对应相乘的结果。以此类推,新矩阵的第i行j列元素是矩阵A第i行所有元素与矩阵B第j列所有元素对应相乘的结果。
代码如下:

package 数组;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class 矩阵相乘 {
public static void MaltrixMultiply(int arrA[][],int arrB[][],int arrC[][],int M,int N,int P) {//设置相乘函数
	int i,j,k,Temp;
	if(M<=0||N<=0||P<=0) {
		System.out.println("[错误:维数M,N,P必须大于0]");
		return;
	}
	for(i=0;i<M;i++) {//新矩阵行数,即A的行数
		for(j=0;j<P;j++) {//新矩阵列数,即B的列数
			Temp=0;//赋值给arrC[][]后Temp置零
			for(k=0;k<N;k++) {//通过一个参数k来遍历A的某一行所有元素和B的某一列所有元素,这里我们再次理解了为什么A的列数要等于B的行数
				Temp=Temp+arrA[i][k]*arrB[k][j];//新矩阵第i行j列的元素是A的第i行所有元素与B的第j列所有元素对应相乘的和
			}
					arrC[i][j]=Temp;//将对应相乘相加的和temp赋值给arrC[i][j]
		}
	}
}
public static void main(String[] args) throws IOException {
	int M,N,P;
	int i,j;
	String strM;
	String strN;
	String strP;
	String tempstr;
	BufferedReader keyin=new BufferedReader(new InputStreamReader(System.in));
	System.out.println("请输入矩阵A的维数(M,N):");
	System.out.println("请先输入矩阵A的M值:");
	strM=keyin.readLine();
	M=Integer.parseInt(strM);
	System.out.println("接下来输入矩阵A的N值:");
	strN=keyin.readLine();
	N=Integer.parseInt(strN);
	int A[][]=new int[M][N];
	System.out.println("[请输入矩阵A的各个元素]");
	System.out.println("注意!每输入一个值都需要按下Enter键确认输入");
	for(i=0;i<M;i++) {
		for(j=0;j<N;j++) {
			System.out.println("a"+i+j+"=");
			tempstr=keyin.readLine();
			A[i][j]=Integer.parseInt(tempstr);
		}
	}
	System.out.println("请输入矩阵B的维数(N,P):");
	System.out.println("请先输入矩阵B的N值:");
	strN=keyin.readLine();
	N=Integer.parseInt(strN);
	System.out.println("接下来输入矩阵B的P值:");
	strP=keyin.readLine();
	P=Integer.parseInt(strP);
	int B[][]=new int[N][P];
	System.out.println("[请输入矩阵B的各个元素]");
	System.out.println("注意!每输入一个值都需要按下Enter键确认输入");
	for(i=0;i<N;i++) {
		for(j=0;j<P;j++) {
			System.out.println("b"+i+j+"=");
			tempstr=keyin.readLine();
			B[i][j]=Integer.parseInt(tempstr);
		}
	}
	int C[][]=new int[M][P];
	MaltrixMultiply(A,B,C,M,N,P);
	System.out.println("A×B的结果是");
	for(i=0;i<M;i++) {
		for(j=0;j<P;j++) {
			System.out.print(C[i][j]+"\t");
		}
		System.out.println();
	}
	
}
}

运行结果如下:
在这里插入图片描述
在这里插入图片描述
(3)转置矩阵
“转置矩阵”(At)就是把原矩阵的行坐标元素与列坐标元素相互调换,假设At为A的转置矩阵,则有At[i][j]=A[j][i].
【范例转置矩阵】
请设计一个Java程序,可任意输入m值和n值,来实现一个m×n二维数组的转置矩阵
用一个双重循环赋值就行。At[i][j]=A[j][i]

package 数组;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class 转置矩阵 {
	public static void main(String[] args) throws IOException {
		int M,N,row,col;
		String strM;
		String strN;
		String tempstr;
		BufferedReader keyin=new BufferedReader(new InputStreamReader(System.in));
		System.out.println("[请输入矩阵的维度]");
		System.out.println("请输入矩阵的维度M:");
		strM=keyin.readLine();
		M=Integer.parseInt(strM);
		System.out.println("请输入矩阵维度N:");
		strN=keyin.readLine();
		N=Integer.parseInt(strN);
		int arrA[][]=new int[M][N];
		int arrB[][]=new int[N][M];
		System.out.println("[请输入矩阵内容]");
		for(row=1;row<=M;row++) {
			for(col=1;col<=N;col++) {
				System.out.println("a"+row+col+"=");
				tempstr=keyin.readLine();
				arrA[row-1][col-1]=Integer.parseInt(tempstr);
			}
		}
		System.out.println("[输入矩阵内容为]\n");
		for(row=1;row<=M;row++) {
			for(col=1;col<=N;col++) {
				System.out.print(arrA[row-1][col-1]);
				System.out.print("\t");
			}
			System.out.println();
		}
		//进行矩阵转置的操作
		for(row=1;row<=N;row++) {
			for(col=1;col<=M;col++) {
				arrB[row-1][col-1]=arrA[col-1][row-1];
			}
		}
		System.out.println("[转置矩阵的内容为]");
		for(row=1;row<=N;row++) {
			for(col=1;col<=M;col++) {
				System.out.print(arrB[row-1][col-1]);
				System.out.print("\t");
			}
			System.out.println();
		}
	}
}

运行结果如下:
在这里插入图片描述
在这里插入图片描述

(4)稀疏矩阵之压缩矩阵
什么是稀疏矩阵呢?
简单地说:“如果一个矩阵中的大部分元素为零的话,就被称为稀疏矩阵”。
对于稀疏矩阵而言,实际存储的数据很少,如果在计算机中使用传统的二维数组方式来存储稀疏矩阵,就会十分浪费计算机的内存空间。特别是当矩阵很大时。提高内存空间利用率的方法是利用三项式的数据结构,我们把每一个非零项以(i,j,item_value)来表示。就是假如一个稀疏矩阵有n个非零项,那么可以利用一个A[n][3]的二维数组来存储这些非零项,我们把这样的矩阵叫做压缩矩阵
左边稀疏矩阵,右边压缩矩阵的元素索引部分
压缩矩阵中,第一行,A[0][1]存储这个稀疏矩阵的行数,A[0][2]存储这个稀疏矩阵的列数,而A[0][3]则是此稀疏矩阵非零项的总数。另外从第二行开始,每一个非零项以(i,j,item-value)来表示。其中i为此矩阵非零项所在的行数,j为此矩阵非零项所在的列数,item-value则为此非零项的值。(在压缩矩阵中,第一行数字表示的含义和下面行数数字表示的含义不同,我们需要区分)
【范例压缩矩阵】
请设计一个Java程序来利用三项式(3-tuple)数据结构,并压缩6×6稀疏矩阵,以减少内存不必要的浪费。
利用随机数来生成稀疏矩阵,通过遍历扫描稀疏矩阵找到其中的非零元素位置和值存储到压缩矩阵中。

package 数组;

public class 压缩矩阵 {
	public static void main(String[] args){
	final int _ROWS=8;//稀疏矩阵定义行数
	final int _COLS=9;//稀疏矩阵定义列数
	final int _NOTZERO=8;//定义稀疏矩阵中不为0的元素个数
	int i,j,tempRW,tempCL,tempNZ;//定义遍历用变量
	int temp=1;//定义并初始化压缩矩阵行数
	int Sparse[][]=new int[_ROWS][_COLS];//声明稀疏矩阵
	int Compress[][]=new int[_NOTZERO+1][3];//声明压缩矩阵
	for(i=0;i<_ROWS;i++) {
		for(j=0;j<_COLS;j++) {
			Sparse[i][j]=0;//将稀疏矩阵置零
		}
	}
	tempNZ=_NOTZERO;
	for(i=1;i<tempNZ+1;i++) {
		tempRW=(int)(Math.random()*100);
		tempRW=(tempRW%_ROWS);
		tempCL=(int)(Math.random()*100);
		tempCL=(tempCL%_COLS);
		if(Sparse[tempRW][tempCL]!=0)
		{
			tempNZ++;
		}//如果随机到了重复的下标,那么循环次数加一
		Sparse[tempRW][tempCL]=i;//随机产生稀疏矩阵中非零元素的值
	}
	System.out.println("[稀疏矩阵的各个元素]");//输出稀疏矩阵的各个元素
	for(i=0;i<_ROWS;i++) {
		for(j=0;j<_COLS;j++) {
			System.out.print(Sparse[i][j]+" ");
		}
		System.out.println();
	}
	/*开始压缩矩阵*/
	Compress[0][0]=_ROWS;
	Compress[0][1]=_COLS;
	Compress[0][2]=_NOTZERO;
	for(i=0;i<_ROWS;i++) {
		for(j=0;j<_COLS;j++) {
			if(Sparse[i][j]!=0) {
				Compress[temp][0]=i;
				Compress[temp][1]=j;
				Compress[temp][2]=Sparse[i][j];
				temp++;
			}
		}
	}
	System.out.println("[稀疏矩阵压缩后的内容为]");//输出压缩矩阵的各个元素
	for(i=0;i<_NOTZERO+1;i++) {
		for(j=0;j<3;j++) {
			System.out.print(Compress[i][j]+" ");
		}
		System.out.println();
	}
	
}
}

运行结果如下:
在这里插入图片描述

(5)上三角矩阵
上三角矩阵就是一种对角线以下元素都为0的n×n矩阵(不包括对角线)。其中又可分为右上三角矩阵与左上三角矩阵。由于上三角矩阵仍有许多元素为0,为了避免浪费内存空间,我们可以把三角形矩阵的二维模式存储在一维数组中。
【范例右上三角矩阵压缩为一维数组】
请设计一个Java程序,将右上三角矩阵压缩为一维数组。
二维数组之前转化成一维数组我们在冒泡中讲到过,这里是将特殊的二维矩阵右上三角矩阵压缩为一维数组,压缩的意思是需要舍去等于0的部分,我们需要在下标上做一点变化。详细请看代码。

package 数组;

public class 右上三角矩阵压缩成一维数组 {
	private int[] arr;
	private int array_size;
	public  右上三角矩阵压缩成一维数组(int[][] array) {
		 array_size = array.length;
		 arr=new int[array_size*(1+array_size)/2];//这里加1的目的是防止奇数除以二被舍去小数点部分使得空间不够
		 int index=0;
		 for(int i=0;i<array_size;i++) {
			 for(int j=0;j<array_size;j++) {
				 if(array[i][j]!=0) {
					 arr[index++]=array[i][j];
				 }
			 }
		 }
	}
	public int getValue(int i,int j) {
		int index=array_size*i-i*(i+1)/2+j;//i*(i+1)/2是之前所有没有存的数据个数,等差数列求和公式
		return arr[index];
	}
	public static void main(String[] args) {
		int array[][]= {
				{7,8,12,21,9},
				{0,5,14,17,6},
				{0,0,7,23,24},
				{0,0,0,32,19},
				{0,0,0,0,8}
				};
		右上三角矩阵压缩成一维数组 Array_object=new 右上三角矩阵压缩成一维数组(array);
		int i=0,j=0;
		System.out.println("======================================================");
		System.out.println("上三角型矩阵:");
		for(i=0;i<Array_object.array_size;i++) {
			for(j=0;j<Array_object.array_size;j++) {
				System.out.print("\t"+array[i][j]);
			}
			System.out.println();
		}
		System.out.println("======================================================");
		System.out.println("以一维数组的方式表示为:");
		System.out.print("\t"+"[");
		for(i=0;i<Array_object.array_size;i++) {
			for(j=0;j<Array_object.array_size;j++) {
				System.out.print(" "+Array_object.getValue(i, j));
			}
		}
		System.out.print(" ]");
		System.out.println();
	}
}

运行结果为:
在这里插入图片描述

(6)下三角矩阵
与上三角矩阵相反,就是一种对角线以上元素都为0的n×n矩阵。其中也可以分为左下三角矩阵和右下三角矩阵。
【范例左下三角矩阵压缩成一维数组】
请设计一个Java程序,将左下三角矩阵压缩为一个一维数组。
下三角型矩阵压缩的代码和上三角型矩阵压缩的代码一模一样。但是和之前不同的是这里通过getValue()方法中的i、j取到的值和二维数组中的元素下标不对应。但是从总体上讲筛选一维数组的长度和上三角矩阵长度一样,传给getValue方法的i、j值可以把筛选后的一维数组遍历一遍输出。甚至于不写getValue方法直接从头到尾遍历一遍筛选后的一维数组就行。

package 数组;

public class 右上三角矩阵压缩成一维数组 {
	private int[] arr;
	private int array_size;
	public  右上三角矩阵压缩成一维数组(int[][] array) {
		 array_size = array.length;
		 arr=new int[array_size*(1+array_size)/2];//这里加1的目的是防止奇数除以二被舍去小数点部分使得空间不够
		 int index=0;
		 for(int i=0;i<array_size;i++) {
			 for(int j=0;j<array_size;j++) {
				 if(array[i][j]!=0) {
					 arr[index++]=array[i][j];
				 }
			 }
		 }
	}
	public int getValue(int i,int j) {
		int index=array_size*i-i*(i+1)/2+j;//i*(i+1)/2是之前所有没有存的数据个数,等差数列求和公式。这里没有做到和二维数组下标对应,但是不影响。
		return arr[index];
	}
	public static void main(String[] args) {
		int array[][]= {
				{76,0,0,0,0},
				{54,51,0,0,0},
				{23,8,26,0,0},
				{43,35,28,18,0},
				{12,9,14,35,46}
				};
		右上三角矩阵压缩成一维数组 Array_object=new 右上三角矩阵压缩成一维数组(array);
		int i=0,j=0;
		System.out.println("======================================================");
		System.out.println("下三角型矩阵:");
		for(i=0;i<Array_object.array_size;i++) {
			for(j=0;j<Array_object.array_size;j++) {
				System.out.print("\t"+array[i][j]);
			}
			System.out.println();
		}
		System.out.println("======================================================");
		System.out.println("以一维数组的方式表示为:");
		System.out.print("\t"+"[");
		for(i=0;i<Array_object.array_size;i++) {
			for(j=0;j<Array_object.array_size;j++) {
				System.out.print(" "+Array_object.getValue(i, j));
			}
		}
		System.out.print(" ]");
		System.out.println();
	}
}

运算结果:
在这里插入图片描述

(7)带状矩阵
带状矩阵是一个矩阵中右上三角一部全为0,左下三角一部分全为0,成对称分布。就像海带一样的矩阵。这种矩阵用得比较少。我们就了解一下。
在这里插入图片描述
5.数组与多项式
首先我们得明白多项式是什么,然后再弄清楚多项式和数组的关系。
多项式:P(x)=anx^n+ an-1x^(n-1)+…+a1x+a0,这个多项式就被称为n次多项式。
存储多项式有两种方式:
(1)使用一个n+2长度的一维数组来存放,数组的第一个位置存储最大指数n项的次数,其他位置按照指数n递减顺序存储对应的系数。
使用这种表示法的优点是比较方便,但是大部分系数为0就浪费存储空间。
(2)只存储多项式中的非零项。如果有m项非零项,则使用2m+1长的数组来存储每一个非零项的指数和系数,但数组的第一个元素则为此多项式非零项的个数。
【范例多项式加法】
这里用第一种方法,相加比较方便。

package 数组;
public class 多项式加法 {
	final static int ITEMS=6;//设置相加数组长度为6
	public static void PrintPloy(int Ploy[],int items) {
		int i,MaxExp;//MaxExp表示次数,从最大次数开始
		MaxExp=Ploy[0];
		for(i=1;i<=Ploy[0]+1;i++) {
			MaxExp--;
		if(Ploy[i]!=0) {
			if((MaxExp+1)!=0) {
				System.out.print(Ploy[i]+"X^"+(MaxExp+1));
				}else {
					System.out.print(Ploy[i]);
				}
			if(MaxExp>=0) {
				System.out.print('+');//如果不是次数为0的项,后面加‘+’
			}
			}
		}
		System.out.println();
	}
	public static  void PloySum(int Ploy1[],int Ploy2[]) {
		int i;
		int result[]=new int[ITEMS];
		result[0]=Ploy1[0];
		for(i=1;i<=Ploy1[0]+1;i++) {
			result[i]=Ploy1[i]+Ploy2[i];//等幂次系数相加
		}
		PrintPloy(result,ITEMS);
	}
	public static void main(String[] args) {
		int[] PloyA= {4,3,7,0,6,2};//声明多项式A
		int[] PloyB= {4,1,5,2,0,9};//声明多项式B
		System.out.print("多项式A=>");
		PrintPloy(PloyA,ITEMS);
		System.out.print("多项式B=>");
		PrintPloy(PloyB,ITEMS);
		System.out.print("A+B=>");
		PloySum(PloyA,PloyB);
	}
}

运行结果如下
在这里插入图片描述

数组部分大概就写到这里了,接下来我会继续写链表结构。夯实基础,共同进步!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吴澳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值