(python)数据结构:单链表

一:

链表(顺序表)和列表的区别:

比如在电影院,你们10个非常要好的朋友去看电影。因为你们10个的关系非常好所以决定要坐在一起。然后你们去电影院一看,发现没有10个连在一起的座位了。此时会有两种情况:

1:你们仗着人多势众,把其他人赶走,硬是腾出了10个连在一起的座位。你们正准备坐下观看,然后警察来了,然后你们就被带走了。

结果:你们因扰乱社会治安被处罚。

2:其中一个朋友说:要不我们分开坐吧。然后你们分开各找了一个座位,为了方便走的时候还一起,你们还分享了自己的位置。

结果:你们美滋滋的看完了电影,然后又一起去网吧开黑。

列表选择了第一种处理方式。链表选择了第二种处理方式。

结果:

选择了列表的程序出现了错误。o(╥﹏╥)o

而选择了链表的程序美滋滋的成功运行。(*^▽^*)

总结如下:

             列表长度固定。存储空间连续。

             链表长度不固定。存储空间可以不连续(但其中每个节点都有下个节点的位置)。

优缺点:

            列表:查找方便。但删除和插入一个元素需要移动大量元素。

             链表:删除和插入数据方便(直接修改节点所指向的位置)。但查找元素需要遍历大量元素。

使用列表还是链表要根据具体情况而定。

二:

链表,顾名思义,表中的每个节点都保存有下一个节点的位置,所有节点串成一条链。

根据指针的不同,可以分为:

         单链表:每个节点都有一个指向下一节点的指针(末尾节点除外)

         双链表:每个节点都有一个指向上一节点的指针和指向下一节点的指针。(头结点无指向上一节点的指针。尾节点无指向下一节点的指针)

         循环链表:为尾节点增加一个指向头节点的指针(对单链表而言)。将头结点上指针指向尾节点,将尾节点的下指针指向头结点(对双链表而言)。

实现链表中的节点:           

class Node:

    """节点类"""
    def __init__(self, data, next = None):
        self._data = data;  # 当前节点保存的数据
        self._next = next;  # 所指向的下一个节点

    def __repr__(self):
        return str(self._data);

实现链表:

      1:初始化方法

class ChainTable:

    """链表类"""
    def __init__(self):
        self._head = None; # 表示链表的头节点
        self._length = 0; # 表示链表的长度
        self._index_next = 0; # 用于_next()函数中的计数

      2:判断链表是否为空的方法(重要)

#  判断链表是否为空
    def _isEmpty(self):
        return (self._length == 0);

     3:向链表中追加元素

 # 向链表末尾追加元素
    def _append(self, DataOrNode):
        """
        :param DataOrNode: 数据或Node类的对象
        :return: None
        """
        # 将数据的类型统一为Node类
        item = None;
        if isinstance(DataOrNode, Node):
            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;

    4:根据传入的索引删除元素

# 根据索引删除数据
    def _delete(self, index):
        """
        :param index: 要删除元素的索引
        :return: None
        """
        if self._isEmpty():
            print("链表为空!!!");
            return;
        if index < 0 and index >= self._length:
            raise IndexError("索引错误!!!");
        if index == 0:
            self._head = self._head._next;
            self._length -= 1;
        else:
            j = 0; # 辅助定位
            prev = self._head;
            node = 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;

    5:在指定位置插入元素

# 在指定位置插入数据
    def _insert(self, index, DataOrNode):
        """
        :param index: 要插入的位置
        :param DataOrNode: 要插入的数据
        :return: None
        """
        if self._isEmpty():
           print("链表为空!!!");
           return;
        if index < 0 and index >= self._length:
            raise IndexError("索引错误!!!");

        # 将数据的类型统一为Node类
        item = None;
        if isinstance(DataOrNode, Node):
            item = DataOrNode;
        else:
            item = Node(DataOrNode);

        if index == 0:  # 如果插入的位置为0
            item._next = self._head;
            self._head = item;
            self._length += 1;
        else:
            j = 0; # 辅助定位
            prev = self._head; # 表示当前节点的上一节点
            node = self._head; # 表示当前节点
            while node._next and j < index: # 保证当前节点不是最后一个节点
                prev = node;
                node = node._next;
                j += 1;
            if j == index:
                prev._next = item;
                item._next = node;
                self._length += 1;

    6:修改某一索引的元素

# 修改某一索引的元素
    def _update(self, index, newData):
        """
        :param index: 要修改元素的索引
        :param newData: 新的元素值
        :return: None
        """
        if self._isEmpty():
           print("链表为空!!!");
           return;
        if index < 0 and index >= self._length:
            raise IndexError("索引错误!!!");
        if index == 0:
            self._head._data = newData;
        else:
            j = 0; # 辅助定位
            node = self._head;
            while node._next and j < index:
                node = node._next;
                j += 1;
            if j == index:
                node._data = newData;

    7:根据索引获得元素

# 根据索引来查找节点的数据
    def _getItem(self, index):
        """
        :param index: 要查找的索引
        :return: Item: 该索引对应的节点
        """
        if self._isEmpty():
            print("链表为空!!!");
            return;
        if index < 0 or index >= self._length:
            raise IndexError("索引错误!!!");
        j = 0; # 辅助定位
        node = self._head; # 表示当前节点
        while node._next and j < index:
            node = node._next;
            j += 1;
        return node;

    8:根据传入的值,找到该元素在链表中的位置(若有多个同值元素,则只返回第一个元素的位置)

 # 根据元素找到改元素的索引, 只返回第一个相同元素的位置
    def _getIndex(self, data):
        """
        :param data:要查找位置的元素
        :return: Index: 该元素在链表中的位置
        """
        if self._isEmpty():
            print("链表为空!!!");
            return;
        j = 0; # 辅助定位
        node = self._head; # 表示当前节点
        while node:
            if node._data == data:
                return j;
            else:
                node = node._next;
                j += 1;
        if j == self._length:
            return None;

    9:清空链表

 #清空链表的方法
    def _clear(self):
        """
        :return: None
        """
        self._head = None;
        self._length = 0;

    10:像生成器一样逐个返回链表中的元素

# 像生成器一样逐个返回链表中的元素
    def _next(self):
        """
        :return: every_data: 链表中的节点
        """
        every_data = self._getItem(self._index_next);
        self._index_next += 1;
        return every_data;

    11:返回链表长度(len()方法)

#  使用 len(ChainTable) 时返回链表的长度
    def __len__(self):
        return self._length;

    12:直接输出链表对象时,返回链表中所有数据组成的字符串

 # 直接输出链表对象时,返回链表中所有数据组成的字符串
    def __repr__(self):
        """
        :return:None
        """
        if self._isEmpty():
            print("链表为空!!!");
            return;
        result = "";
        j = 0; # 辅助定位
        while j < self._length:
            result += str(self._getItem(j)) + " ";
            j += 1;
        return result;

完整代码可参考:https://github.com/shyorange/CommonlyUsedToolsProjects/blob/master/ChainTable.py

三:

要实现循环链表只要将尾节点的 _next 指向头结点即可。这里不再进行讲解。

关于双链表的实现原理与单链表相似,具体分析请看我的下一篇博客。

猜你喜欢

转载自blog.csdn.net/hungpangzi/article/details/84439447
今日推荐