赞
踩
表从存储结构上分为顺序表和链表;
顺序表是指在内存中连续存储的数据存储空间,数组,可以用下标访问每一个单元;
链表是指在内存中不是连续存储而是由指针链连接各个单元的线性存储空间;
0. 线性表:将具有线性关系的数据存储到计算机中所使用的存储结构称为线性表。
线性表的分类:逻辑结构上相邻的数据在实际的物理存储中有两种形式:分散存储和集中存储。
考虑到这两种情况,线性表分为两种,分别解决两种情况下数据的存储问题:
1. 顺序表
顺序表的基本布局
(1) 顺序表的基本形式(数据元素本身连续存储)
顺序表中,数据元素本身连续存储,每个元素所占的存储单元大小固定相同,元素的下标是其逻辑地址,而元素存储的物理地址(实际内存地址)可以通过存储区的起始地址Loc(c0)加上其逻辑地址(第i个元素)与存储单元大小(c)的乘积计算而得;
访问指定元素时无需从头遍历,通过计算便可以获得对应地址,其时间复杂度为O(1)。
顺序表的基本形式如下图:
逻辑地址 | 元素存储 | 物理地址 |
0 | C0 | L0 |
1 | C1 | L0+1*c |
2 | C2 | L0+2*c |
3 | C3 | Lo+3*c |
… | … | … |
n-1 | Cn-1 | L0+(n-1)*c |
(2) 元素外置的顺序表(保存对应元素的地址信息-即链接)
如果元素的大小不统一,则需采用元素外置的形式,将实际数据元素另行存储,而顺序表中各单元位置保存对应元素的地址信息(即链接)。由于每个链接所需的存储量相同,通过公式计算出元素链接的存储位置,而后顺着链接找到实际存储的数据元素。
元素外置的顺序表如下图所示:
顺序表的两种实现方式:一体式结构和分离式结构;
2. 链表
链表实现的最基本元素是节点Node;
每个节点至少要包含2个信息:数据项本身,以及指向下一个节点的引用信息。注意next 为None的意义是没有下一个节点了;
设立一个属性head,保存对第一个节点的引用;空表的head为None; 随着数据项的加入,无序表的head始终指向链条中的第一个节点;
由链表结构我们知道,要访问到整条链上的所有数据项,都必须从表头head开始沿着next链接逐个向后查找。所以添加新数据项最快捷的位置是表头,整个链表的首位置;
单向链表实现代码:(见文末)
3.链表与顺序表的对比
链表失去了顺序表随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大,但对存储空间的使用要相对灵活。
链表与顺序表的各种操作的复杂度如下所示:
操作 | 链表 | 顺序表 |
访问元素 | O(n) | O(1) |
在头部插入\删除 | O(1) | O(n) |
在尾部插入\删除 | O(n) | O(1) |
在中间插入\删除 | O(n)时间花在遍历上 | O(1)数据搬迁 |
注意:
虽然表面看起来复杂度都是O(n),但是链表和顺序表在插入和删除时进行的是完全不同的操作。
链表的主要耗时操作是遍历查找,删除和插入操作本身的复杂度是O(1)。
顺序表查找很快,主要耗时操作是拷贝覆盖。
因为除了目标元素在尾部的特殊情况,顺序表进行插入和删除时需要对操作点之后的所有元素进行前后移位操作,只能通过拷贝和覆盖的方法进行。
单向链表实现代码
- # -*- coding: utf-8 -*-
- """
- Created on Wed Apr 1 20:30:47 2020
- @author: coolgirl
- """
-
- class Node(object):
- """节点"""
- def __init__(self,elem): #初始化
- self.elem=elem
- self.next=None
- class SingleLinkList(object):
- """单链表"""
- def __init__(self,node=None): #node默认参数为None
- self.__head=node ##私有函数,对外不使用
- def is_empty(self): #对象方法,对象方法和类方法有什么区别?
- """链表是否为空"""
- return self.__head==None #如果是空列表返回True __head始终指向首节点;
-
- def length(self):
- """链表长度"""
- #cur游标,用来移动遍历节点
- cur=self.__head
- #count记录数据
- count=0
- while cur != None:
- count+=1
- cur = cur.next
- return count
-
- def travel(self):
- """遍历整个列表"""
- cur=self.__head
- while cur != None:
- print(cur.elem, end=" ")
- cur = cur.next
-
- def add(self,item): #需要有具体的节点
- """"链表头部添加元素,头插法,时间复杂度为O(1)"""
- node=Node(item)
- node.next=self.__head #python里等号寓意是指向!!!! 次数不能弄反!!
- self.__head=node
-
- def append(self,item): #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
-
- def insert(self,pos,item):
- """在指定位置添加元素
- :param pos 从0开始"""
- pre= self.__head
- count=0
- node=Node(item)
- if (pos<0):
- self.add(item)
- elif (pos>self.length()-1):
- self.append(item)
- else:
- while count<(pos-1):
- count+=1
- pre =pre.next
- #当循环退出后,pre指向pos-1位置
- node.next=pre.next
- pre.next=node
-
- pass
- def remove(self,item):
- """删除节点"""
- cur=self.__head
- pre=None
-
- while cur!=None:
- #考虑首节点就是要删除的节点
- if cur.elem==item:
- if cur==self.__head:
- self.__head=cur.next
- else:
- pre.next=cur.next
- break
- else:
- pre=cur
- cur=cur.next
-
- def search(self,item):
- """查找节点是否存在"""
- cur=self.__head
- while cur!=None:
- if cur.elem==item:
- return True
- else:
- cur=cur.next
- return False
-
- if __name__=="__main__":
- ll = SingleLinkList()
- print(ll.is_empty())
- print(ll.length())
-
- ll.append(2)
- ll.add(8)
- ll.append(3)
- ll.append(4)
- ll.append(5)
- ll.append(6)
- ll.insert(2,0)
- ll.insert(-9,0)
- ll.remove(5)
- ll.remove(3)
- ll.travel()
-
- # print(ll.travel())
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。