for
循环,但是我可以进一步减少它吗?有没有更优雅的解决方案?public class Diamond {
static boolean cont = true;
public static void main (String[] args) {
Scanner input = new Scanner(System.in);
while (cont) {
System.out.print("Width: ");
int width = input.nextInt();
int lines = width;
System.out.println();
for (int line = 0; line < lines; line++) {
for (int spaces = 0; spaces < Math.abs(line - (lines / 2)); spaces++) {
System.out.print(" ");
}
for (int marks = 0; marks < width - 2 * (Math.abs(line - (lines / 2))); marks++) {
System.out.print("x");
}
System.out.println();
}
System.out.println();
}
}
}
#1 楼
我们可以做一些清理工作。这是我要提取到自己的方法中的东西。处理通过
main()
方法获取用户输入,然后将其传递给drawDiamond()
方法。您的
for
循环分为在行,空格和标记上迭代。我们可以简化为行和列,一次可以遍历每个单独的单元。这还将在最终方法中消除您的
System.out.println()
之一。我们可以简化在哪里印刷钻石的数学运算。
if ((column == Math.abs(row - half)) || (column == (row + half)) || (column == (sqr - row + half - 1)))
最终方法:
void drawDiamond(int sqr)
{
int half = sqr/2;
for (int row=0; row<sqr; row++)
{
for (int column=0; column<sqr; column++)
{
if ((column == Math.abs(row - half)) || (column == (row + half)) || (column == (sqr - row + half - 1)))
{
System.out.print("*");
}
else System.out.print(" ");
}
System.out.println();
}
}
#2 楼
您知道,很高兴看到代码能够执行所声明的内容,并且这是一个很好的简单任务,仍然需要花些时间来抓....但是我假设您是Java初学者。基本知识
遍历一些基本内容...
方法外部已将
cont
变量声明为静态变量,但唯一的地方是使用的是方法内部。在这种情况下,应将声明移至main
方法内。另外,没有任何改变该状态的程序,因此该程序可以运行,并且可以运行,这是可以的(初学者)。您无需关闭
input
扫描仪。同样,这可能是因为该程序永远不会完成,但是Java7中有很多不错的方法可以确保它整洁地发生,并且无需花费太多精力。您应该验证用户输入。如果用户输入负整数,则实际上可以(程序不执行任何操作)。更令人担忧的是,如果用户输入2000000000,则应设置一个上限。您可以将此形状称为“钻石”,但实际上它是一个正方形。宽度和高度是相同数量的字符。您只需要一个变量,
lines
或width
,而不是两个都使用。混淆了您同时拥有
line
和lines
变量。如果您改用lines
,则不需要width
,因此请消除它(也是因为用户提示是“ Width:”)。好,那是一些相对简单的东西。使用上面的建议来弄乱代码,我会得到:
public static void main (String[] args) {
boolean cont = true;
try (Scanner input = new Scanner(System.in)) {
while (cont) {
System.out.print("Width: ");
int width = input.nextInt();
System.out.println();
if (width > 100) {
System.out.println("Width too wide, reducing to 100");
width = 100;
}
for (int line = 0; line < width; line++) {
for (int spaces = 0; spaces < Math.abs(line - (width / 2)); spaces++) {
System.out.print(" ");
}
for (int marks = 0; marks < width - 2 * (Math.abs(line - (width / 2))); marks++) {
System.out.print("x");
}
System.out.println();
}
System.out.println();
}
}
}
算法
好的,现在,一些算法问题:
System.out.print(...)
和println
变体实际上确实很慢。从内部循环调用它们是性能的实际问题,并且是学习的坏习惯。这些方法锁定控制台输出,并且对其他线程也不好。在可能的情况下,应始终将字符打印批处理成更大的语句。有时,拿走东西比添加东西容易....(含糊的提示)。
通过一些技巧,我们可以解决循环中的许多复杂性。这是一个建议:
建立两个字符串,一个为空格,另一个为“ x”字符。每个参数至少应与我们所需的最长值一样长。
遍历行并使用上述两个字符串中的每个字符串的一部分。
逻辑与您的逻辑完全相同除了我有很大的事情我会使用一部分,而你却一点一点地建立起来。重要的部分是Math.abs(...)语句与以前的版本相同....它们是我们构建的值的限制。
这是一种实现方法:
public static void main (String[] args) {
boolean cont = true;
try (Scanner input = new Scanner(System.in)) {
while (cont) {
System.out.print("Width: ");
int width = input.nextInt();
System.out.println();
if (width > 100) {
System.out.println("Width too wide, reducing to 100");
width = 100;
}
char[] spaces = new char[width / 2];
char[] exes = new char[width];
Arrays.fill(spaces, ' '); // now an array of spaces
Arrays.fill(exes, 'x'); // now an array of 'x'
for (int line = 0; line < width; line++) {
String pad = new String(spaces, 0, Math.abs(line - (width / 2)));
String fill = new String(exes, 0, width - 2 * (Math.abs(line - (width / 2))));
System.out.println(pad + fill);
}
System.out.println();
}
}
}
这只是您要考虑的问题.....
#3 楼
人们已经对语法,程序结构等进行了许多重要的研究。但是,我认为您可以使循环更简单易懂:int halfheight = (width + 1) / 2;
int spaces = halfheight;
int exes = width - 2 * spaces;
for (int i = 0; i < halfheight; i++)
{
spaces--;
exes += 2;
// You could use the approaches suggested by other folk here instead of inner loops
for (int s = 0; s < spaces; s++)
System.out.print(" ");
for (int x = 0; x < exes; x++)
System.out.print("X");
System.out.print("\n");
}
for (int i = 0; i < halfheight - 1; i++)
{
spaces++;
exes -= 2;
for (int s = 0; s < spaces; s++)
System.out.print(" ");
for (int x = 0; x < exes; x++)
System.out.print("X");
System.out.print("\n");
}
(我相信这可以处理与您完全相同的奇数和偶数宽度,只是在偶数宽度的情况下它不会输出初始空白行。我认为这是人工制品,而不是规范的一部分。)
我唯一要做的“算术”是在初始化中,然后循环使用无需任何计算即可完全清除的数量,并以完全显而易见的方式更改每次迭代中的exe和空格数。用
abs
和整数除法进行的各种计算似乎并不复杂,但是,当您调试或尝试对代码进行稍微修改时,您会浪费时间思考不同的情况(正,负,奇,偶,初次迭代,最后一次迭代),可能会发现自己只是在测试不同的值something
,something + 1
,something - 1
等,而不是能够在边缘情况下看到每个变量的精确交互。请注意,我有6个for循环,并且代码比您或其他人的相应部分长得多。并不是减少这些使代码清晰。事实是很容易掌握每个函数所做的事情,而无需引用有助于维护者的循环之外的(很多)东西。恕我直言(我知道有些人会不同意),这里的重复很少且对称地使用,因为它比我将其排除在外要优雅得多。
#4 楼
将您的所有代码都放入main()
是不好的做法。在这里,您还有另一个问题,即main()
要做三件事:提示输入,打印菱形和循环。 (顺便说一句,您提供了从无穷循环中退出的无错误方法。)将这些任务混合到一个函数中将使它变得不可能,例如,无法以其他方式重用您的菱形印刷例程(例如使连续的垂直菱形字符串(由几个菱形组成)。@ syb0rg提供了一种从打印例程中分离输入例程的方法。我会进一步建议在Java中建立面向对象的接口是一种好习惯。这是一种方法:
private static int promptWidth(Scanner input) {
System.out.print("Width: ");
return input.hasNextInt() ? input.nextInt() : 0;
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int width;
// Exit cleanly on EOF, or if anything other than a positive
// integer is entered.
while ((width = promptWidth(input)) > 0) {
System.out.println();
new Diamond(width).draw(System.out);
System.out.println();
}
input.close();
}
换句话说,
Diamond
知道如何将自己吸引到System.out
。这是另一种方法:
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int width;
// Exit cleanly on EOF, or if anything other than a positive
// integer is entered.
while ((width = promptWidth(input)) > 0) {
int width = input.nextInt();
System.out.println();
System.out.println(new Diamond(width));
System.out.println();
}
input.close();
}
,这依赖于
Diamond
的.toString()
方法,您必须使用StringBuilder
来实现。#5 楼
您确实可以在一个循环中完成它。由于我不会讲Java,所以我将使用C#语法。
public static void Main()
{
string valueString;
int width;
do
{
Console.Write("Width:");
valueString = Console.ReadLine();
} while (!int.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out width) && width > 0 && width <= 100);
int half = (int)((double)width/2+0.5);
string pattern = new string(' ',width)+new string('*',width);
for (int row = 1; row <= width; row++)
{
int spaces = width-Math.Abs(half - row);
Console.WriteLine(pattern.Substring(spaces, spaces));
}
}
为了您的方便而翻译成Java ....
public static void main (String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
int width;
do
{
System.out.print("Width:");
width = scanner.nextInt();
} while (width < 0 || width > 100);
char[] blanks = new char[width];
char[] exes = new char[width];
Arrays.fill(blanks, ' ');
Arrays.fill(exes, 'x');
String pattern = new String(blanks) + new String(exes);
int half = (int)((double)width / 2 + 0.5);
for (int row = 1; row <= width; row++)
{
int spaces = width - Math.abs(half - row);
// Java substring has arguments (first, last), not (first, length).
System.out.println(pattern.substring(spaces, spaces + spaces));
}
System.out.println();
}
}
评论
\ $ \ begingroup \ $
是的,我已经对此进行了测试,输出就是您所期望的,请自己尝试。 space的值是在循环内部计算的,并且每次迭代都不同。诀窍是构造一个包含X个前导空格和X个菱形字符的字符串,在每个循环中,我们都从字符串中取出不同的部分。
\ $ \ endgroup \ $
– Marc Selis
2014年1月30日15:26
\ $ \ begingroup \ $
哦....(...一分钱掉了...)这很聪明(我已经在调试中逐步执行了您的代码。)。 ;-) 感谢那。如果可以的话,将+2。
\ $ \ endgroup \ $
–rolfl
2014年1月30日15:37
评论
\ $ \ begingroup \ $
同意第一句话。多年前,我花了2个小时在公共汽车上解决了抽奖钻石问题,而现在我自己解决了这个问题,我对此感到非常高兴。
\ $ \ endgroup \ $
–艾肯·雅西(AycanYaşıt)
2014年1月30日8:39
\ $ \ begingroup \ $
称其为“钻石”并非不正确。实际上,正方形像钻石一样新颖而令人兴奋!
\ $ \ endgroup \ $
– 200_success
2014年1月30日12:43
\ $ \ begingroup \ $
如果将char数组替换为最大长度的String文字,则可以避免Arrays.fill()调用,而只是采用子字符串,这样可以保存新String(char [])的基础数组副本。
\ $ \ endgroup \ $
– Bowmore
2014年1月31日0:00