Printing numbers in a pyramid pattern(一)

本文深入探讨了程序设计中的核心技巧与算法实现方法,包括数据结构、算法设计、版本控制、项目管理等多个方面,旨在帮助开发者提升编程能力与效率。

Description
Write a program that reads an interger n, then display one of the following patterns.
Pattern 1
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6

Pattern 2
1 2 3 4 5 6
1 2 3 4 5
1 2 3 4
1 2 3
1 2
1

Pattern 3
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6

Pattern 4
1 2 3 4 5 6
1 2 3 4 5
1 2 3 4
1 2 3
1 2
1

Input
An integer n (1<=n<=4).

Output
Pattern n.
You should specify the width of each number’s print field to 3, justify the output to right.

Sample Input
Copy sample input to clipboard
1
Sample Output
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6

代码实现:

#include<iostream>
using namespace std;

void  fun1(int rows)
{
    for(int i = 1; i <= rows; i++){
        for(int j = 1; j <= i; j++){
            cout << "  " << j;   //两个空格
        }
        cout << endl;
    }
}

void fun2(int rows)
{
    for(int i = rows; i >= 1; i--){
        for(int j = 1; j <= i; j++){
            cout << "  " << j;    //两个空格
        }
        cout << endl;
    }
}

void fun3(int rows)
{
    for(int i = rows; i >= 1; i--){
        for(int j = 0; j < i-1; j++){
            cout << "   ";  //三个空格 
        }
        for(int j = 1; j <= (rows+1)-i; j++){
            cout << "  " << j;  //两个空格 
        }
        cout << endl;
    }
}

void fun4(int rows)
{
    for(int i = 1; i <= rows; i++){
        for(int j = 0; j < i-1; j++){
            cout << "   ";
        }
        for(int j = 1; j <= (rows+1)-i; j++){
            cout << "  " << j;
        }
        cout << endl;
    }   
} 


