python数据结构:以链表为底层原理重新实现字典dict

Posted 九死九歌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python数据结构:以链表为底层原理重新实现字典dict相关的知识,希望对你有一定的参考价值。

(PS:本人主要研究方向是java,python代码写的烂请见谅,大佬轻喷)


一、概述:

首先我们只知道,python中有几个已经实现好的数据结构,底层为链表linkList的列表list、底层为哈希表hashTable的集合set和字典dict。
这确实为我们在程序开发的过程中提供了不少的便利、但也存在一定的弊端。
以dict举个例子:
在java中有一种与dict相似的结构叫做Map,java中同一个容器可以用不同的底层来实现,Map也是如此,像下面这样:

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;

public class Main {

	public static void main(String[] args) {

		Map<Integer, String> m1 = new HashMap<>();
		Map<Integer, String> m2 = new TreeMap<>();
		Map<Integer, String> m3 = new LinkedHashMap<>();
		
	}

}

无论m1、m2还是m3,他们都可以像python中的dict那样实现键值对应,不一样的在于,pythondict的底层无论如何都只能是哈希表,但是在上面这个例子中,m1底层为哈希表、m2底层为树,m3底层为链表。
为了克服python的这一短处,我们可以尝试自己构建一个类,名为myDict,具有dict的大部分操作,插入删除值排序键排序等等。
由于myDict的底层是链表,所以它可以比dict更加高效的进行字典拼接,排序等操作,唯一一点不足就是·查找元素的效率比dict要底。
废话不多说,我们开始上代码:

二、代码实现

1.首先写好构造器、成员变量是两个链表,分别代表键和值,并且利用isinstance函数保证构造器函数只能传参None、myDict、dict和字符串

class myDict:
    def __init__(self, dct=None):
        self.__keys = []
        self.__values = []
        if dct is None:
            return
        elif isinstance(dct, myDict):
            self.__keys = dct.keys()
            self.__values = dct.values()
        elif isinstance(dct, dict):
            for k in dct.keys():
                self.__keys.append(k)
            for v in dct.values():
                self.__values.append(v)
        elif isinstance(dct, str):
            if dct[0] != "{" or dct[len(dct) - 1] != "}":
                raise TypeError
            dct = dct[1:len(dct) - 1]
            lst = dct.split(", ")
            enties = [[], []]
            for entry in lst:
                ety = entry.split(":")
                for i in range(2):

                    try:
                        enties[i].append(int(ety[i]))
                        continue
                    except ValueError:
                        pass

                    try:
                        enties[i].append(float(ety[i]))
                        continue
                    except ValueError:
                        pass

                    try:
                        enties[i].append(complex(ety[i]))
                        continue
                    except ValueError:
                        pass

                    if ety[i] == "True" or ety[i] == "False":
                        enties[i].append(ety[i] == "True")
                        continue

                    try:
                        enties[i].append(eval(ety[i]))
                        continue
                    except BaseException:
                        pass

                    if ety[i][0] != "'" or ety[i][len(ety[i])] != "'":
                        raise TypeError
                    enties[i].append(ety[i])

            self.__keys = enties[0]
            self.__values = enties[1]
            self.__balance()
        else:
            raise TypeError

2.写两个成员函数用于返回键、值、项目列表。其作用相当于dict中的同名函数:

    def keys(self):
        return self.__keys

    def values(self):
        return self.__values

    def items(self):
        lst = []
        for i in range(0, len(self)):
            lst.append((self.__keys[i], self.__values[i]))
        return lst

3.由于要保证键不可重复,所以我们要写一个私有函数进行去重:

    def __balance(self):
        newKeys = list(set(self.__keys))
        newValues = []
        for k in newKeys:
            newValues.append(self.get(k))
        self.__keys = newKeys
        self.__values = newValues

