zoukankan      html  css  js  c++  java
  • 单链表

    写给自己看的笔记, 很多坑

    1. 创建一个节点类

    class Node(object):
        '''节点类'''
    
        def __init__(self, elem):
            self.elem = elem
            self.next = None
    

    类内部的 __init__函数,是初始化函数,只要是类的实例对象,就会自动执行__init__函数内部的代码块,也就是说,类的实例对象都会有__init__函数的属性

    ex:

    __node = Node()__
    

    __node__就是Node类的__实例__对象
    该node具有__elem__和__next__属性

    [========]

    2. 创建一个链表类

    class SingleLinkList():
    
        def __init__(self, node=None):
            self.__head = node
    

    1. 定义实例的首节点属性,该属性为实例的私有属性

    self__head = node
    

    表示self的head属性是self私有的

    2. 链表可以定义为空, 但是空链表内必须存在首节点,node=None,默认的首节点指向None,但以传递进来的首节点node为准

    def __init__(self, node=None):
        slef.__head=node
    

    node在函数的参数元祖内, 如果不传递node,默认的node的值为None

    ex1:

    linklist = SingleLinkList()
    
    1. 创建一个SingleLinkList类的实例对象
    1. 该对象没有给SingleLinkList类传递node节点
    2. 所以该实例的首节点self.__head = None

    ex2:

    linklist = SingleLinkList(110)
    
    1. 创建一个SingleLinkList类的实例对象
    1. 该实例对象的首节点self.__head = 110

    [========]

    3.给SingleLinkList类,添加内置方法

    1. 所有的内置方法

    def __init__(self, node=None):
        """SingleLinkList类初始化,私有的,首节点方法"""
        self.__head = node
    
    def is_empty(self):
        """链表是否为空"""
    
    def length(self):
        """链表的长度"""
    
    def tarvel(self):
        """遍历整个链表"""
    
    def add(self, item):
        """链表头部添加元素, 首插法"""
    
    def append(self, item):
        """链表尾部添加元素, 尾插法"""
    
    def insert(self, pos, item):
        """指定位置插入元素"""
    
    def remove(self, item):
        """删除节点"""
    
    def search(self, item):
        """查找节点是否存在"""
    

    [========]

    4. 创建实例对象,及调用内部方法

    ex:

    linklist= SingleLinkList()
    

    创建一个实例对象

    linklist.is_empty()
    

    调用该实例的is_empty方法

    [========]

    5. 详解该链表的每一个方法

    1. is_empty()

    def is_empty(self):
        return self.__head == None
    

    __作用:__判断该链表是否为空
    步骤详解:

    1. self.__head是该链表的首节点,
    2. 如果self._head==None,就表示该链表首节点为None,即该链表没有节点
    3. return返回的是布尔值,如果为空返回True,否则返回False

    [========]

    2. length()

    def length(self):
        cur = self.__head
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count
    

    __作用:__查看该链表的长度
    步骤详解:

    cur = self.__head
    

    创建游标,起始是指向链表的首节点

    count = 0
    

    创建count,起始值为0,进行数数

    while cur != None:
    

    遍历所有元素
    1.判断条件:如果游标(cur)指向的不是None,就一直循环.
    2.最后一个节点的next域指向的就是None
    3.当cur == None的时候,就是已经遍历完所有的节点

    count += 1
    

    如果游标cur所指向的节点不是None,则执行count加一操作

    cur = cur.next
    

    将游标cur进行后移一位

    return count
    

    返回count的数值

    注意点:
    1. 如果该链表为空怎么办?

    1. 当链表为空的时候,游标cur的指向None;cur = self.__head
    2. count=0已经设置好了;
    3. 链表为空,跳过循环体;while cur != None:
    4. return count 返回count的值0

    2. cur == None 与 cur.next == None的判断条件的问题

    1. cur == None表示当前游标指向的节点为None
    2. cur.next == None表示当前游标指向的节点的后继节点为None
    3. __后继结点:__表示当前节点的后一个节点

    [========]

    3. tarvel()

    def tarvel(self):
            cur = self.__head
            while cur != None:
                print(cur.elem, end=" ")
                cur = cur.next
            print("")
    

    __作用:__遍历所有节点[遍历整个链表]
    步骤详解:

    1. cur = self.__head
      创建游标,游标的起始指向是链表的首节点
    2. while cur != None:
      遍历所有节点,如果游标cur指向的不是None,执行此循环
    3. print(cur.elem, end=" ")
      在循环体内,如果cur所指向节点不是None,则打印当前节点的elem的值'''
    4. cur = cur.next
      将游标进行后移一位
    5. print("")
      1.当连续调用此方法的时候,终端输出的内容为连续
      2.如果设置print(""),每次打印完毕都会换行

    注意点
    1. 如果该链表为空怎么办?

    1. 当链表为空的时候,游标cur的指向None;cur = self.__head
    2. 链表为空,跳过循环体;while cur != None:
    3. 打印print("")

    2. cur == None 与 cur.next == None的判断条件的问题

    1. cur == None表示当前游标指向的节点为None
    2. cur.next == None表示当前游标指向的节点的后继节点为None
    3. 如果判断条件为cur.next == None,则会丢掉最后一个元素
    4. __后继结点:__表示当前节点的后一个节点

    [========]

    4. add():

    def add(self, item):
            node = Node(item)
            node.next = self.__head
            self.__head = node
    

    __作用:__链表头部添加元素, 首插
    步骤详解:

    1. node = Node(item)
      创建一个Node(item)的新节点,要插入到链表的首部, 也就是作为当前链表的首节点
    2. 假设链表本身是有很多节点的
      如果直接将链表的self.__head首节点指向新节点,那么就会丢失原有的所有节点
    3. 先将新节点的next域指向原先的首节点node.next = self.__head
    4. 然后再将self.__head指向现在的新节点self.__head = node

    注意点:

    1. 当链表为空的时候, 默认的首节点是指向None的
      slef.__head = None
    2. 以上三行代码完全可以应对链表为空的情况

    [========]

    5. append()

    def append(self, item):
        node = Node(item)
        if self.is_empty():
            self.__head = node
        else:
            cur = self.__head
            while cur.next != None:
                cur = cur.next
            cur.next = node
    
    

    __作用:__链接尾部添加节点,尾追加

    步骤详解:

    1. node = Node(item)
      创建一个新节点,该节点的elem为item
    2. if self.is_empty():
      判断该链表是否为空
      1.self.__head = node
      将节点node作为链表的首节点
    3. cur = self.__head
      利用首节点来创建游标
    4. while cur.next != None:
      cur = cur.next
      如果游标指向的节点的next域不指向None,则进行后移操作
    5. cur.next = node
      1.循环结束
      2.游标指向最后一个节点(最后一个节点的next域指向None)
      3.将最后一个节点的next域指向node(最后一个节点的next域指向新创建的node节点)

    [========]

    6. insert()

    def insert(self, pos, item):
            if pos <= 0:
                self.add(item)
            elif pos > (self.length()-1):
                self.append(item)
            else:
                node = Node(item)
                pro = self.__head
                count = 0
                while count < (pos-1):
                    count += 1
                    pro = pro.next
                node.next = pro.next
                pro.next = node
    

    __作用:__指定位置插入节点

    步骤详解:

    1. if pos <= 0:
      self.add(item)
      如果给定的下标小于等于0,直接在链表首部添加元素
    2. elif pos > (self.length()-1):
      self.append(item)
      如果给定的下标大于链表的尾部下标,直接进行尾部添加元素

    3.else:
    进入插入节点的代码体
    node = Node(item)
    创建一个新节点
    pro = self.__head
    创建游标
    count = 0
    我们计数的方式来控制游标
    while count < (pos-1):
    当下标到pos前一位元素的时候,结束循环
    count += 1
    pro = pro.next
    游标向后移动一位
    node.next = pro.next
    新节点的next域指向pos上一个位置处的next域的指向
    pro.next = node
    将pos上一个位置处的next域指向新节点
    注意: 如果给定的下标等于尾部下标,就等于是在尾部下标处添加元素,原有的尾部元素要向后移动一位, 我们把他归类到插入节点的代码中

    [========]

    7. search()

    def search(self, item):
        cur = self.__head
        while cur != None:
            if cur.elem == item:
                return True
            else:
                cur = cur.next
        return False
    
    

    __作用:__查找节点是否存在

    1. cur = self.__head
      创建游标,起始指向首节点
    2. while cur != None:
      遍历所有节点,也就是说只要游标指向的不是None,此循环一直执行
      1.if cur.elem == item:
      如果节点的elem等于item,返回True
      return True
      2.else:
      cur = cur.next
      游标向后移动一位
    3. return False
      循环结束后,也就是遍历了所有节点之后没有找到item元素,返回False

    [========]

    8. remove()

    def remove(self, item):
            cur = self.__head
            pro = None
            while cur != None:
                if cur.elem == item:
                    if cur == self.__head:
                        self.__head = cur.next
                    else:
                        pro.next = cur.next
                    break
                else:
                    pro = cur
                    cur = cur.next
    

    __作用:___删除节点

    1. 创建两个游标,cur__和__pro
      cur = self.__head
      游标cur,起始指向链表的首节点.
      作用:指向当前节点
      pro = None
      游标Pro,起始指向None
      作用:指向cur游标的上一个节点
    2. 遍历所有元素,条件为cur不等于None
      while cur != None:
      2.1. if cur.elem == item:
      如果cur的elem等于item(如果游标所指向的节点的元素等于要查找的元素), 执行删除操作
      2.2.if cur == self.__head:
      先判断item的节点是否为首节点
      2.3self.__head = cur.next
      让首节点指向cur的后继节点

    3.else:
    pro.next = cur.next
    item如果不是首节点的elem,
    直接将当前节点的__前一个节点的next域__指向当前节点的__后继节点的next域__
    4.break
    pro = cur
    pro为cur的上一个元素的游标
    cur = cur.next
    注意: pro与cur的位置不能颠倒
    注意点:

    1. 先判断该链表是否为空
      如果是空链表不执行任何操作
    2. 如果只有一个节点
      以上代码完全可以完成任务(即:self.__head == cur.next)
    3. 首节点
      如果是首节点,将链表的首节点self.__head指向cur当前节点的后继节点
    4. 尾节点
      以上代码完全可以完成任务(即:pro.next = cur.next)

    顺序表与单链表的对比

    时间复杂度的对比:

    操作 链表 顺序表
    访问元素 O(n) O(1)
    从头部删除元素 O(1) O(n)
    从尾部删除元素 O(n) O(1)
    在中间插入元素 O(n) O(n)

    总结:

    链表失去了顺序表随机读取的优点,同时链表由于增加了节点的指针域,空间开销比较大,但对存储空间使用要相对灵活
    

    链表和顺序表在插入和删除是进行的是完全不同的操作

    链表:

    1.主要耗时的操作是遍历查找
    2.删除和插入操作本身的复杂度是O(1)

    顺序表:

    1.主要耗时的操作是拷贝覆盖
    2.抛除元素在尾部的情况
    顺序表进行插入和删除时,需要对操作点之后的所有元素进行前后移动操作
    只能通过拷贝和覆盖的方法进行

  • 相关阅读:
    asp.net+ tinymce粘贴word
    jsp+ tinymce粘贴word
    jsp+ ueditor word粘贴上传
    php+ ueditor word粘贴上传
    asp.net+ueditor word粘贴上传
    word写博客
    【转】如何使用离线博客发布工具发布CSDN的博客文章
    用word发布CSDN文章
    用word发CSDN blog,免去插图片的烦恼
    如何实现word上传服务器
  • 原文地址:https://www.cnblogs.com/amou/p/8979359.html
Copyright © 2011-2022 走看看