Python重组列表,使列表中 每个成员 都与 其他成员 相临

本文介绍了一种使用Python实现的算法,该算法可以确保列表中每个人都能与其他所有人相邻出现一次,通过具体示例展示了算法的运行过程及结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

比如说列表中有Kenn、Tom、Jerry、Jenifer、Candy,想让其中每个人都与其他四个人相邻:

import numpy as np

SI = np.array([], dtype=int)
for i in range(5):
    SI = np.append(SI, i+1)
print(SI)   # [1 2 3 4 5]

people = ['Kenn', 'Tom', 'Jerry', 'Jenifer', 'Candy']


def not_exist(arr, array):
    for i in range(len(array)):
        if arr[0] == array[i]:
            if i != len(array)-1:
                if arr[1] == array[i+1]:
                    return False
    return True


def algorithm1_real(SI):
    SIS = [1]
    SI_new = [SI[0]]
    i = 1
    j = i + 1
    while i != j:
        if j > len(SI):
            j = 1
        elif not_exist([i, j], SIS) and not_exist([j, i], SIS):
            SI_new.append(SI[j-1])
            SIS.append(j)
            i = j
            j = j + 1
        else:
            j = j + 1
    return SI_new


print(algorithm1_real(SI))
# [1, 2, 3, 4, 5, 1, 3, 5, 2, 4, 1]
print(algorithm1_real(people))
# ['Kenn', 'Tom', 'Jerry', 'Jenifer', 'Candy', 'Kenn', 'Jerry', 'Candy', 'Tom', 'Jenifer', 'Kenn'] 

输出结果:

['Kenn', 'Tom', 'Jerry', 'Jenifer', 'Candy', 'Kenn', 'Jerry', 'Candy', 'Tom', 'Jenifer', 'Kenn']

对Kenn来说,他与其余四人Tom、Jerry、Jenifer、Candy均相邻。

对Jerry也是如此:

<think>我们正在讨论面向对象编程中成员变量和方法的继承机制及其底层原理。根据用户的问题,我们需要从以下几个方面展开: 1. 继承的基本概念:派生类如何自动获得基类的成员变量和方法。 2. 底层实现原理:内存布局、方法表等。 3. 不同语言(如C++、Java、JavaScript)的实现差异。 4. 引用中提到的JavaScript对象冒充继承的原理和缺陷。 我们将结合用户提供的引用内容,特别是引用[1][2][3][4]中的观点,来构建回答。 注意:用户要求理解机制和底层原理,所以需要深入一些。 结构安排: 一、继承的基本概念 二、成员变量的继承机制内存布局 三、成员方法的继承机制方法表 四、不同语言的实现差异(C++、Java、JavaScript) 五、JavaScript对象冒充继承的原理缺陷(根据引用[2][4]) 六、super关键字的作用(根据引用[3]) 七、总结 同时,按照要求,在回答末尾生成相关问题。 注意:引用标识要自然地添加在引用内容的末尾。</think>### 面向对象编程中成员变量方法的继承机制及底层原理 #### 一、继承的基本机制 1. **成员继承** 派生类自动获得基类的**非私有成员变量和方法**(除构造/析构函数外)[^1]。 ```java class Animal { // 基类 protected int age; // 成员变量 public void breathe() { // 成员方法 System.out.println("Breathing..."); } } class Fish extends Animal { // 派生类 // 自动获得age属性和breathe()方法 } ``` 2. **访问权限控制** | 继承方式 | public成员 | protected成员 | private成员 | |--------------|------------|---------------|------------| | public继承 | public | protected | 不可访问 | | protected继承| protected | protected | 不可访问 | | private继承 | private | private | 不可访问 [^1] --- #### 二、成员变量的继承原理 1. **内存布局** 派生类对象的内存包含**基类子对象 + 派生类新增成员**: ``` | 基类成员变量区 | 派生类新增成员区 | ↑ ↑ 基类起始地址 派生类扩展地址 ``` - 基类成员位于内存起始位置 - 派生类成员紧随其后[^1] 2. **访问机制** ```cpp Fish f; f.age = 2; // 实际访问基类子对象中的age ``` - 编译器将`f.age`转换为`*(&f + offset)`的内存访问 - offset在编译时确定(基类成员固定偏移量) --- #### 三、成员方法的继承原理 1. **方法表(vTable)机制** ```mermaid graph LR A[Animal vTable] -->|虚函数指针| B[Animal::breathe] C[Fish vTable] -->|继承| A C -->|新增| D[Fish::swim] ``` - 每个类拥有独立的方法表(vTable) - 派生类vTable包含基类方法指针副本 - 方法调用通过`对象指针->vTable[索引]`实现[^1] 2. **方法覆盖的动态绑定** ```java Animal a = new Fish(); a.breathe(); // 动态调用Fish覆盖后的方法 ``` - 虚函数调用在运行时通过vTable解析 - 非虚函数在编译期静态绑定 --- #### 四、JavaScript的特殊实现 1. **对象冒充继承** ```javascript function Animal(age) { this.age = age; this.breathe = function() {...} // 方法副本 } function Fish(age) { this.temp = Animal; this.temp(age); // 将Animal方法绑定到Fish实例 delete this.temp; } ``` - 通过临时绑定基类构造函数实现继承[^2][^4] - **缺陷**: - 每个实例创建方法副本(内存浪费) - 无法继承prototype链上的方法[^2] 2. **原型链继承** ```javascript Fish.prototype = new Animal(); Fish.prototype.constructor = Fish; ``` - 通过原型链实现方法共享 - 方法定义在原型上,避免内存重复占用 --- #### 五、关键操作原理 1. **super关键字** ```java class Fish extends Animal { void breathe() { super.breathe(); // 调用基类被覆盖的方法 System.out.println("Underwater"); } } ``` - 编译后转换为`Animal::breathe(this)`调用[^3] - 通过隐藏指针访问基类方法表 2. **构造/析构链** - 构造顺序:基类 → 派生类(保证基类先初始化) - 析构顺序:派生类 → 基类(反向销毁) - 派生类构造函数必须显式/隐式调用基类构造[^1] --- ### 总结:核心原理对比 | 机制 | 成员变量 | 成员方法 | |-----------------|---------------------------------------|---------------------------------------| | **继承本质** | 内存包含基类子对象 | 方法表复制基类函数指针 | | **访问方式** | 内存偏移量访问 | vTable动态绑定 | | **内存成本** | 每个实例包含基类数据副本 | 方法表共享(非JS对象冒充) | | **关键操作** | 派生类构造时初始化基类成员 | super通过作用域解析访问基类方法[^3] | > 继承的本质是**编译时的内存布局重组**(变量)和**运行时的动态绑定**(方法),通过方法表实现多态,而JS等动态语言通过原型链实现类似机制[^1][^2]。 --- ### 相关问题 1. 在C++中,虚函数表(vTable)的具体内存结构是怎样的?派生类如何修改其中的函数指针? 2. JavaScript的原型链继承经典面向对象语言(如Java)的类继承机制有哪些本质差异? 3. 当存在多重继承时(如C++),派生类的内存布局会如何安排?菱形继承问题如何通过虚继承解决? 4. 为什么Java的`final`方法和C++的非虚函数无法实现运行时多态?其底层实现原理是什么? 5. 在Python等动态类型语言中,方法解析顺序(MRO)如何解决多继承时的成员冲突问题?[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值