问题:
循环链表的检查
构造一个单向循环链表。
输出是否有循环,循环的长度,开始循环的节点。
例:
a-b-c-d-e-f-g-h-i-j-k-l-m-n-e
有循环e-f-g-h-i-j-k-l-m-n-e
循环长度为10
开始循环的节点为e
解决方案:
在头节点前增加一个空节点,便于一致性处理。
采用两个变量x, y从空节点开始分别遍历该链表。
变量x按顺序遍历每一个节点。
变量y按顺序隔一个节点遍历一次。
若x和y同时指向同一个节点,则有循环。
当x和y再次相遇时,x遍历的节点就是循环的长度。
用一个数组存储x所有遍历过的节点,倒序搜索,找到不在循环中的节点。该节点的下一个节点就是循环的开始节点。
讨论:
当链表很大时,存储路径的数组需要比较大,耗资源。
源代码:
# coding=utf-8 import re import os import time from datetime import datetime def test_jump_to(n): '''跳转表''' return { 1: test_dict_item, # 只是函数名,不能带小括号 2: test_str, 3: test_time_format, 4: do_loop_link_list }.get(n, test_default) class link_node(): def __init__(self, node_value, node_next=None): # type: (object, object) -> object self.node_value = node_value self.node_next = node_next class do_loop_link_list(): def __init__(self, list_num, loop_position): self.list_num = list_num self.loop_position = loop_position self.list_value = ['%s' % chr(i) for i in range(65, 65+self.list_num, 1)] # ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N'] print(self.list_value) self.link_node0 = link_node('') # 在头结点前加入空节点 for i in range(1, self.list_num+1, 1): node_name_pre = 'link_node' + '{num}'.format(num=i-1) node_name = 'link_node' + '{num}'.format(num=i) node_value = self.list_value[i-1] exec ('self.' + node_name + '=link_node(node_value)') # self.link_node1 = link_node('A') exec ('self.' + node_name_pre + '.node_next' '=self.' + node_name) # self.link_node0.node_next = self.link_node1 self.show_link_list() self.create_loop(self.loop_position) self.show_link_list() def show_link_list(self): node = self.link_node0 list_len = 0 if False == self.has_loop(): while(1): list_len += 1 if node.node_next == None: break node = node.node_next print('\n链表(无循环)长度为:%d' % list_len) else: print('\n链表存在循环') def create_loop(self, loop_position): node = self.link_node0 node_list = [] if False == self.has_loop(): while (1): if node.node_next == None: node.node_next = node_list[loop_position] node_list.append(node.node_next) break node = node.node_next node_list.append(node) print(('\n设置开始循环的节点位置为:%d 取值为:%s') % (loop_position, node_list[loop_position].node_value)) for node in node_list: print(node.node_value), def has_loop(self): flag = 0 loop_len = 0 rec_list = [] # 记录x的轨迹 node_x = self.link_node0 node_y = self.link_node0 while(1): rec_list.append(node_x) if node_x.node_next == None or node_y.node_next == None: break elif node_y.node_next.node_next == None: break else: node_x = node_x.node_next node_y = node_y.node_next.node_next if node_x == node_y: flag += 1 if flag == 1: # 第一次相遇时开始计数 loop_len += 1 elif flag == 2: # 再次相遇时退出 print('\n循环长度为:%d' % loop_len) break if flag == 2: rec_list.pop(0) for i in range(0, len(rec_list), 1): if rec_list[i].node_value == rec_list[i + loop_len].node_value: print(('\n开始循环的节点位置:%d 取值为:%s') % (i, rec_list[i].node_value)) break return True if flag else False def test_default(): print('hello') s = 'abc' exec(s+'=5') print(abc) def test_time_format(): print(datetime.now()) s = '2015-12-21 15:01:28' time_s = datetime.strptime(s, "%Y-%m-%d %H:%M:%S") print(time_s) def test_dict_item(): '''测试字典的 items、iteritems、viewitems三个属性''' b = {'a':1,'b':2,'c':3} bi = b.items() # v3版本统一 bii = b.iteritems() # v3版本取消 bvi = b.viewitems() # v3版本兼容 print(bi) print(bii) print(bvi) for key, value in bii: print('bii',key,value) for key, value in bvi: print('bvi', key, value) print('*******************') b['d']=4 print(bi) print(bii) print(bvi) for key, value in bii: print('bii', key, value) for key, value in bvi: print('bvi', key, value) def test_str(): str0 = 'nihao "hello" hi' print(str0) str1 = "nihao \"hello\" hi" print(str1) dict0 = {'a': 1, 'b': 2, 'c': 3} str2 = 'a=%(a)s,b=%(b)s,c=%(c)s' % dict0 # % 小括号 str3 = 'a={a},b={b},c={c}'.format(a=1, b=2, c=3) # format 大括号 print(str2) print(str3) str4 = ('adfad' 'agdf') print(str4) if '__main__' == __name__: test_jump_to(4)(18,8) ''' ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R'] 链表(无循环)长度为:19 设置开始循环的节点位置为:8 取值为:I A B C D E F G H I J K L M N O P Q R I 循环长度为:10 开始循环的节点位置:8 取值为:I 链表存在循环 '''