python数据结构:链表

   一、单链表

1、单链表简介   

      数据结构是计算机科学必须掌握的一门学问,之前很多的教材都是用C语言实现链表,因为c有指针,可以很方便的控制内存,很方便就实现链表,其他的语言,则没那么方便,有很多都是用模拟链表,不过这次,我不是用模拟链表来实现,因为python是动态语言,可以直接把对象赋值给新的变量。

     好了,在说我用python实现前,先简单说说链表吧。在我们存储一大波数据时,我们很多时候是使用数组,但是当我们执行插入操作的时候就是非常麻烦,看下面的例子,有一堆数据1,2,3,5,6,7我们要在3和5之间插入4,如果用数组,我们会怎么做?当然是将5之后的数据往后退一位,然后再插入4,这样非常麻烦,但是如果用链表,我就直接在3和5之间插入4就行,听着就很方便。

    链表的结构:链表像锁链一样,由一节节节点连在一起,组成一条数据链。 链表的节点的结构如下: data next data为自定义的数据,next为下一个节点的地址。 链表的结构为,head保存首位节点的地址:

链表的节点的结构如下:

datanext

链表由一系列不必在内存中相连的结构构成,这些对象按线性顺序排序。每个结构含有表元素和指向后继元素的指针。最后一个单元的指针指向NULL。为了方便链表的删除与插入操作,可以为链表添加一个表头

删除操作可以通过修改一个指针来实现。

插入操作需要执行两次指针调整。

2、python实现单链表

'1、定义节点类Node'
class Node:
    '''
    data:节点保存的数据
    _next:保存下一个节点对象
    '''
    def __init__(self,data,pnext=None):
        self.data=data
        self._next=pnext
    def __repr__(self):
        '''
        用来定义Node的字节输出,print为输出data.
        '''
        return str(self.data)
    
'2、定义链表类ChainTable'
#链表要包括:属性:,链表头:head,链表长度:length
class ChainTable(object):
    def __init__(self):
        self.head=None
        self.length=0
    
    '2.1、判断是否为空: isEmpty()'
    def isEmpty(self):
        return(self.length==0)
        
    '2.2、增加一个节点(在链表尾添加): append()'
    def append(self,dataOrNode):
        item=None
        if isinstance(dataOrNode,Node):
            #isinstance判断某个对象是否属于某个类。
            item=dataOrNode
        else:
            item=Node(dataOrNode)
        
        if not self.head:
            self.head=item
            self.length+=1
        else:
            node=self.head
            while node._next:
                node=node._next
            node._next=item
            self.length+=1
            

    '2.3、删除一个节点: delete()'
    def delete(self, index):
        if self.isEmpty():
            print("this chain table is empty.")
            return

        if index < 0 or index >= self.length:
            print('error: out of index')
            return
        
        #要注意删除第一个节点的情况
        #如果有空的头节点就不用这样
        #但是我不喜欢弄头节点
        if index == 0:
            self.head = self.head._next
            self.length -= 1
            return

        #prev为保存前导节点
        #node为保存当前节点
        #当j与index相等时就
        #相当于找到要删除的节点
        j = 0
        node = self.head
        prev = self.head
        while node._next and j < index:
            prev = node
            node = node._next
            j += 1

        if j == index:
            prev._next = node._next
            self.length -= 1

    '2.4、插入一个节点: insert()'
    def insert(self, index, dataOrNode):
        if self.isEmpty():
            print("this chain tabale is empty")
            return

        if index < 0 or index >= self.length:
            print("error: out of index")
            return

        item = None
        if isinstance(dataOrNode, Node):
            item = dataOrNode
        else:
            item = Node(dataOrNode)

        if index == 0:
            item._next = self.head
            self.head = item
            self.length += 1
            return

        j = 0
        node = self.head
        prev = self.head
        while node._next and j < index:
            prev = node
            node = node._next
            j += 1

        if j == index:
            item._next = node
            prev._next = item
            self.length += 1

    '2.5、修改一个节点: update()'
    def update(self, index, data):
        if self.isEmpty() or index < 0 or index >= self.length:
            print('error: out of index')
            return
        j = 0
        node = self.head
        while node._next and j < index:
            node = node._next
            j += 1

        if j == index:
            node.data = data

    '2.6、查找一个节点: getItem()'
    def getItem(self, index):
        if self.isEmpty() or index < 0 or index >= self.length:
            print("error: out of index")
            return
        j = 0
        node = self.head
        while node._next and j < index:
            node = node._next
            j += 1

        return node.data

    '2.7、查找一个节点的索引: getIndex()'
    def getIndex(self, data):
        j = 0
        if self.isEmpty():
            print("this chain table is empty")
            return
        node = self.head
        while node:
            if node.data == data:
                return j
            node = node._next
            j += 1

        if j == self.length:
            print("%s not found" % str(data))
            return
    
    '2.8、清空链表: clear()'
    def clear(self):
        self.head = None
        self.length = 0

    def __repr__(self):
        if self.isEmpty():
            return("empty chain table")
        node = self.head
        nlist = ''
        while node:
            nlist += str(node.data) + ' '
            node = node._next
        return nlist
    '2.9、展示链表:show()'
    def show(self):
        n=0
        if self.isEmpty():
            print("this chain table is empty")
            return
        node=self.head
        while n<self.length:
            print("node %d:%s"%(n,node.data))
            node=node._next
            n+=1

    def __getitem__(self, ind):
        if self.isEmpty() or ind < 0 or ind >= self.length:
            print("error: out of index")
            return
        return self.getItem(ind)

    def __setitem__(self, ind, val):
        if self.isEmpty() or ind < 0 or ind >= self.length:
            print("error: out of index")
            return
        self.update(ind, val)

    def __len__(self):
        return self.length

