一、单链表
1、单链表简介
数据结构是计算机科学必须掌握的一门学问,之前很多的教材都是用C语言实现链表,因为c有指针,可以很方便的控制内存,很方便就实现链表,其他的语言,则没那么方便,有很多都是用模拟链表,不过这次,我不是用模拟链表来实现,因为python是动态语言,可以直接把对象赋值给新的变量。
好了,在说我用python实现前,先简单说说链表吧。在我们存储一大波数据时,我们很多时候是使用数组,但是当我们执行插入操作的时候就是非常麻烦,看下面的例子,有一堆数据1,2,3,5,6,7我们要在3和5之间插入4,如果用数组,我们会怎么做?当然是将5之后的数据往后退一位,然后再插入4,这样非常麻烦,但是如果用链表,我就直接在3和5之间插入4就行,听着就很方便。
链表的结构:链表像锁链一样,由一节节节点连在一起,组成一条数据链。 链表的节点的结构如下: data next data为自定义的数据,next为下一个节点的地址。 链表的结构为,head保存首位节点的地址:
链表的节点的结构如下:
data | next |
链表由一系列不必在内存中相连的结构构成,这些对象按线性顺序排序。每个结构含有表元素和指向后继元素的指针。最后一个单元的指针指向NULL。为了方便链表的删除与插入操作,可以为链表添加一个表头
删除操作可以通过修改一个指针来实现。
插入操作需要执行两次指针调整。
2、python实现单链表
'1、定义节点类Node'
class Node:
'''
data:节点保存的数据
_next:保存下一个节点对象
'''
def __init__(self,data,pnext=None):
self.data=data
self._next=pnext
def __repr__(self):
'''
用来定义Node的字节输出,print为输出data.
'''
return str(self.data)
'2、定义链表类ChainTable'
#链表要包括:属性:,链表头:head,链表长度:length
class ChainTable(object):
def __init__(self):
self.head=None
self.length=0
'2.1、判断是否为空: isEmpty()'
def isEmpty(self):
return(self.length==0)
'2.2、增加一个节点(在链表尾添加): append()'
def append(self,dataOrNode):
item=None
if isinstance(dataOrNode,Node):
#isinstance判断某个对象是否属于某个类。
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
'2.3、删除一个节点: delete()'
def delete(self, index):
if self.isEmpty():
print("this chain table is empty.")
return
if index < 0 or index >= self.length:
print('error: out of index')
return
#要注意删除第一个节点的情况
#如果有空的头节点就不用这样
#但是我不喜欢弄头节点
if index == 0:
self.head = self.head._next
self.length -= 1
return
#prev为保存前导节点
#node为保存当前节点
#当j与index相等时就
#相当于找到要删除的节点
j = 0
node = self.head
prev = 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
'2.4、插入一个节点: insert()'
def insert(self, index, dataOrNode):
if self.isEmpty():
print("this chain tabale is empty")
return
if index < 0 or index >= self.length:
print("error: out of index")
return
item = None
if isinstance(dataOrNode, Node):
item = dataOrNode
else:
item = Node(dataOrNode)
if index == 0:
item._next = self.head
self.head = item
self.length += 1
return
j = 0
node = self.head
prev = self.head
while node._next and j < index:
prev = node
node = node._next
j += 1
if j == index:
item._next = node
prev._next = item
self.length += 1
'2.5、修改一个节点: update()'
def update(self, index, data):
if self.isEmpty() or index < 0 or index >= self.length:
print('error: out of index')
return
j = 0
node = self.head
while node._next and j < index:
node = node._next
j += 1
if j == index:
node.data = data
'2.6、查找一个节点: getItem()'
def getItem(self, index):
if self.isEmpty() or index < 0 or index >= self.length:
print("error: out of index")
return
j = 0
node = self.head
while node._next and j < index:
node = node._next
j += 1
return node.data
'2.7、查找一个节点的索引: getIndex()'
def getIndex(self, data):
j = 0
if self.isEmpty():
print("this chain table is empty")
return
node = self.head
while node:
if node.data == data:
return j
node = node._next
j += 1
if j == self.length:
print("%s not found" % str(data))
return
'2.8、清空链表: clear()'
def clear(self):
self.head = None
self.length = 0
def __repr__(self):
if self.isEmpty():
return("empty chain table")
node = self.head
nlist = ''
while node:
nlist += str(node.data) + ' '
node = node._next
return nlist
'2.9、展示链表:show()'
def show(self):
n=0
if self.isEmpty():
print("this chain table is empty")
return
node=self.head
while n<self.length:
print("node %d:%s"%(n,node.data))
node=node._next
n+=1
def __getitem__(self, ind):
if self.isEmpty() or ind < 0 or ind >= self.length:
print("error: out of index")
return
return self.getItem(ind)
def __setitem__(self, ind, val):
if self.isEmpty() or ind < 0 or ind >= self.length:
print("error: out of index")
return
self.update(ind, val)
def __len__(self):
return self.length
3、创建单链表
chainTable=ChainTable()
for i in range(10):
chainTable.append(i)
chainTable.show()
print('查找data为5的索引:',chainTable.getIndex(5))
print('查找第五个节点的data:',chainTable.getItem(5))
print('将索引为1的位置更新为99:',chainTable.update(1,99))
print('删除索引为4的节点的data:',chainTable.delete(4))
print('在第五个索引出插入100:',chainTable.insert(5,100))
chainTable.show()
运行结果:
node 0:0
node 1:1
node 2:2
node 3:3
node 4:4
node 5:5
node 6:6
node 7:7
node 8:8
node 9:9
查找data为5的索引: 5
查找第五个节点的data: 5
将索引为1的位置更新为99: None
删除索引为4的节点的data: None
在第五个索引出插入100: None
node 0:0
node 1:99
node 2:2
node 3:3
node 4:5
node 5:100
node 6:6
node 7:7
node 8:8
node 9:9
二、循环链表(环形链表)
将单链表中终端结点的指针域由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为单循环链表,简称循环链表。 代码实现,输入一个单链表的头(head)构造环形链表:
def cyclechaintable(head):
node = head
#寻找尾节点
while node.next:
node = node.next
#尾节点指向头结点
node.next = head
return head
将两个链表合并成循环链表 (1) 算法思想 假设有A、B两个循环链表,且其尾指针分别为rearA、rearB。
- 使A循环链表的尾指针rearA指向(rearA->next)B循环链表的第一个结点(非头结点);
- 使B循环链表的尾指针rearB指向(rearB->next)A循环链表的头结点,即就链接成了一个新的循环链表。
def mergetwochainable(headA, headB):
node1 = headA
while node1.next:
node1 = node1.next
node1.next = headB
node2 = headB
while node2.next:
node2 = node2.next
node2.next = headA
return headA
注:循环链表和单链表的主要差异就在于循环的判断条件上,即p.next是否为空。如果最后一个结点的指针域p.next为空则说明该链表为单链表;如果p.next等于头结点则说明该链表为循环链表,假如终端结点的指针域rear,那么rear.next指向头结点。
判断单项链表是否有环
算法思路:用两个指针开始都指向头节点,pA一次移动一个节点,pB一次向后移动两个节点,循环下去……每循环一次,如果pB==NULL,说明没有环(否则不会到达NULL),结束;如果pB==pA(转回来了),说明有环,结束。
def hasCycle(self, head):
slow = head
fast = head
if head == None:
print 'This chaintable do not has Cycle!'
return False
while slow:
slow = slow.next
fast = fast.next
if fast and fast.next:
fast = fast.next
else:
print 'This chaintable do not has Cycle!'
return False
break
if slow == fast:
print 'This chaintable has Cycle!'
return True
break
三、双向链表(感觉双向链表遇到的比较少,就简要介绍)
双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。与单链表的主要区别是,双链表中的结点都有两个指针域,一个指向直接后继,另一个指向直接前驱。用空间换来时间上的性能改进。 (1)插入一个元素 实现思路: a)创建新结点s,分别设置其直接后继、直接前驱 s.prior=p;
s.next=p.next; b)将新结点s赋值给p.next结点的直接前驱指针(p.next.prior) p.next.prior = s; c)将新结点s赋值p结点的直接后继指针(p.next) p.next = s;(b.c不能互换,否则p.next.prior = p) (2)删除一个元素 实现思路:
p->prior->next=p->next; //把p->next赋值给p->prior的后继
p->next->prior=p->prior; //把p->prior赋值给p->next的前驱
free(p); //释放结点p占用的内存空间
参考博客: