常见数据结构线性表(数组和链表)python实现

数组

数据在内存中顺序存储,可以通过下标索引。

特点:支持随机访问,索引元素效率高,插入元素和删除元素效率低。

数组存放空间连续,插入元素时需要将插入位置及后面的元素一次往后移动一位,然后将元素插入到空出的插入位置。

python中的list是一个动态数组,支持动态扩容(2^n),list中封装了数组常用的方法:

>>> list = [3, 5, 7]
>>> list.append(9) # 往数组尾部添加元素
>>> list
[3, 5, 7, 9]
>>> list.insert(2,5) # 在指定位置插入元素
>>> list
[3, 5, 5, 7, 9]
>>> list.pop() # 取数组最后一个元素,会从数组中删除该元素
9
>>> list
[3, 5, 5, 7]
>>> list.remove(5) # 删除数组中的指定元素,有多个时只删除第一个
>>> list
[3, 5, 7]
>>> list.index(5) # 查找元素在列表中的位置
1
>>> list.reverse() # 列表反转
>>> list
[7, 5, 3]

在python中通过id()函数来输出列表元素的第地址时,可以看到id的值并不是连续的,这是为什么呢?

>>> arr = ['a','b','c']
>>> for char in arr:
        print(id(char))
2204167613216
2204167611536
2204167474288

因为python的list存的是元素对象的引用而不是元素本身,从下面代码中可以看出来,所以输出的id值是元素对象的引用值,在底层的c语言中是使用数组来实现的。

>>> a = 1
>>> id(a)
1598830848
>>> b = [a]
>>> id(b)
9390640
>>> id(b[0])
1598830848

链表

链表数据在内存中的存储不连续,链表有一系列的节点通过指针依次连接起来,每个节点包含数据域和指针域,数据域存储数据,指针域存储下一个节点的指针。

单向链表

单向链表也叫单链表,是链表中最简单的形式,它的每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。

image.png

因为链表中的数据不是顺序存储的,不能随机访问,因此链表的查询效率低,但是链表在任意位置插入和删除节点时不用移动节点位置,因此插入和删除效率高。

链表实现

通常有以下步骤:

  1. 定义节点
  2. 定义链表
  3. 使用链表
    class Node(object):
        '''1.节点定义'''
    
        def __init__(self,data):
            # 数据域
            self.data = data
            # 指针域,创建时为None
            self.next = None
    
    class SingleList(object):
        '''2.链表定义'''
    
        def __init__(self):
            # 链表头
            self.head = None
         
    if __name__ == '__main__':
        #3.链表使用
        # 创建链表
        singlelist = SingleList()
        # 创建节点
        node1 = Node(3)
        # 将链表头指向节点
        singlelist.head = node1
        # 创建节点往链表上添加
        node2 = Node(5)
        node1.next = node2
        node3 = Node(7)
        node2.next = node3
    
        # 创建临时变量指向头节点
        temp = singlelist.head
        # 取头节点的数据
        print(temp.data)
        # 取下一个节点的数据
        temp = temp.next
        print(temp.data)

    输出结果:

3

5

上面定义并使用了一个单项链表,但是链表的使用很不方便,获取元素添加和获取需要定位到节点,长度也没法知道,所以需要定义一些常用的方法,方便链表的使用。

链表中的常用方法:

  • is_empty() 链表是否为空
  • length() 链表长度
  • items() 获取链表数据迭代器
  • add(item) 链表头部添加元素
  • append(item) 链表尾部添加元素
  • insert(pos, item) 指定位置添加元素
  • remove(item) 删除节点
  • find(item) 查找节点是否存在
class Node(object):
    '''节点定义'''

    def __init__(self,data):
        # 数据域
        self.data = data
        # 指针域,创建时为None
        self.next = None

class SingleList(object):
    '''链表定义'''

    def __init__(self):
        # 链表头
        self.head = None

    def is_empty(self):
        '''链表判空'''
        return self.head is None

    def length(self):
        '''链表长度'''
        # 获取初始的头指针
        cur = self.head
        count = 0
        while cur is not None:
            count += 1
            # 指针后移1位
            cur = cur.next
        return count

    def datas(self):
        '''链表遍历'''
        cur = self.head
        while cur is not None:
            # 返回生成器
            yield cur.data
            # 指针后移1位
            cur = cur.next

    def add(self,data):
        '''在头部插入节点'''
        # 创建新节点
        node = Node(data)
        # 新节点指向原头节点
        node.next = self.head
        # 头节点指向新节点
        self.head = node

    def append(self,data):
        '''向尾部插入节点'''
        node = Node(data)
        if self.is_empty():
            # 空链表则直接将head指向node
            self.head = node
        else:
            cur = self.head
            while cur.next is not None:
                # 将指针移到最后一个节点
                cur = cur.next
            # 将最后一个节点的指针指向node
            cur.next = node

    def insert(self,index,data):
        '''任意位置插入节点'''
        if index <= 0:
            # 在头部插入
            self.add(data)
        elif index >= self.length():
            # 在尾部插入
            self.append(data)
        else:
            cur = self.head
            for i in range(index - 1):
                cur = cur.next
                # 创建新节点
            node = Node(data)
            # 将新节点指向就节点
            node.next = cur.next
            # 将旧节点前一个节点指向新节点
            cur.next = node

    def remove(self, item):
        """ 删除一个结点 """
        if self.is_empty():
            return
        cur = self.head
        pre = None
        # 第一个元素为需要删除的元素
        if cur.data == item:
            if cur.next != None:
                cur.next = self.head.next
                # 调整头部结点
                self.head = self.head.next
            else:
                # 只有一个元素
                self.head = None
        else:
            # 不是第一个元素
            pre = self.head
            while cur.next != self.head:
                if cur.data == item:
                    # 删除
                    pre.next = cur.next
                    return True
                else:
                    pre = cur  # 记录前一个指针
                    cur = cur.next  # 调整指针位置
        # 当删除元素在末尾
        if cur.data == item:
            pre.next = self.head
            return True

    def find(self, data):
        """ 查找元素是否存在"""
        return data in self.datas()

    def printlist(self):
        '''打印链表元素'''
        print('当前链表:')
        for i in self.datas():
            print(i)

