python数据结构教程第一课

从这里将会正式开始讲解python的一些实用的数据结构,原理加上实例源码。

一、简介

二、线性表的抽象数据类型

三、顺序表的实现

四、链接表的实现

1.单链表

2.带尾指针的单链表

3.循环单链表

4.双链表

5.循环双链表

五、线性表的应用—Josephus问题

1.顺序表解法

2.循环单链表解法

##一、简介 ##

在程序里经常需要将一组数据元素作为整体管理和使用,需要创建这种元素组,用变量记录它们,一组数据中包含的元素个数可能发生变化,也可能会用元素在序列里的位置和顺序,表示实际应用中的某种有意义信息。线性表就是这样一组元素的抽象,其具体实现方式有两种,顺序表和链接表

二、线性表的抽象数据类型(ADT)

线性表的基本操作应当有创建空表、返回长度信息、插入、删除等操作,其基本的ADT如下:

ADT List:

List(self) #创建一个新表

is_empty(self) #判断self是否是一个空表

len(self) #返回表长度

prepend(self,elem) #在表头插入元素

append(self,elem) #在表尾加入元素

insert(self,elem,i) #在表的位置i处插入元素

del_first(self) #删除第一个元素

def_last(self) #删除最后一个元素

del(self,i) #删除第I个元素

search(self,elem) #查找元素在表中第一次出现的位置

forall(self,op) #对表元素的遍历操作,op操作

三、顺序表的实现##

python内部的tuple与list采用的就是顺序表结构,其不同点在于tuple是固定结构,一旦创建就无法进行改动,而list则支持变动操作,具有上述ADT所描述的全部操作,这里不再具体重写类代码,其主要使用命令如下

list1 = list([1,2,3,4,5]) #创建新表

list1.append(6) #在尾部添加新元素 6

k = len(list1) #返回表长度

list1.insert(k,7) #在位置k插入7

list1.pop() #返回并删除尾部元素

print(list1) #输出表的全部元素

list2 = list1[2:] #表的切片操作

顺序表的优势在于O(1)时间的定位元素访问,很多简单的操作效率也比较高,比较麻烦的地方在于,表中间位置元素的插入删除操作,由于元素在顺序表的存储区里连续排列,插入/删除操作可能要移动很多元素,代价很高

四、链接表的实现##

基于链接技术实现的线性表称为链接表或者链表,用链接关系显式表示元素之间的顺序关系,链接表结构的基本思想如下:

1.把表中的元素分别存储在一批独立的存储块(结点)里

2.保证从组成表结构中的任一个结点可找到与其相关的下一个结点

3.在前一结点里用链接的方式显式地记录与下一结点之间的关联

在python里链表的实现有诸多方式和变形,接下来将选取主要的结构进行源码讲解

1.单链表

单链表是最基本也是最常用的链表结构,以下描述了链表的各种方法,包括,插入、排序、删除、融合等

import copy

#单链表结点类

class LNode:

def __init__(self, elem,next_=None):

self.elem = elem

self.next = next_

#链表位置定位错误

class LinkedListUnderflow(ValueError):

pass

#单链表类的具体实现

class LList:

def __init__(self): #初始化操作

self._head = None

self.num = 0 #num记录结点数

def is_empty(self): #空表判定

return self._head is None

def len(self): #返回表长

return self.num

#定位到链表的第loc个元素

def located(self,loc):

if (loc > self.num or loc < 1):

raise LinkedListUnderflow('in located')

temp = self._head

i = 1

if loc == 1:

return temp

else:

while i < loc:

temp = temp.next

i += 1

return temp

#在链表的第loc个位置添加元素elem

def located_add(self,loc,elem):

temp = self.located(loc)

node = LNode(elem)

if loc == 1:

node.next = self._head

self._head = node

else:

node.next = temp.next

temp.next = node

self.num += 1

#在链表的第loc个位置删除元素

def located_del(self,loc):

temp = self.located(loc)

if loc == 1:

self._head = self._head.next

else:

temp.next = temp.next.next

self.num -= 1

#表头插入元素

def prepend(self,elem):

self._head = LNode(elem,self._head)

self.num += 1

#返回并删除表头元素

def pop(self):

if self._head is None:

raise LinkedListUnderflow('in pop')

e = self._head.elem

self._head = self._head.next

self.num -= 1

return e

#在表尾添加元素

def append(self,elem):

if self._head is None:

self._head = LNode(elem)

self.num += 1

return

p = self._head

while p.next is not None:

p = p.next

p.next = LNode(elem)

self.num += 1

#返回并删除表尾元素

def pop_last(self):

if self._head is None:

