Python3中定义一个单向链表

链表是由节点构成的,一个指针代表一个方向,如果一个构成链表的节点都只包含一个指针,那么这个链表就是单向链表。

单向链表中的节点不光有代表方向的指针变量,也有值变量。所以我们定义链表,就是要定义链表中的节点,对链表的操作最后也就是对节点的操作。

这些包含数据的节点们在一种指定的结构下连接起来,成为了一种数据结构——单向链表。以上是我对单向链表的理解。

以下是我用python3对单向链表这种数据结构的一种实现:

‘‘‘
    Python3版单向链表-单向链表简称单链表
    单链表中所包含的基本操作:
    初始化
    创建
    生成
    打印
    显示调用过程
    计算长度
    判空
    获取
    删除
    插入
    修改
    追加

‘‘‘

class Node(object):
    # 节点初始化
    def __init__(self, value, p=None):
        self.value = value
        self.next = p

class LinkList(object):
    # 初始化单链表
    def __init__(self):
        self.head = None

    # 创建单链表
    def create(self, value):
        self.head = Node(value[0])
        p = self.head
        for i in value[1:]:
            p.next = Node(i)
            p = p.next

    # 生成单链表
    def _yield(self):
        p = self.head
        while p != None:
            yield p.value
            p = p.next

    # 打印单链表
    def print(self):
        print([i for i in self._yield()])

    # 显示方法调用前后的单链表
    def show(func):
        def wrapper(self, *args):
            print("方法{func_name}执行前".format(func_name=func.__name__))
            self.print()
            print("方法{func_name}执行中".format(func_name=func.__name__))
            func(self, *args)
            print("方法{func_name}执行后".format(func_name=func.__name__))
            self.print()

        return wrapper

    # 获取单链表的长度
    def length(self):
        p = self.head
        length = 0
        while p != None:
            length += 1
            p = p.next
        return length

    # 判断单链表是否为空
    def is_null(self):
        return self.length() == 0

    # 获取单链表偏移位元素返回并打印其节点值
    # 支持顺序索引和逆序索引:0代表索引一位,-1代表倒数第一位,-2代表倒数第二位
    # 获取不存在的位返回None
    def get(self, offset):
        p = self.head
        index = 0
        length = self.length()
        if offset > length - 1:
            print(None)
            return None
        if offset < 0 and offset + length < 0:
            print(None)
            return None
        if offset < 0 and offset + length >= 0:
            offset = length + offset
        while index < length - 1 and index < offset:
            p = p.next
            index += 1
        print("获取索引{index}位节点-值为{value}".format(index=index, value=p.value))
        return p

    # 删除单链表偏移位元素并打印
    # 支持顺序索引和逆序索引:0代表第一位,-1代表倒数第一位,-2代表倒数第二位
    # 删除不存在的位返回None
    @show
    def remove(self, offset):
        p = self.head
        length = self.length()
        index = 0
        if offset > length - 1:
            print(None)
            return None
        if offset == 0 or offset + length == 0:
            print("删除索引{index}位节点-值为{value}".format(index=index, value=self.head.value))
            self.head = p.next
            return None
        if offset < 0 and length + offset > 0:
            offset = length + offset
        while index < length - 1 and index < offset - 1:
            p = p.next
            index += 1
        print("删除索引{index}位节点-值为{value}".format(index=index + 1, value=p.next.value))
        p.next = p.next.next

    # 在指定index位插入节点-值为value
    # 什么是插入——在两个节点之间加入才叫插入
    # 所以在末尾插入的意思就是在索引倒数第二位和倒数第一位之间插入
    @show
    def insert(self, offset, value):
        length = self.length()
        # 如果偏移量对应的索引位不在链表对应索引位范围内-返回None
        if offset > length - 1 or offset + length < 0:
            return None
        if offset < 0:
            offset = offset + length
        node = Node(value)
        if offset == 0 or offset + length == 0:
            p = self.head
            self.head = node
            node.next = p
        else:
            previous_node = self.get(offset - 1)
            current_node = self.get(offset)
            previous_node.next = node
            node.next = current_node
        print("在索引{index}位插入节点-值为{value}".format(index=offset, value=value))

    # 在链表索引末位追加一个节点-值为value
    @show
    def append(self, value):
        last_node = self.get(self.length() - 1)
        last_node.next = Node(value)

    # 修改链表索引位节点值
    @show
    def modify(self, offset, value):
        self.get(offset).value = value

if __name__ == ‘__main__‘:
    list = [1, 2, 33, 4, 55, 6, 76, 78]
    # 初始化链表
    link_list = LinkList()
    # 创建链表
    link_list.create(list)
    # 获取节点
    link_list.get(-1)
    # 删除节点
    link_list.remove(0)
    # 插入节点
    link_list.insert(-2, 0.2)
    # 末位追加节点
    link_list.append(3)
    # 修改节点值
    link_list.modify(-1, 666)

原文地址:https://www.cnblogs.com/LanTianYou/p/8652639.html

时间: 2024-10-14 03:08:44

Python3中定义一个单向链表的相关文章

