網站首頁 編程語言 正文
寫在前面
最近寫周賽題, 逃不開的一種題型是設計數據結構, 也就是第三題, 做這種題需要的就是對語言中的容器以及常用排序查找算法的掌握, 而我只熟悉了最基本的一些方法, 做起這些題來總是超時…
為了搞定這些題, 我決定學習一下大佬們的做法, 特別是優先隊列的方法維護有序容器以及有序列表等容器, 這些都在Python
中封裝好了, 用起來很是方便, 但是采用defaultdict
的時候, 其缺省數據類型常常需要與題目給出的特定結構匹配, 這就需要定義一個新的數據類型, 下面我就以一種十分常用的結構SortedList
為例, 設置自定義的數據類型(本例為將默認的升序列表變成降序列表).
其他的數據結構當然也可以根據下面列出的方法來改, 主要知識點就是函數與類的運用了
第一種方法: 封裝成函數
首先導入需要的函數, 其中neg
方法可以用lambda x: -x
代替, 本質上是一樣的, 下面寫的代碼這兩種均可.
from collections import defaultdict from sortedcontainers import (SortedList as SL, SortedKeyList as SKL) from operator import neg # or `lambda x: -x`
然后我們來看第一種方法, 其實封裝成函數本質上就是將自定義對象作為函數返回值, 下面給出兩種實現, 其實不傳入參數也可以, 但是這樣的話下面的第15
行就不能使用了, 只能通過add()
來添加值, 還是有局限的.
代碼中的d2
直接用一個新的lambda
函數, 定義鍵, 就不需要考慮直接初始化失效的情況.
def reverseSL(x=None): return SL(iterable=x, key=lambda x: -x) def reverseSL1_no_args(): return SL(key=lambda x: -x) d1 = defaultdict(reverseSL) d2 = defaultdict(lambda: SL(key=neg)) data = [3, 2, 4, 1] for i in data: d1[1].add(i) d2[1].add(i) # 也可以直接加入排序列表 d1[2] = reverseSL([1, 2]) d2[2] = reverseSL([1, 2]) print(d1) print(d2)
可以得到如下的結果:
defaultdict(<function reverseSL at 0x100a680d0>, {1: SortedKeyList([4, 3, 2, 1], key=<function reverseSL.<locals>.<lambda> at 0x100c659d0>), 2: SortedKeyList([2, 1], key=<function reverseSL.<locals>.<lambda> at 0x100caa550>)})
defaultdict(<function <lambda> at 0x100c65820>, {1: SortedKeyList([4, 3, 2, 1], key=<built-in function neg>), 2: SortedKeyList([2, 1], key=<function reverseSL.<locals>.<lambda> at 0x100cb9940>)})
[Finished in 214ms]
如果第15
行改為:
d1[2] = reverseSL_no_args([1, 2])
就會提示:TypeError: reverseSL_no_args() takes 0 positional arguments but 1 was given
, 但是add()
方法不會有問題.
第二種方法: 類封裝
這種方法比較復雜, 并且有一個小坑, 這里先看第一個類的代碼.
我這里實現了兩個類, 其中mySL1
采用的是組合
的面向對象設計方法, mySL2
用的是繼承
. 第一種代碼比較多, 因為里面添加了一個組件SortedList
, 就需要重寫add()
.
class mySL1: def __init__(self, iterable=None): self.sl = SL(iterable=iterable, key=lambda x: -x) def add(self, item): self.sl.add(item) def get(self): return list(self.sl) def __repr__(self): return repr(self.sl)
其中的__repr__
是可選的, 只是為了清楚地顯示已加入到defaultdict
的數據情況. 不寫的話還得調用get()
方法, 進行字典值(values
)數據的輸出, 這里為方便就直接轉換為List
類型了, 如果不轉換, 沒辦法在類外通過list()
進行轉換, 因為這樣得到的數據不是可迭代對象, 通過直接輸出值的類型, 可以得到<class '__main__.mySL1'>
.
然后是第二個類, 繼承語法簡潔明了, 直接調用父類的初始化方法, 但是這里需要注意的是, 繼承SortedList
類的代碼這里就不能用了, 因為如果還是使用SortedList
, 在__init__
中修改key
就會提示斷言錯誤, assert key is None
, 這個問題讓我比較困惑, 甚至覺得可能繼承的方法行不通,(下面是模塊的__new__方法的源碼) 我知道了問題的所在.
def __new__(cls, iterable=None, key=None): """Create new sorted list or sorted-key list instance. Optional `key`-function argument will return an instance of subtype :class:`SortedKeyList`. >>> sl = SortedList() >>> isinstance(sl, SortedList) True >>> sl = SortedList(key=lambda x: -x) >>> isinstance(sl, SortedList) True >>> isinstance(sl, SortedKeyList) True :param iterable: initial values (optional) :param key: function used to extract comparison key (optional) :return: sorted list or sorted-key list instance """ # pylint: disable=unused-argument if key is None: return object.__new__(cls) else: if cls is SortedList: return object.__new__(SortedKeyList) else: raise TypeError('inherit SortedKeyList for key argument')
這里模塊的作者提供了一個SortedList
的子類, 叫做SortedKeyList
, 顧名思義, 就是提供了一種可以寫入key
的類, 這時候繼承這個類就不會有問題了.
其實在上面的函數調用那塊, 就已經有所提示, 輸出結果中的類型, 就顯示是
SortedKeyList
, 這個類型就是修改了key
(使得key is not None
)之后得到的對象. 大家可以嘗試一下, 如果不修改key
, 就還是SortedList
.
class mySL2(SKL): """use SortedKeyList instead SortedList, because SortedList cannot init argument `key`, `assert key is None` in its `__init__`""" def __init__(self, iterable=None): super().__init__(iterable=iterable, key=neg)
最后是創建defaultdict
, 以及數據的讀取:
d3 = defaultdict(mySL1) d4 = defaultdict(mySL2) for i in [19, 11, 12, 123]: d3['x'].add(i) d4['y'].add(i) # 或者直接通過列表初始化 d3['z'] = mySL1([1, 2]) d4['w'] = mySL2([1, 2]) print(d3) print(d4) print(d3['x'].get(), d3['z'].get()) print(list(d4['y']), list(d4['w']))
可以得到下面的結果:
defaultdict(<class '__main__.mySL1'>, {'x': SortedKeyList([123, 19, 12, 11], key=<function mySL1.__init__.<locals>.<lambda> at 0x1008e40d0>), 'z': SortedKeyList([2, 1], key=<function mySL1.__init__.<locals>.<lambda> at 0x100bebd30>)})
defaultdict(<class '__main__.mySL2'>, {'y': mySL2([123, 19, 12, 11], key=<built-in function neg>), 'w': mySL2([2, 1], key=<built-in function neg>)})
[123, 19, 12, 11] [2, 1]
[123, 19, 12, 11] [2, 1]
可以看出, 第一種類的創建, 其實最后還是用到了SortedKeyList
這個子類.
原文鏈接:https://blog.csdn.net/qq_41437512/article/details/125986285
相關推薦
- 2022-12-06 docker多容器操作與強制刪除容器的方法步驟_docker
- 2022-09-05 Spring 解決循環依賴
- 2022-10-26 使用Go?http重試請求的示例_Golang
- 2022-07-12 CSS樣式:樣式的沖突 樣式的繼承 偽元素 偽類
- 2023-06-17 pytorch?簡介及常用工具包展示_python
- 2022-07-30 Redis如何使用HyperLogLog的實現_Redis
- 2022-06-12 詳解Flutter如何讀寫文本文件_Android
- 2022-03-17 Qt編寫提示進度條的實現示例_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支