if __name__ == '__main__':
    # 创建链表
    singlelist = SingleList()
    
    #添加节点
    singlelist.add(3)
    singlelist.append(5)
    singlelist.append(7)
    # 链表长度
    length = singlelist.length()
    print('链表长度:',length)

    singlelist.printlist()

    # 删除元素
    singlelist.remove(5)
    print('--删除元素--')
    singlelist.printlist()

    # 任意位置插入元素
    singlelist.insert(2,666)
    print('--任意位置插入元素--')
    singlelist.printlist()

双向链表

双向链表与与单向链表的区别在于,双向链表的节点包含了两个指针域,如下图,prev指针域指向前一个节点,next指向后一个节点,head指向头节点,第一个节点的prev指针为None,最后一个节点的next为空。

image.png为了方便操作双向链表,也会在链表中定义一些常用的方法。实例如下:

class Node(object):
    '''双链表的节点'''

    def __init__(self,data):
        self.data = data
        self.prev = None
        self.next = None

class DoubleLinkedList(object):
    '''双向链表'''

    def __init__(self):
        self.head = None
        self.tail = None

    def is_empty(self):
        return self.head is None

    def length(self):
        cur = self.head
        count = 0
        while cur is not None:
            cur = cur.next
            count += 1
        return count

    def items(self):
        '''顺序遍历'''
        cur = self.head
        while cur is not None:
            yield cur.data
            cur = cur.next

    def add(self,data):
        '''向链表头部添加节点'''
        node = Node(data)
        if self.head is None:
            self.head = node
            self.tail = node
        else:
            node.next = self.head
            self.head.prev = node
            self.head = node

    def append(self,data):
        '''向链表尾部添加节点'''
        node = Node(data)
        if self.tail is None:
            self.head = node
            self.tail = node
        else:
            node.prev = self.tail
            self.tail.next = node
            self.tail = node

    def insert(self,index,data):
        '''向指定位置添加节点'''
        if index <= 0:
            self.add(data)
        elif index >= self.length():
            self.append(data)
        else:
            node = Node(data)
            cur = self.head
            for i in range(index):
                cur = cur.next
            # 循环完后cur指向节点index了
            node.next = cur
            node.prev = cur.prev
            cur.prev.next = node
            cur.prev = node

    def remove(self, item):
        """ 删除一个结点 """
        if self.is_empty():
            return
        # 当删除的节点在尾部
        if item == self.tail.data:
            self.tail = self.tail.prev
            self.tail.next = None
            return True
        cur = self.head
        pre = None
        # 第一个节点为需要删除的节点
        if cur.data == item:
            # 有多个节点
            if cur.next != None:
                self.head = cur.next
                return True
            # 只有一个节点
            else:
                self.head = None
                return True
        else:
            # 首尾之外的任意节点
            while cur.next != self.tail:
                if cur.data == item:
                    pre.next = cur.next
                    cur.next.prev = pre
                    return True
                else:
                    pre = cur
                    cur = cur.next

    def find(self, data):
        """ 查找节点是否存在"""
        return data in self.items()

    def print_list(self):
        '''打印链表数据'''
        print('链表当前节点:')
        for node in self.items():
            print(node)

if __name__ == '__main__':
    # 实例化双向链表
    doublelist = DoubleLinkedList()
    
    # 向头部添加节点
    doublelist.add(10)
    doublelist.add(20)
    doublelist.print_list()

    # 向尾部添加节点
    doublelist.append(30)
    doublelist.append(40)
    doublelist.print_list()
    
    # 任意位置添加节点
    doublelist.insert(2,666)
    doublelist.print_list()
    
    # 删除首尾和任意节点
    doublelist.remove(666)
    doublelist.remove(20)
    doublelist.remove(40)
    doublelist.print_list()

输出结果:

链表当前节点:

20

10

链表当前节点:

20

10

30

40

链表当前节点:

20

10

666

30

40

链表当前节点:

10

30

其他数据结构:栈、队列、树等的实现可以看:python-data-structure

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值