【编程题目】输入一个单向链表,输出该链表中倒数第 k 个结点

第 13 题(链表):题目:输入一个单向链表,输出该链表中倒数第 k 个结点.链表的倒数第 0 个结点为链表的尾指针.链表结点定义如下: struct ListNode {int m_nKey;ListNode* m_pNext;}; 我的思路:先翻转链表,再从翻转后的链表的头向尾数k-1个,返回,再次翻转链表. 代码如下:注意这个思路非常差.差的原因是:如果只是用最原始的方法,先遍历一遍计数,再遍历一遍找倒数第k个,需要遍历两遍.但我的思路,翻转两次链表就要遍历两遍.还要在走k-1步找倒数第k

13输入一个单向链表,输出该链表中倒数第k个结点。链表的倒数第0个结点为链表的尾指针。

转载请注明出处:http://www.cnblogs.com/wuzetiandaren/p/4250795.html 声明:现大部分文章为寻找问题时在网上相互转载,此博是为自己做个记录记录,方便自己也方便有类似问题的朋友,本文的思想也许有所借鉴,但源码均为本人实现,如有侵权,请发邮件表明文章和原出处地址,我一定在文章中注明.谢谢. 题目:输入一个单向链表,输出该链表中倒数第k个结点.链表的倒数第0个结点为链表的尾指针. 题目分析: 1.链表的倒数第0个结点为链表的尾指针,设为r,则r指向最后一

输入一个单向链表,输出该链表中倒数第 k 个结点

class ListNode { public: ListNode() { pNext = NULL; nValue = 0; } ListNode* pNext; int nValue; }; ListNode* CreaList() { int nValue; ListNode* Head = NULL; ListNode* ListIndex = NULL; while(cin >> nValue) { if (Head == NULL) { Head = new ListNode();

如何判断一个单向链表是否为回文链表(Palindrome Linked List)

题目:给定一个单向链表,判断它是不是回文链表(即从前往后读和从后往前读是一样的).原题见下图,还要求了O(n)的时间复杂度O(1)的空间复杂度. 我的思考: 1,一看到这个题目,大脑马上想到的解决方案就是数组.遍历链表,用数组把数据存下来,然后再进行一次遍历,同时用数组反向地与之比较,这样就可以判断是否回文.这个方法时间复杂度是O(n),达到了要求,然而空间复杂度显然不满足要求.所以,开数组这一类的方法显然不是最佳的. 2,既然要满足O(1)的空间复杂度,我就想到了用一个变量来存储这些数据,恰好

在 C# 中定义一个真正只读的 List

public class Class1 { public readonly SynchronizedReadOnlyCollection<int> ints; public Class1() { ints = new SynchronizedReadOnlyCollection<int>(new[] {1,2,3}); } public void test() { ints.Add ? } } 在 C# 中定义一个真正只读的 List

在主方法中定义一个大小为50的一维整型数组,数组i名为x,数组中存放着{1,3,5,…,99}输出这个数组中的所有元素,每输出十个换一行

package hanqi; import java.util.Scanner; public class Test7 { public static void main(String[] args) { //在主方法中定义一个大小为50的一维整型数组,数组i名为x,数组中存放着{1,3,5,…,99}输出这个数组中的所有元素,每输出十个换一行 int [] x=new int[50]; int a =1; for(int i=0;i<50;i++) { x[i]=a; a+=2; } for(

android中定义一个可勾选的ListView

1.在layout中定义一个CheckedTextView <CheckedTextView android:id="@+id/textView1" android:layout_width="match_parent" android:layout_height="wrap_content" android:checkMark="?android:attr/listChoiceIndicatorMultiple" an

在主方法中定义一个大小为10*10的二维字符型数组,数组名为y,正反对角线上存的是‘*’,其余 位置存的是‘#’;输出这个数组中的所有元素。

//在主方法中定义一个大小为10*10的二维字符型数组,数组名为y,正反对角线上存的是‘*’,其余 位置存的是‘#’:输出这个数组中的所有元素. char [][]y=new char [10][10]; for(int i=0;i<10;i++) { for(int j=0;j<10;j++) { if(i==j||i+j==9) { y[i][j]='*'; } else { y[i][j]='#'; } } } for(int i =0;i<10;i++) { for(int k

C++异常机制的实现方式和开销分析 (大图,编译器会为每个函数增加EHDL结构,组成一个单向链表,非常著名的“内存访问违例”出错对话框就是该机制的一种体现)

白杨 http://baiy.cn 在我几年前开始写<C++编码规范与指导>一文时,就已经规划着要加入这样一篇讨论 C++ 异常机制的文章了.没想到时隔几年以后才有机会把这个尾巴补完 :-). 还是那句开场白:“在恰当的场合使用恰当的特性” 对每个称职的 C++ 程序员来说都是一个基本标准.想要做到这点,就必须要了解语言中每个特性的实现方式及其时空开销.异常处理由于涉及大量底层内容,向来是 C++ 各种高级机制中较难理解和透彻掌握的部分.本文将在尽量少引入底层细节的前提下,讨论 C++ 中这一