爱情不是变成编程,婚姻更不是算法!(数据结构一)

爱情不是编程,婚姻更不是算法!
今天在微博上看到这句话,突然感觉很有道理,刚好一直在看数据结构,发现其实实现一个算法,其中的逻辑思维异常巧妙,前段时间总结的ListHelper就感觉很low,不过都是一种思想,今天总结的都是一些关于数据结构的内容,数据结构这块很难理解,相对而言比较抽象,但要将这种抽象的具体化,需要不断的练习。
首先看一下单链表,将线性列表中的元素分布在储存器的不同存储块,称为结点,每个结点中都持有下一个结点的引用,这样的存储结构为链表结构(尾部结点除外)。可以这样理解,我们有一个列表,每个元素都存有下一个元素的地址,这样我们就能从这个元素找到下一个元素。我们对列表的有一定的操作了,包括增删改查,那么链表当然也一样,不过实现起来要比列表复杂。
接下来我们看看对链表的操作,是如何实现增删改查的。
创建结点类,其中self.val是一个元素

class Node(object):
    def __init__(self, val, next=None):
        self.val = val  # 有用数据
        self.next = next

接下来我们对这个链表进行操作,我们创建了一个LinkList的类,让这个类继承自父类,如果我们创建的类没有继承我们就定义这个类继承object这个父类。这里用到之前的类,我们初始化这个方法,定义head为一个空值,在定义init_list方法的时候,我们传入data这个元素,让self.head=Node(None)这个就是一个链表的开头,它包含下一个数据的next地址,我们通过这个就可以拿到下一个元素的val。

class LinkList(object):
    def __init__(self):
        self.head = None
    def init_list(self, data):
        self.head = Node(None)  # 链表的开头
        p = self.head  # 可移动变量p
        for i in data:
            p.next = Node(i)
            p = p.next

我们在定义一个方法来打印这个链表,在这个方法中,我们创建self.head.next的对象,循环遍历,直到这个链表的值为空,只要这个对象不是None我们就打印这个对象的val。

def show(self):
    p = self.head.next
    while p != None:
        print(p.val, end=' ')
        p = p.next
    print()

那么以上就是对单链表遍历的操作了。
接下来我们对链表进行一些其他操作,第一个在尾部插入新节点,那我们遍历到最后一个元素时,此时这个元素的next应该是一个None,循环遍历这个链表,如果不是空,就让这个next等于表头,如果是个空此时传入我们的数据。
同样定义一个方法,用的时候直接调用就可以了

#  尾部插入新的结点
def append(self, item):
    p = self.head
    while p.next is not None:
        p = p.next
    p.next = Node(item)

第二个获取这个链表的长度,获取链表长度这里引入之前学循环时的计数器思想,同样循环遍历next,如果不是空我们就让计数器加1如果他是一个人空值我们就返回这个数,结束当前的循环。为什么要一直遍历next呢?因为只有next中保存了下一个元素的地址,那这个next是一个空值的时候,也就是说这个链表结束了他没有保存下一个元素的地址了!

#  获取链表长度
def get_length(self):
    n = 0
    p = self.head
    while p.next is not None:
        n += 1
        p = p.next
    return n

第三个判断链表是否是一个空来链表,我们在拿到一个链表的时候我们也不知道这个链表里边有没有数据,那么此时我们就要先判断一下这个链表,如果是空我们就返回一个True,如果不是我们就返回一个False,这时我们调用刚刚写好的判断链表长度的方法就很简单了。

#  判断链表是否为空
def is_empty(self):
    if self.get_length() == 0:
        return True
    else:
        return False

第四个清空链表,当我们要清空一个链表的时候的,我们其实只需要做一件事就可以了,就是让表头的next等于一个空值,其他的链表自然也就断了我们就不能拿到剩余的元素了,这样我们就认为我们已经清空这个链表了!

# 清空链表
def clear(self):
    self.head.next = None

第五个获取索引值,比如说我们要获取某个索引值的元素,要对这个值进行操作的时候,我们就要获取到这个元素的索引值才可以,同样定义方法,也引用到计数器的思想,首先我们让这个表头的next等于一个对象,在循环遍历这个链表的时候,计数器必须小于要索引的值,同时next不能为一个空值,如果是一个空那就等于是最后一个元素了,那么在循环遍历的时候,就让这个对象等于下一个next,同时我们还需判断这个对象,如果是一个空就抛出一个错误,如果不是我们就返回这个元素。

#  获取索引值
def get_item(self, index):
    p = self.head.next
    i = 0
    # 没有到对应索引号并且遍历索引没有到最后就循环
    while i < index and p is not None:
        i += 1
        p = p.next
    # 如果因为p到最后了则说明越界
    if p is None:
        raise IndexError("list index out of range")
    # i 不小于inedx说明找到索引结点了
    else:
        return p.val

第六个插入元素,我们要在某索引位置上插入一个元素,首先判断这个索引是不是大于0或者大于链表的长度,如果不能满足其中任何一个我们就没必要在做剩下的事了,此时就抛出错误。先对表头创建一个对象,同样引入计数器思想,这数据结构中经常会使用到计数器的思想,循环让对象一直移动到带插入元素位置的前一个,然后我就创建一个新的结点,这个方法前边也有写,接下来就插入结点,并切让这个对象的next的关于node,此时我们就插入你想要插入的元素了。

def insert(self,index,item):
    if index < 0 or index > self.get_length():
        raise IndexError("list index out of range")

    # 让p移动到待插入位置的前一个
    p = self.head
    i = 0
    while i < index:
        p = p.next
        i += 1

    node = Node(item)  # 创建新的结点
    node.next = p.next  # 插入结点
    p.next = node

最后删除某一个元素,同样创建一个表头对象,循环遍历,这个对象的next,此时判断这个对象的next.val等于我们的元素,就让这个next等于这个元素的下一个next,切断了这个元素的next,此时这个元素就相当于消失了,因为我们这个是一个链表,这个元素勾这下一个元素的地址,一但切掉,这个元素就相当于消失了。如果我们遍历完了仍然没有找到,我们就要抛出错误了,证明你想要删除的这个元素没有在这个链表中。

def delete(self,item):
    p = self.head
    while p.next is not None:
        # 如果值相等则越过中间的结点
        if p.next.val == item:
            p.next = p.next.next
            break
        p = p.next
    else:
        raise ValueError("x not in list")

这些是我整理的一些对链表的操作,数据结构中还有很多操作,后边有时间会慢慢整理出来!
可谓一入编程深似海,从此君郎是路人啊!此时已是深夜,分享一段话“满地都是六便士,他却抬头看见了月亮”,献给每一位在看见月亮的路上不断奔跑的人!

发布了14 篇原创文章 · 获赞 6 · 访问量 989

猜你喜欢

转载自blog.csdn.net/weixin_44935235/article/details/90105093
今日推荐