raise LinkedListUnderflow('in pop_last')

p = self._head

if p.next is None:

e = p.elem

self._head = None

self.num -= 1

return e

while p.next.next is not None:

p = p.next

e = p.next.elem

p.next = None

self.num -= 1

return e

#返回表中所有满足pred()操作的元素

def filter(self,pred):

p = self._head

while p is not None:

if pred(p.elem):

yield p.elem

p = p.next

#输出表中的全部元素

def printall(self):

p = self._head

while p is not None:

print(p.elem,end='')

if p.next is not None:

print(', ',end='')

p = p.next

print('')

#对表中的所有元素执行proc操作

def for_each(self,proc):

p = self._head

while p is not None:

proc(p.elem)

p = p.next

#使链表支持iterator操作

def elements(self):

p = self._head

while p is not None:

yield p.elem

p = p.next

#链表倒置

def rev(self):

p = None

while self._head is not None:

q = self._head

self._head = q.next

q.next = p

p = q

self._head = p

#链表从小到大排序

def sort(self):

if self._head is None:

return

crt = self._head.next

while crt is not None:

x = crt.elem

p = self._head

while p is not crt and p.elem <= x:

p = p.next

while p is not crt:

y = p.elem

p.elem = x

x = y

p = p.next

crt.elem = x

crt = crt.next

#第二种排序算法

def sort1(self):

p = self._head

if p is None or p.next is None:

return

rem = p.next

p.next = None

while rem is not None:

p = self._head

q = None

while rem is not None and p.elem <= rem.elem:

q = p

p = p.next

if q is None:

self._head = rem

else:

q.next = rem

q = rem

rem = rem.next

q.next = p

#第三种排序算法

def sort2(self):

list1 = copy.deepcopy(self)

if list1._head.next is None:

return

list1._head.next.next = None

if list1._head.next.elem < list1._head.elem:

a = list1._head

list1._head = list1._head.next

list1._head.next = a

list1._head.next.next = None

temp = self._head.next.next

while temp is not None:

p = list1._head

q = list1._head.next

if temp.elem < list1._head.elem:

a = temp.next

temp.next = list1._head

list1._head = temp

temp = a

if temp is not None:

print(temp.elem)

list1.printall()

elif temp.elem >= list1._head.elem:

while q is not None:

if q.elem >= temp.elem:

a = temp.next

temp.next = q

p.next = temp

temp = a

break

elif q.elem < temp.elem:

q = q.next

p = p.next

if q is None:

p.next = temp

a = temp.next

temp.next = None

temp = a

self._head = list1._head

#链表深拷贝操作

def deep_copy(self):

Co = copy.deepcopy(self)

return Co

#链表相等判断

def __eq__(self,List1):

Co1 = self.deep_copy()

Co2 = List1.deep_copy()

Co1.sort()

Co2.sort()

temp1 = Co1._head

temp2 = Co2._head

while Co1.len() == Co2.len() and temp1 is not None and temp2 is not None and temp1.elem == temp2.elem:

temp1 = temp1.next

temp2 = temp2.next

return temp1 is None and temp2 is None

#链表按字典序,< 运算函数

def __lt__(self,other):

temp1 = self._head

temp2 = other._head

while temp1 is not None and temp2 is not None:

if temp1.elem < temp2.elem:

return True

elif temp1.elem > temp2.elem:

return False

else:

temp1 = temp1.next

temp2 = temp2.next

if temp1 is None and temp2 is not None:

return True

else:

return False

#链表按字典序,=< 运算函数

def __le__(self,other):

temp1 = self._head

temp2 = other._head

while temp1 is not None and temp2 is not None:

if temp1.elem < temp2.elem:

return True

elif temp1.elem > temp2.elem:

return False

else:

temp1 = temp1.next

temp2 = temp2.next

if temp1 is None:

return True

else:

return False

#链表按字典序 >= 运算函数

def __ge__(self,other):

temp1 = self._head

temp2 = other._head

while temp1 is not None and temp2 is not None:

if temp1.elem > temp2.elem:

return True

elif temp1.elem < temp2.elem:

return False

else:

temp1 = temp1.next

temp2 = temp2.next

if temp2 is None:

return True

else:

return False

#链表按字典序,> 运算函数

def __gt__(self,other):

temp1 = self._head

temp2 = other._head

while temp1 is not None and temp2 is not None:

if temp1.elem > temp2.elem:

return True

elif temp1.elem < temp2.elem:

return False

else:

temp1 = temp1.next

temp2 = temp2.next

if temp2 is None and temp1 is not None:

return True

else:

return False

#链表反向遍历,执行对每个元素执行op操作