4.编写最基础的增删改查四件套、以及排序切片操作:

	    def append(self, k, v):
        if k not in self.__keys:
            self.__keys.append(k)
            self.__values.append(v)
        else:
            index = self.__keys.index(k)
            self.__values[index] = v

    def insert(self, k, v, index):
        if k in self.__keys:
            return
        else:
            self.__keys.insert(index, k)
            self.__values.insert(index, v)

    def extend(self, dct):
        self.__keys.extend(dct.keys())
        self.__values.extend(dct.values())
        self.__balance()

    def get(self, k):
        if k not in self.__keys:
            return None
        return self.__values[self.__keys.index(k)]

    def deleteByIndex(self, index):
        self.__keys.pop(index)
        self.__values.pop(index)

    def deleteByKey(self, k):
        if k not in self.__keys:
            raise Exception
        self.deleteByIndex(self.__keys.index(k))

    def deleteByValue(self, v):
        if v not in self.__values:
            raise Exception
        self.deleteByIndex(self.__values.index(v))

    def sortedByKeys(self):
        l = len(self.__keys)
        for i in range(0, l):
            for j in range(i + 1, l):
                flag = True
                if self.__keys[i] > self.__keys[j]:
                    flag = False
                    keyTmp = self.__keys[i]
                    self.__keys[i] = self.__keys[j]
                    self.__keys[j] = keyTmp
                    valueTmp = self.__values[i]
                    self.__values[i] = self.__values[j]
                    self.__values[j] = valueTmp
                if flag:
                    break

    def sortedByValues(self):
        l = len(self.__values)
        for i in range(0, l):
            for j in range(i + 1, l):
                flag = True
                if self.__values[i] > self.__values[j]:
                    flag = False
                    keyTmp = self.__keys[i]
                    self.__keys[i] = self.__keys[j]
                    self.__keys[j] = keyTmp
                    valueTmp = self.__values[i]
                    self.__values[i] = self.__values[j]
                    self.__values[j] = valueTmp
                if flag:
                    break

    def slice(self, begin=0, end=None):
        if end is None:
            end = len(self)
        self.__keys = self.__keys[begin:end]
        self.__values = self.__values[begin:end]

5.最后一步了,编写特殊函数:

    def __len__(self):
        if len(self.__keys) != len(self.__values):
            raise Exception
        else:
            return len(self.__keys)

    def __str__(self):
        lst = []
        for i in range(len(self)):
            s = ""
            if isinstance(self.__keys[i], str):
                s += "\\'" + self.__keys[i] + "\\'"
            else:
                s += str(self.__keys[i])
            s += ":"
            if isinstance(self.__values[i], str):
                s += "\\'" + self.__values[i] + "\\'"
            else:
                s += str(self.__values[i])
            lst.append(s)
        return "{" + ", ".join(lst) + "}"

6.最后我们把这个文件命名为dict.py并在main.py中测试一番:

from dict import myDict

'''构造器函数可以为空,可以为一个字典,可以为字符串'''
d = myDict()
print(d)
d = myDict({1: True, 2: "hello", "shi": 10})
print(d)
d = myDict("{2:3.6, True:3+j, 'abc':'cba'}")
print(d)
print()

'''可以返回值列表,键列表,元素列表'''
print(d.keys())
print(d.values())
print(d.items())
print()

'''因为重写了__len__和__str__方法,所以可以直接用print输出,也可以使用len函数测量长度,又因为有参数为字符串的构造器,所以可以由用户输入获取字典'''
print("d的长度是", len(d), ",  d的内容是", d)
try:
    print(myDict(input()))
except:
    print("输入有误!")

'''myDict不同于dict,其底层实现是链表,而不是哈希表,因此可以实现更高效的插入,删除,切片,排序等操作'''
'''这是链表相较于哈希表的优点,当然也是myDict相较于dict的优点'''
d = myDict({1: 3, 0: 9, 2: 7, 3: 5})

d.append(4, 6)
d.insert(4, 8, 3)
d.extend(myDict({2: 9, 3: 8}))
print(d)

d.append("abc", "bca")
d.sortedByKeys()
print(d)
d.sortedByValues()
print(d)

d.deleteByIndex(1)
d.deleteByValue(3)
d.deleteByKey(2)
print(d)
d.slice(2, 4)
print(d)

这样一个虽然有一(hao)些(duo)bug,但是基本上功(te)能(bie)完(la)善(ji)的链表式的字典就构建好了。

以上是关于python数据结构:以链表为底层原理重新实现字典dict的主要内容,如果未能解决你的问题,请参考以下文章

栈(基于数组&基于链表)与队列(基于数组&基于链表)

hashmap实现原理

jdk1.8hashmap常见的面试问题

Python字典的实现原理

hashmap底层实现原理是啥?

一起探秘,不可不知双向链表底层原理