int main()
{
    int n;
    while(cin >> n){
        switch(n){
            case 1: fun1(6); break;
            case 2: fun2(6); break;
            case 3: fun3(6); break;
            case 4: fun4(6); break; 
        }
    }
    return 0;
}
<think>嗯,用户想用Tkinter实现个数字金字塔,行数根据窗口大小动态变化,还要动态创建和销毁组件来调整布局。首先,我得理解需求。数字金字塔通常是每行显示递增的数字,比如第行1个数字,第二行2个,依此类推。动态调整意味着当窗口大小变化时,金字塔的行数会相应增加或减少,同时界面上的组件需要更新,而不是简单地隐藏或叠加。 接下来,我需要考虑如何检测窗口大小的变化。Tkinter中可以用`<Configure>`事件来绑定窗口变化的事件。当窗口的尺寸改变时,触发回调函数,这个函数需要计算当前窗口能容纳多少行。比如,根据窗口的高度,每行的高度大概是多少,然后总行数就是窗口高度除以行高。 然后,动态创建和销毁组件是关键。每次窗口大小变化时,需要清除现有的组件,再根据新的行数重新生成。这时候应该用`grid_forget()`或者直接销毁组件,比如遍历所有子组件并销毁,然后再重新创建新的标签和数字。 另外,布局方面可能需要使用grid布局管理器,这样方便按行和列来排列数字。中间对齐的话,可能需要计算每行的起始列位置,比如总列数是2*行数-1,然后每行的数字从中间向两边展开。比如第i行的数字从第n-i列开始,每个数字占据两个位置,或者中间留空格? 然后数字的生成逻辑,每行的数字应该是中间为行号,向两边递减,比如第5行是5 4 3 2 1 2 3 4 5?或者可能用户想要的是每行显示行号重复?需要明确数字的排列方式。假设用户希望的是每行显示从1到当前行数,然后递减,比如第3行是1 2 3 2 1?或者可能只是简单的递增数字,比如每行显示行号多次?可能需要进步确认,但根据常见金字塔结构,应该是中间对称的数字排列。 不过用户可能希望每行显示行号,比如第行1,第二行2 2,第三行3 3 3,但这样可能不够金字塔形状。或者另种可能是数字递增,每行数字数量递增,但数字本身递增,比如1,2 3,4 5 6,但这样可能不是金字塔结构。可能需要明确用户的需求,但根据常规金字塔,应该是每行的数字对称排列,例如第n行是1到n再倒回到1,或者类似的结构。比如第3行是1 2 3 2 1,这样的对称排列。或者可能用户只是希望每行显示行号,例如第1行是1,第2行是2 2,第3行是3 3 3,这样形成个金字塔形状。这时候需要确定数字生成的逻辑。 假设用户希望的是每行显示行号重复,那么第i行有i个数字,每个数字都是i的值。这样金字塔的形状会更明显。但如果是这样,布局上每行的数字应该居中显示,可能需要通过grid的列布局来实现,比如总列数为最大行数的两倍减,然后每行的起始列是中间位置减去当前行数的位置。例如,最大行数为n,则总列数为2n-1,第i行的数字从第n-i列开始,占据i个位置。或者更简单的方式,使用frame来包裹每行,并使用pack或grid布局让它们居中。 不过动态调整的话,可能需要更灵活的方式。比如每次窗口变化时,计算当前可容纳的行数,然后生成对应的行,每行的数字根据行号生成,并排列在中间位置。 接下来,代码结构大致是:创建个Tkinter窗口,绑定Configure事件,当窗口大小变化时触发更新函数。在更新函数中,首先销毁现有的组件,然后根据当前窗口的高度计算行数,再生成对应的标签和数字。 关于动态创建和销毁组件,可能需要维护个列表来保存当前的所有组件,或者在每次更新时遍历并销毁所有子组件。例如,在回调函数中,使用winfo_children()获取所有子组件,然后destroy()它们,或者更高效的方式是使用个容器frame,每次清空frame中的组件。 另外,考虑性能问题,频繁地创建和销毁组件可能在窗口大小调整时导致卡顿。因此,可能需要设置个延迟,比如在窗口调整结束后再触发更新,而不是在每次调整时都触发。可以用after()方法来延迟处理,避免频繁回调。 总结步骤: 1. 创建Tkinter窗口,设置初始大小。 2. 绑定<Configure>事件到回调函数。 3. 在回调函数中,获取窗口当前高度,计算可容纳的行数。 4. 销毁现有的所有组件(如标签和数字)。 5. 根据新的行数,动态生成每行的数字,并排列在中间。 6. 使用grid布局管理器,计算每行数字的位置,使其居中显示。 7. 可能需要调整字体大小或组件间距以适应不同窗口大小。 现在,关于代码实现的具体细节: - 使用Frame作为容器,将数字标签添加到Frame中,方便管理。 - 计算行数:假设每行的高度是30像素(包括间距),那么行数=窗口高度//30。但需要根据实际字体大小调整这个值。 - 每行的数字生成,例如第i行显示从1到i的数字,或者对称排列的数字。 - 使用grid布局,每行的起始列位置为(max_columns - 当前行数字数量)//2,这样居中显示。 例如,对于行数n,最大列数为2n-1(假设每两个数字之间有个空格),或者根据实际数字的位数调整。或者更简单的方式,每行的每个数字放在个grid列中,中间对齐。 可能的代码结构: import tkinter as tk class NumberPyramid: def __init__(self): self.root = tk.Tk() self.root.title("动态数字金字塔") self.container = tk.Frame(self.root) self.container.pack(expand=True, fill='both') self.root.bind('<Configure>', self.on_resize) self.current_rows = 0 self.root.mainloop() def on_resize(self, event): # 计算行数 height = event.height row_height = 30 # 根据实际情况调整 new_rows = height // row_height if new_rows != self.current_rows: self.current_rows = new_rows self.update_pyramid() def update_pyramid(self): # 清空容器 for widget in self.container.winfo_children(): widget.destroy() # 生成新的金字塔 for i in range(1, self.current_rows + 1): row_frame = tk.Frame(self.container) row_frame.pack() # 生成数字,例如i重复i次 for j in range(i): label = tk.Label(row_frame, text=str(i), font=('Arial', 10)) label.pack(side='left', padx=5, pady=5) # 或者使用grid布局,可能需要更复杂的计算 不过这样使用pack布局可能不够灵活,难以居中。改用grid布局,可能需要计算每行的总列数,并设置每行的起始位置。 另个方法是将所有标签放在个grid中,每行居中显示。例如: def update_pyramid(self): for widget in self.container.winfo_children(): widget.destroy() for row in range(self.current_rows): cols = row + 1 # 第row行有cols个元素(从0开始) for col in range(cols): # 计算在总列数中的位置,假设总列数为2*current_rows -1 total_cols = 2 * self.current_rows -1 position = (total_cols - cols) // 2 + col label = tk.Label(self.container, text=str(row+1)) label.grid(row=row, column=position, padx=5, pady=5) 但这样总列数可能过大,导致布局问题。或者使用sticky和权重让列自动调整。或者使用Frame作为每行的容器,并pack在中间。 可能需要更灵活的方式,比如每行的Frame使用pack(side='top', anchor='center'),然后每个数字放在该Frame中,使用pack(side='left')。这样每行会自动居中。 所以修改update_pyramid函数: def update_pyramid(self): # 清空容器 for widget in self.container.winfo_children(): widget.destroy() # 生成新的行 for i in range(1, self.current_rows +1): row_frame = tk.Frame(self.container) row_frame.pack(pady=2, anchor='center') for j in range(i): label = tk.Label(row_frame, text=str(i), font=('Arial', 12)) label.pack(side='left', padx=2) 这样,每行的Frame会被pack到container的顶部,并且居中对齐。数字标签按顺序排列在Frame中,居左排列,而Frame本身居中,这样整体看起来是居中的金字塔。 但需要测试是否真的居中。可能需要在container中使用grid布局,设置columnconfigure权重,或者使用place布局。 或者,container使用grid布局,每行占据行,列数足够多,然后将标签放置在中间位置。例如: def update_pyramid(self): for widget in self.container.winfo_children(): widget.destroy() max_cols = 2 * self.current_rows -1 # 假设最大列数足够 for i in range(self.current_rows): num_labels = 2*i +1 # 例如,第i行有i+1个数字,或者按用户需求 # 需要确定数字的生成方式 # 假设每行显示i+1个数字,每个数字为i+1的值,例如第1行是1,第2行是2 2,第3行是3 3 3... # 则num_labels = i+1 num_labels = i+1 start_col = (max_cols - num_labels) //2 for j in range(num_labels): label = tk.Label(self.container, text=str(i+1)) label.grid(row=i, column=start_col +j, padx=2, pady=2) # 设置列的权重,使得中间列扩展 for col in range(max_cols): self.container.columnconfigure(col, weight=1) 但这种方法需要动态设置列的权重,确保标签居中。可能更可靠。 不过,用户的需求是数字金字塔,可能更倾向于每行的数字对称排列,比如中间数字最大,向两边递减。例如,第3行是1 2 3 2 1。这时候生成数字的逻辑会更复杂。 但用户的问题中并没有明确数字的排列方式,只提到“数字金字塔”,可能需要假设是每行显示递增的数字,或者对称排列。这里可能需要进步询问,但根据示例代码可能需要灵活处理。 不过用户可能更关注动态调整布局的部分,数字的具体内容可能次要。所以先按每行显示行号重复多次,形成金字塔形状。比如第1行1个1,第2行两个2,依此类推。 在代码中,当窗口调整时,根据高度计算行数,然后动态生成对应行数的标签,并居中显示。 另外,为了优化性能,在调整窗口时可能会有多次Configure事件触发,可以使用after方法来延迟处理,避免频繁更新。例如,设置个定时器,在窗口停止调整后再执行更新。 例如,在on_resize函数中: def on_resize(self, event): if event.widget == self.root: # 使用after来延迟处理,避免频繁更新 if hasattr(self, 'resize_id'): self.root.after_cancel(self.resize_id) self.resize_id = self.root.after(200, self.update_pyramid) 然后在update_pyramid中计算当前窗口高度,确定行数: def update_pyramid(self): # 获取当前窗口高度 height = self.root.winfo_height() row_height = 30 # 每行的高度,包括间距 new_rows = max(1, height // row_height) # 至少1行 if new_rows == self.current_rows: return self.current_rows = new_rows # 清空容器 for widget in self.container.winfo_children(): widget.destroy() # 生成新的行 for i in range(1, self.current_rows +1): row_frame = tk.Frame(self.container) row_frame.pack(pady=2, anchor='center') for j in range(i): label = tk.Label(row_frame, text=str(i), font=('Arial', 12)) label.pack(side='left', padx=2) 这样,当窗口调整时,会延迟200毫秒执行更新,避免频繁重建组件。 不过需要测试实际效果,比如窗口变化时是否准确计算行数,以及标签是否正确居中。 另个问题是,当行数较多时,标签可能会超出容器宽度,导致布局混乱。可能需要调整字体大小,或者使用更灵活的布局方式。 此外,用户希望根据窗口大小动态调整,所以可能需要考虑宽度的影响。例如,窗口变宽可以显示更多列,但用户需求是行数根据窗口大小变化,可能指的是高度决定行数,宽度自适应。或者行数由高度决定,每行的数字数量由行数决定,而每行的数字在宽度允许的情况下显示。可能需要明确,但根据用户描述,行数根据窗口大小动态变化,所以可能主要是高度决定行数。 综合以上思考,示例代码应包含: - 窗口绑定Configure事件,延迟处理。 - 根据窗口高度计算行数。 - 动态销毁旧组件,创建新组件。 - 每行的数字居中显示。 最终,提供个示例代码,满足用户的需求,并根据窗口高度动态调整行数,同时数字居中显示。</think>以下是使用Tkinter实现动态数字金字塔的示例代码,支持窗口大小变化时自动调整行数并重新布局: ```python import tkinter as tk class DynamicPyramid: def __init__(self): self.root = tk.Tk() self.root.title("动态数字金字塔") self.root.geometry("400x300") # 主容器使用Frame实现弹性布局 self.container = tk.Frame(self.root) self.container.pack(expand=True, fill='both') # 初始化参数 self.current_rows = 0 self.row_height = 30 # 每行预估高度 # 绑定窗口大小改变事件 self.root.bind('<Configure>', self.on_resize) self.update_pyramid() # 初始渲染 self.root.mainloop() def on_resize(self, event): """窗口大小改变事件处理""" if event.widget == self.root: # 使用延时防止频繁触发 if hasattr(self, 'resize_id'): self.root.after_cancel(self.resize_id) self.resize_id = self.root.after(200, self.update_pyramid) def update_pyramid(self): """更新金字塔布局""" # 计算当前可容纳行数 new_rows = max(1, self.root.winfo_height() // self.row_height) if new_rows != self.current_rows: # 清空旧组件 for widget in self.container.winfo_children(): widget.destroy() # 生成新金字塔 for row in range(1, new_rows+1): # 每行使用独立Frame实现居中 row_frame = tk.Frame(self.container) row_frame.pack(pady=2, anchor='center') # 生成对称数字序列(如第3行:1 2 3 2 1) nums = list(range(1, row+1)) + list(range(row-1, 0, -1)) for num in nums: label = tk.Label(row_frame, text=str(num), font=('Arial', 12), padx=3) label.pack(side='left') self.current_rows = new_rows if __name__ == "__main__": DynamicPyramid() ``` ### 关键实现原理 1. **动态布局机制**: 通过`<Configure>`事件监听窗口大小变化,使用`after()`实现200ms延时触发机制防止频繁更新[^2]。行数计算基于窗口高度与预设行高的比值`(winfo_height() // row_height)`。 2. **组件生命周期管理**: 每次更新时先`destroy()`所有旧组件,再根据新行数动态创建Label组件。这种销毁重建方式比隐藏/显示更节省内存[^1]。 3. **对称数字生成**: 采用`range(1, row+1) + range(row-1, 0, -1)`生成对称数列(如第3行生成1 2 3 2 1),通过`pack(side='left')`实现水平排列。 4. **居中显示方案**: 每行使用独立的Frame容器,设置`pack(anchor='center')`实现行级居中,结合数字的水平排列形成金字塔结构。 ### 效果优化建议 - 调整`row_height`参数可改变行高密度 - 修改`font`参数可调整数字大小 - 在`nums`生成逻辑中可自定义数字模式 - 添加`minsize()`限制最小窗口尺寸
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值