def rev_visit(self,op):

temp = copy.deepcopy(self)

temp.rev()

head = temp._head

while head is not None:

op(head.elem)

head = head.next

#删除表中的elem

def del_elem(self,elem):

a = self._head

b = self._head.next

if a is None:

return

if a.elem == elem:

self._head = b

while b is not None:

if b.elem == elem:

a.next = b.next

a = a.next

b = b.next

#删除表中最小元素

def del_minimal(self):

temp = copy.deepcopy(self)

temp.sort()

elem = temp._head.elem

self.del_elem(elem)

#删除表中所有满足pred操作的元素

def del_if(self,pred):

temp = self._head

while temp is not None:

if pred(temp.elem):

self.del_elem(temp.elem)

temp = temp.next

#返回一个字典,字典记录了表中每个元素出现的次数

def elem_num(self):

temp = self._head

adict = dict()

while temp is not None:

if temp.elem not in adict:

adict[temp.elem] = 1

else:

adict[temp.elem] += 1

temp = temp.next

return adict

#删除链表中出现的重复项,第一次不变

def del_duplicate(self):

temp1 = self._head

temp2 = self._head.next

adict = self.elem_num()

if adict[temp1.elem] > 1:

adict[temp1.elem] *= -1

while temp2 is not None:

if adict[temp2.elem] > 1:

adict[temp2.elem] *= -1

temp1 = temp1.next

elif adict[temp2.elem] < 0:

temp1.next = temp2.next

else:

temp1 = temp1.next

temp2 = temp2.next

print(adict)

#两个链表的交叉融合为一个链表

def interleaving(self,another):

temp1 = self._head

temp2 = another._head

while temp1 is not None and temp2 is not None:

p = temp1.next

temp1.next = temp2

q = temp2.next

temp2.next = p

temp1 = p

temp2 = q

if temp1 is None:

p = self._head

while p.next is not None:

p = p.next

p.next = temp1

以上描述了单链表的众多方法,单链表还存在很多别的形态,可以让很多操作变的简洁有效率

2.带尾结点的单链表

单链表对尾部结点的访问效率是十分低下的,需要遍历表中之前的全部结点,当单链表带上尾部指针时,这种操作就会变的有效率很多

#带尾结点的单链表,继承自单链表,支持其的全部属性和方法

class LList1(LList):

def __init__(self): #初始化,新添了—rear作为尾结点

LList.__init__(self)

self._rear = None

#首部结点插入方法

def prepend(self,elem):

self._head = LNode(elem,self._head)

if self._rear is None:

self._rear = self._head

#尾部结点方法重写

def append(self,elem):

if self._head is None:

self._head = LNode(elem,self._head)

self._rear = self._head

else:

self._rear.next = LNode(elem)

self._rear = self._rear.next

#返回并删除最后一个结点

def pop_last(self):

if self._head is None:

raise LinkedListUnderflow('in pop_last')

p = self._head

if p.next is None:

e = p.elem

self._head = None

return e

while p.next.next is not None:

p = p.next

e = p.next.elem

p.next = None

self._rear = p

return e

3.循环单链表

使单链表的尾指针指向首结点,就构成了循环单链表,其与单链表的不同在于,其扫描循环结束的控制判断

class LCList: #循环单链表

def __init__(self):

self._rear = None

#空链表判断

def is_empty(self):

return self._rear is None

#前端插入

def prepend(self,elem):

p = LNode(elem)

if self._rear is None:

p.next = p

self._rear = p

else:

p.next = self._rear.next

self._rear.next = p

#尾端插入

def append(self,elem):

self.prepend(elem)

self._rear = self._rear.next

#尾端返回并删除

def pop(self):

if self._rear is None:

raise LinkedListUnderflow('in pop of CLList')

p = self._rear.next

if self._rear is p:

self._rear = None

else:

self._rear.next = p.next

return p.elem

#输出所有结点内容

def printall(self):

if self.is_empty():

return

p = self._rear.next

while True:

print(p.elem,end = " ")

if p is self._rear:

break

p = p.next

#两个链表交叉融合为一个链表

def interleaving(self,another):

temp1 = self._rear.next

temp2 = another._rear.next

while temp1 is not self._rear and temp2 is not another._rear:

a = temp2.next

temp2.next = temp1.next

temp1.next = temp2

temp2 = a

temp1 = temp1.next.next

if temp1 is self._rear:

while temp2 is not another._rear:

self.append(temp2.elem)

temp2 = temp2.next

4.双链表

在单链表中,除了首结点和尾结点外,每个元素不但指向它的下一个结点,还会指向它的上一个结点,双链表支持更简单的反向遍历操作,双链表需要双结点类支持

