大话数据结构 - 链表

1. 顺序表的缺陷
线性表的顺序存储结构有致命的缺陷, 由于地址的连续性, 插入和删除都需要移动大量的元素。其次是在C、C++等语言中,数组的长度有限,这可能带来极大的不便。

2. 链表 - 线性表的链式存储结构
链表为了摆脱顺序表的缺陷, 从物理结构上链表各个元素是随机位置, 而不是连续存储; 这样也就导致了每个节点除了存储本身的数据之外还需要存储下一个节点的地址;

这是的插入和删除非常方便, 但是无法像顺序表那样直接获取某个位置的元素, 只能从头结点往下遍历。


3. 单链表的Python实现

# -*- coding: utf-8 -*-

class Node:
    def __init__(self, data):
        # 链表节点类, 数据域及指针域
        self.data = data
        self.next = None
        
class Linklist:
    """
    线性表的链式存储结构: 链表
    
    属性:
        头结点, 链表长度
    
    方法:
        1. 获取链表中第i个位置的元素
        2. 向链表任意位置插入元素
        3. 删除链表任意位置的一个元素
        
    几乎所有的链表操作, 都是先要引用链表的头结点
    
    """
    def __init__(self, node):
        # 头结点, 链表长度
        self.head = node
        self.length = 1
        
    def _get_list_length(self):
        # 获取链表的长度
        current = self.head
        length = 0
        while current != None:
            current = current.next
            length += 1
        return length
    
    def get_i_ele(self, i):
        # 1. 获取链表中第i个位置的元素
        if i not in range(0, self.length): raise(Exception("输入参数错误"))
        
        current = self.head; k = 0
        while i != k: 
            current = current.next
            k += 1
        return current.data
        
    def insert(self, i, data):
        # 2. 向链表任意位置插入元素
        if i not in range(0, self.length+1): raise(Exception("输入参数错误"))
        current = self.head
        if i != 0:
            k = 0
            while k < i: 
                if k == i - 1: previous_node = current # 待插入节点的上一个节点
                current = current.next
                k += 1
            inserted_node = Node(data) # 新建一个待插入的节点
            previous_node.next = inserted_node # 把上一个节点指向待插入节点
            inserted_node.next = current # 待插入的节点指向下一个节点
       
        # 插入的位置是头结点
        else:
            inserted_node = Node(data)  # 新建一个待插入的节点
            self.head = inserted_node # 把头结点变成待插入的节点
            self.head.next = current
            
        # 更新链表的长度
        self.length += 1
        
    def delete(self, i):
        # 3. 删除链表中第i个位置的元素
        if i not in range(0, self.length+1): raise(Exception("输入参数错误"))
        current = self.head
        length = self.length
        for j in range(length):
            if j == i-1:
                previous_node = current
                break
            current = current.next
        current = current.next.next
        previous_node.next = current
        self.length -= 1
        
    def clear_list(self):
        # 清空整个链表
        self.head = None
        self.length = 0
        
    def print_List(self):
        # 打印整个链表
        current = self.head
        k = 0
        print("\n")
        while current != None:
            print("链表中的第{0}个元素 = {1}".format(k, current.data))
            current = current.next
            k += 1
            
def test():
    # 创建头结点
    node = Node(0)
    
    # 创建链表
    List = Linklist(node)
    
    print("\n链表的长度 = {0}".format(List.length))
    
    # 向链表中插入节点
    for i in range(1,10):
        List.insert(i, i)
    List.insert(0, 100)
    
    # 打印当前链表
    List.print_List()
    
    # 删除节点
    List.delete(7)
    
    # 打印当前链表
    List.print_List()
    
    # 清空整个链表
    List.clear_list()
    
    # 打印当前链表
    List.print_List()    

4. 单链表与顺序表

1)若需要频繁读取时,应采用顺序表,比如网站的用户注册信息,一般较少修改,读取较多,宜采用顺序表;而游戏中玩家的装备,道具等等经常发生增加和删除等操作,此时更易使用链表。

2)当线性表中的元素个数变化变化太大,或者个数难以估计时,宜采用链表


5. 循环链表与双向链表

循环链表:单链表的操作核心就是抓住表头,但是通常一个链表除了表头,表尾也是我们经常需要的。循环链表就是让表尾的指针不再指到null而是指到表头。因此这儿也是循环链表和单链表操作上的最大区别:单链表是判断p->next是否为空来判断程序是否终止;而循环链表是判断p->next是否等于头结点来判断程序是否终止。

双向链表:单链表的节点类包括一个指针和数据,其中指针的不断传递和连接构成了链表的方向性。那么显然双向链表就是每个节点有两个指针,分别指向上一个节点和下一个节点。这样一来虽然使用更方便,但是结构就变得更复杂,比如在删除和插入节点时需要同时更改上游节点和下游节点四个指针的指向。


猜你喜欢

转载自blog.csdn.net/zk_j1994/article/details/78089113