3、创建单链表

chainTable=ChainTable()
for i in range(10):
    chainTable.append(i)
    
chainTable.show()
print('查找data为5的索引:',chainTable.getIndex(5))
print('查找第五个节点的data:',chainTable.getItem(5))
print('将索引为1的位置更新为99:',chainTable.update(1,99))
print('删除索引为4的节点的data:',chainTable.delete(4))
print('在第五个索引出插入100:',chainTable.insert(5,100))
chainTable.show()

运行结果:

node 0:0
node 1:1
node 2:2
node 3:3
node 4:4
node 5:5
node 6:6
node 7:7
node 8:8
node 9:9
查找data为5的索引: 5
查找第五个节点的data: 5
将索引为1的位置更新为99: None
删除索引为4的节点的data: None
在第五个索引出插入100: None
node 0:0
node 1:99
node 2:2
node 3:3
node 4:5
node 5:100
node 6:6
node 7:7
node 8:8
node 9:9

二、循环链表(环形链表)

        将单链表中终端结点的指针域由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为单循环链表,简称循环链表。 代码实现,输入一个单链表的头(head)构造环形链表:

def cyclechaintable(head):
    node = head
    #寻找尾节点
    while node.next:
        node = node.next
    #尾节点指向头结点
    node.next = head
    return head

将两个链表合并成循环链表 (1) 算法思想 假设有A、B两个循环链表,且其尾指针分别为rearA、rearB。

  1. 使A循环链表的尾指针rearA指向(rearA->next)B循环链表的第一个结点(非头结点);
  2. 使B循环链表的尾指针rearB指向(rearB->next)A循环链表的头结点,即就链接成了一个新的循环链表。
def mergetwochainable(headA, headB):
    node1 = headA
    while node1.next:
        node1 = node1.next
    node1.next = headB
    node2 = headB
    while node2.next:
        node2 = node2.next
    node2.next = headA

    return headA

注:循环链表和单链表的主要差异就在于循环的判断条件上,即p.next是否为空。如果最后一个结点的指针域p.next为空则说明该链表为单链表;如果p.next等于头结点则说明该链表为循环链表,假如终端结点的指针域rear,那么rear.next指向头结点。

判断单项链表是否有环

算法思路:用两个指针开始都指向头节点,pA一次移动一个节点,pB一次向后移动两个节点,循环下去……每循环一次,如果pB==NULL,说明没有环(否则不会到达NULL),结束;如果pB==pA(转回来了),说明有环,结束。

def hasCycle(self, head):
    slow = head
    fast = head

    if head == None:
        print 'This chaintable do not has Cycle!'
        return False

    while slow:
        slow = slow.next
        fast = fast.next
        if fast and fast.next:
            fast = fast.next
        else:
            print 'This chaintable do not has Cycle!'
            return False
            break

        if slow == fast:
            print 'This chaintable has Cycle!'
            return True
            break

三、双向链表(感觉双向链表遇到的比较少,就简要介绍)

双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。与单链表的主要区别是,双链表中的结点都有两个指针域,一个指向直接后继,另一个指向直接前驱。用空间换来时间上的性能改进。 (1)插入一个元素 实现思路: a)创建新结点s,分别设置其直接后继、直接前驱 s.prior=p; 
s.next=p.next; b)将新结点s赋值给p.next结点的直接前驱指针(p.next.prior) p.next.prior = s; c)将新结点s赋值p结点的直接后继指针(p.next) p.next = s;(b.c不能互换,否则p.next.prior = p) (2)删除一个元素 实现思路:

p->prior->next=p->next;    //把p->next赋值给p->prior的后继
p->next->prior=p->prior;    //把p->prior赋值给p->next的前驱
free(p);                                 //释放结点p占用的内存空间

参考博客:

面试宝典python数据结构-列表,栈与队列,链表,树,字典

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值