#双结点类

class DLNode(LNode):

def __init__(self,elem,prev = None,next_ = None):

LNode.__init__(self,elem,next_)

self.prev = prev

#双链表继承自带首尾指针的单链表,不过需要重写添加和删除方法

class DLList(LList1):

def __init__(self): #初始化

LList1.__init__(self)

#使用双向结点前端插入

def prepend(self,elem):

p = DLNode(elem,None,self._head)

if self._head is None:

self._rear = p

else:

p.next.prev = p

self._head = p

#首端返回并删除

def pop(self):

if self._head is None:

raise LinkedListUnderflow('in pop of DLList')

e = self._head.elem

self._head = self._head.next

if self._head is not None:

self._head.prev = None

return e

#尾端返回并删除

def pop_last(self):

if self._head is None:

raise LinkedListUnderflow('in pop_last of DLList')

e = self._rear.elem

self._rear = self._rear.prev

if self._rear is None:

self._head = None

else:

self._rear.next = None

return e

5.循环双链表

双链表的尾部首部互指,构成循环双链表

class DCLList():

def __init__(self): #双链表类

self._head = None

self.__num = 0

#尾端插入

def append(self,elem):

p = DLNode(elem,None,None)

if self._head is None:

p.next = p

p.prev = p

self._head = p

else:

p.prev = self._head.prev

p.next = self._head

self._head.prev.next = p

self._head.prev = p

self.__num += 1

#尾部返回并删除

def pop(self):

if self._head is None:

raise LinkedListUnderflow('in pop_last of DCLList')

elem = self._head.prev.elem

self._head.prev.prev.next = self._head

self._head.prev = self._head.prev.prev

self.__num -= 1

return elem

#返回长度

def len(self):

return self.__num

#链表倒置

def reverse(self):

q = self._head

p = self._head.prev

n = 1

while p is not q and n <= self.len()/2:

t = p.elem

p.elem = q.elem

q.elem = t

q = q.next

p = p.prev

n += 1

#链表元素排序

def sort(self):

i = 0

while i < self.len():

j = 0

p = self._head

while j < self.len()-i-1:

if p.elem > p.next.elem:

t = p.elem

p.elem = p.next.elem

p.next.elem = t

j += 1

p = p.next

self.printall()

i += 1

#链表倒置算法2

def reverse1(self):

li = DCLList()

p = self._head.prev

for i in range(self.len()):

li.append(p.elem)

p = p.prev

i += 1

self._head = li._head

#链表排序算法2

def sort1(self):

i = 0

while i < self.len()-1:

j = 0

p = self._head.next

while j < self.len()-i-2:

if p.elem > p.next.elem:

a = p.prev

b = p.next.next

c = p.next

a.next = c

c.prev = a

c.next = p

p.prev = c

p.next = b

b.prev = p

else:

p = p.next

j += 1

i += 1

i = 0

p = self._head.next

elem = self._head.elem

while i < self.len()-1:

if p.elem <= elem and p.next.elem > elem:

a = self._head

b = self._head.prev

c = self._head.next

b.next = c

c.prev = b

a.next = p.next

p.next.prev = a

p.next = a

a.prev = p

self._head = c

break

i += 1

p = p.next

if i == self.len()-1:

self._head = self._head.next

#输出链表元素

def printall(self):

p = self._head

for i in range(self.len()):

print(p.elem,end = ' ')

p = p.next

print()

以上介绍了链表的众多基本与高级操作,以及链表的各种形态变形,链表的优势在于,表元素之间的顺序由它们所在的结点之间的链接显式表示,因此表结点可以任意安排位置,灵活的调整结构。

同时,为了实现链接表,每个结点都增加了一个链接域,付出了额外的空间代价,链表的位置访问代价很高,需要一个个结点的遍历,使用链表最合理的方式是前端操作和顺序访问

五、线性表的应用—Josephus问题

这里举出一个经典的问题来描述链表的用法

Josephus问题:

假设有n个人围坐一圈,现要求从第k个人开始报数,报到第m个数的人退出。然后从下一个人开始继续报数并按同样的规则退出,直至所有人退出,要求按顺序输出各出列人的编号

方法1.我们可以用list实现算法:

def josephus_A(n,k,m):

people = list(range(1,n+1))

i = k - 1

for num in range(n):

count = 0

while count < m:

if people[i] > 0:

count += 1

if count == m:

print(people[i],end = ' ')

people[i] = 0

i = (i+1) % n

if num < n - 1:

print(',',end = '')

else:

print('')

return

方法2.如果我们该用循环单链表,会发现问题简单了很多:

class Josephus(LCList):

def turn(self,m):

for i in range(m):

self._rear = self._rear.next

def __init__(self,n,k,m):

LCList.__init__(self)

for i in range(n):

self.append(i+1)

self.turn(k-1)

while not self.is_empty():

self.turn(m-1)

print(self.pop(),end = ('\n' if self.is_empty() else ','))

假设有13个人,从第5个人开始报数,数为6,则两种算法的使用和结果为:

算法1:

josephus_A(13,5,6)

算法2:

Josephus(13,5,6)

python删除链表满足pred的元素_python 数据结构一 之 线性表相关推荐

  1. python 删除链表中的重复元素

    | 删除链表中的重复元素 存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除所有重复的元素,使每个元素 只出现一次 . 返回同样按升序排列的结果链表. 输入:head = [1,1, ...

  2. python删除链表中的最小元素_LintCode Python 入门级题目 删除链表元素、整数列表排序...

    删除链表元素: 循环列表head,判断当前指针pre.next的val是否等于val, 如果是,当前pre重指向pre.next.next, 直至pre.next = Null # Definitio ...

  3. python删除list多个相同元素_python删除list中的重复元素

    可以使用append方法实现. 首先设一个临时列表保存结果,然后从头遍历原列表,如临时列表中没有当前元素则追加. 具体代码: 给定一个列表,要求删除列表中重复元素.listA = ['python', ...

  4. python删除列表第几个元素_python中对列表list遍历的过程中删除元素4种方法

    代码存储库,记录在删除列表中指定元素代码 背景:li=[1,2,3,2,1,3,4,6,73,5,1,3,1,2,4] 列表中的所有等于1,2,3的值 解决方法: 第一种使用逆序遍历num_list ...

  5. python删除列表中的重复元素并保持相对顺序不变

    python删除列表中的重复元素并保持相对顺序不变 从列表中删除重复项以便所有元素都是唯一的同时保持原有相对顺序不变 对于列表我们可以使用如下方法: l1 = [1,7,7,8,5,5,4] l2 = ...

  6. python 删除列表中的指定元素

    python 删除列表中的指定元素 def delete_list(list1,ele):"""删除列表中的指定元素:param list1:原列表:param ele: ...

  7. 算法:删除链表中重复的元素||

    //删除链表中重复的元素方法1:利用哈希表去重,然后遍历哈希表新建节点方法2:双指针 class Solution {public ListNode deleteDuplicates(ListNode ...

  8. Algorithms_基础数据结构(04)_线性表之链表_单向循环链表约瑟夫环问题

    文章目录 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 约瑟夫问题 结构 分析 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 tip:单向链表 约瑟夫问题 N个人围成一圈, ...

  9. python中删除字典中的某个元素_python怎样删除字典中的元素

    python删除字典中元素的方法: 1.使用clear()方法删除字典内所有元素 clear()方法语法:dict.clear() 示例:dict = {'Name': 'Zara', 'Age': ...

最新文章

  1. 独家 | 集成学习入门介绍
  2. 开发音频频谱_ToneBoosters音频效果器插件合集
  3. saltstack二次开发构建自己的api
  4. 【aelf开发者社区招募】重构 C#代码--中高级工程师预期小半天到一天
  5. Altium Designer隐藏或显示元件名字
  6. 【Linux】一步一步学Linux——unset命令(202)
  7. 创建WebPart时的数据库连接问题。
  8. Zookeeper一致性协议原理Zab
  9. hadoop hdfs (java api)
  10. centos6 postgresql安装
  11. 算法(二):分而治之
  12. day、11闭包函数和装饰器
  13. drbd相关知识点解析
  14. 历时2年《爱上Android》出版了
  15. Web API-document
  16. android 8 wifi 信号等级
  17. C++ STL算法系列5---equal() , mismatch()
  18. matlab冲激函数的傅里叶变换,信号与系统课件14.ppt
  19. 【游戏开发】游戏开发书籍汇总
  20. 网络爬虫是什么意思?

热门文章

  1. 每日程序C语言25-查找100以内的素数
  2. 8266串口调试助手_开源软件分享-基于WPF的串口调试工具
  3. java boxplot_Matlab Boxplots
  4. vat可以退税吗_【涨知识】企业对外投资可以申请出口退税吗?
  5. MVP+WCF+三层结构搭建项目框架(上)
  6. spark dataFrame withColumn
  7. 1.4最基本的使用--POM.xml文件
  8. kafka自带没web ui界面,怎么办?安装个第三方的
  9. Lucene之Java实战
  10. 修改 wordpress 后台管理员登录地址