Lists
Python's designers have a lot of options when implementing the data structure of the list. Each choice has the potential to affect how quickly the list operation executes. Of course they also try to optimize some of the less common operations. But when it comes to tradeoffs, they sacrifice the performance of infrequently used operations to fulfill common functions.
This article address: http://www.cnblogs.com/archimedes/p/python-datastruct-algorithm-list-dictionary.html, reprint please indicate source address.
Designers have a number of choices that enable them to implement the data structure of the list. These choices may be affected by how quick list operations are effected. To help them make the right choices, they look at the way people use the list data structures most often and their implementation of optimized lists, resulting in the most common operations being very fast. Of course they also try to optimize uncommon operations, but when a tradeoff has to do with a less common operation the performance tends to be sacrificed in more common operations support.
Two common operations are indexed and assigned to the index location. These two operations take the same amount of time regardless of the size of the list. Called an O (1) Operation time Complexity independent of the list size.
Another common programming operation is to grow a list. There are two ways to create a longer list. You can use the Append tail method or concatenation operator. The additional method is O(1). However, the connection operation is O(k) where k is required to connect to the list of dimensions. This is important to you because it can help you choose the right tool to work to make your program more effective.
Let's look at four different ways to construct a n
list that contains a number starting with 0. Listing 1 shows a list of four different ways to implement:
Listing 1
def Test1 (): l = [] for i in range (1000): l = l + [i] def Test2 (): l = [] for i in Range (1000 def Test3 (): l = [i for i in Range (1000)] def Test4 (): l = list (range)
To calculate the execution time of each function, we can use the Python timeit
module. timeit
The purpose of the module design is to allow programmers to measure time across platforms in a consistent environment.
To use timeit
you must first create an Timer
object with a parameter of two Python declarations. The first argument is that you want to calculate the time is a function declaration, and the second parameter is the number of times the test is set. timeit
The module calculates the execution time. timeit
By default, the Execute declaration parameter represents an action of 1 million times. Returns the number of seconds of a floating-point type when it is finished. However, because it executes the declaration 1 million times, you can interpret the results as how many milliseconds each execution takes. You can also pass to timeit
the function a number
parameter called, which allows you to specify how many times the test statement executes. The following shows how long it will take to run each test function 1000 times.
T1 = Timer ("test1 ()","From __main__ import test1")Print("concat", T1.timeit (number=1000),"milliseconds") T2= Timer ("test2 ()","From __main__ import test2")Print("Append", T2.timeit (number=1000),"milliseconds") T3= Timer ("test3 ()","From __main__ import test3")Print("Comprehension", T3.timeit (number=1000),"milliseconds") T4= Timer ("test4 ()","From __main__ import test4")Print("List Range", T4.timeit (number=1000),"milliseconds")concat 6.54352807999 millisecondsappend 0.306292057037 millisecondscomprehension 0.147661924362 Millisecondslist range 0.0655000209808 milliseconds
In the experiment above, the function declaration is, test1()
test2()
and so on. The declaration of the setting will make you feel weird, so let's take a closer look. You may be familiar with from
statements, import
but this is usually used in a Python program file to start with. In this case, from __main__ import test1
from the The c5/> namespace willtest1 调入到 timeit
所在的命名空间.
The last mention of this little experiment is that the calls you see also contain a certain amount of overhead time, but we can assume that the cost of a function call is the same in all four cases, and we can still get a more meaningful operation comparison result. so it's not said that a concatenation operation takes exactly 6.54 milliseconds, whereas a tandem test function takes 6.54 milliseconds.
From the table below we can see the big-o efficiency of all the operations in the list. After careful observation, you may want to know the difference in the execution time of two different POPs. When a pop takes a time complexity of O (1) in the tail operation of the list, the time required for the pop to operate in the head of the list is O (n), because Python chooses how to implement the list.
the efficiency of the Python List operation (big-o)
Operation |
Efficiency |
Index [] |
O (1) |
Index Assignment |
O (1) |
Append |
O (1) |
Pop () |
O (1) |
Pop (i) |
O (N) |
Insert (I,item) |
O (N) |
del operator |
O (N) |
Iteration |
O (N) |
Contains (in) |
O (N) |
Get slice [x:y] |
O (k) |
Del Slice |
O (N) |
Set Slice |
O (N+k) |
Reverse |
O (N) |
Concatenate |
O (k) |
Sort |
O (n log n) |
Multiply |
O (NK) |
In order to demonstrate the difference in performance, let's use timeit模块做另一个实验
. Our aim is to be able to verify that in a list of known sizes, from the tail of the list and from the head of the list, pop
we also measure the time under different list sizes. We expect that the operation time from the tail of the list and from the head of the list pop
is to keep constant, even when the size of the list increases, but the run time increases with the size of the list.
The following code allows us to distinguish between the execution times of two pop operations. As you can see, in the first example, it takes 0.0003 milliseconds from the tail pop operation, but it takes 4.82 milliseconds from the initial pop operation.
Listing 2
Popzero = Timeit. Timer ("x.pop (0)", "From __main__ import x") Popend= Timeit. Timer ("X.pop ()", "From __main__ import x") x= List (range (2000000)) Popzero.timeit ( number=1000)4.8213560581207275x= List (range (2000000)) Popend.timeit ( number=1000)0.0003161430358886719
The above code can be seen as pop(0)
true pop()效率低
, but no validation pop(0)
time complexity is o(n) but pop()
o( C16>1). To verify this we need to look at an example and call a list at the same time. Look at the following code:
Popzero = Timer ("x.pop (0)", "From __main__ import x") Popend= Timer ("X.pop ()", "From __main__ import x")Print("Pop (0) pop ()") forIinchRange (1000000,100000001,1000000): x=List (range (i)) PT= Popend.timeit (number=1000) x=List (range (i)) PZ= Popzero.timeit (number=1000) Print("%15.5f,%15.5f"% (PZ,PT))
Dictionaries
python the second major data structure is a dictionary. You may remember, A dictionary differs from a list in that you can access items in the dictionary by keyword rather than by location. o ( 1) .  Span style= "line-height:1.5;" Another important dictionary operation is to include operations. o Span id= "mathjax-span-4" class= "Mo" style= "line-height:1.5;" > (1) .
dictionary The execution efficiency of the operation ( big-o )
action |
efficiency |
Td>copy
o (n) |
get item |
O (1) |
Set Item |
O (1) |
Delete Item |
O (1) | /tr>
contains (in) |
O (1) |
iteration |
O (n) |
Our final performance experiment compared the performance of the operation with the list and the dictionary . in this process we will confirm that the list contains an O (N) dictionary that is O (1). We will use a simple comparison in our experiment. We will list a list with a series of data. Then, we'll randomly select the numbers and see if the data is in the list. If we had the right conclusions, As the capacity of the list increases, the time required increases.
We will repeat the experiment with a dictionary that contains the same key. in this experiment, we can see that determining whether a number is not only much faster in the dictionary , but not even changing as the dictionary capacity increases .
The following code implements this comparison. Note that we perform the same non-operation number in container
. The difference is that line 7th x
is a list, and the 9th line x
is a dictionary.
ImportTimeitImportRandom forIinchRange (10000,1000001,20000): T= Timeit. Timer ("Random.randrange (%d) in X"%I,"From __main__ import random,x") x=List (range (i)) Lst_time= T.timeit (number=1000) x= {J:none forJinchrange (i)} d_time= T.timeit (number=1000) Print("%d,%10.3f,%10.3f"% (i, lst_time, d_time))
You may also be interested in:
Python data structure and algorithm--algorithm analysis
Python data structures and algorithms-object-oriented
Python data structures and algorithms--type
Python Basics (10)--Digital
Python Basics (9)--Regular expressions
Python Basics (8)--File
Python Basics (7)--functions
Python Basics (6)-conditions, loops
Python Basics (5)--Dictionary
Python Basics (4)--string
Python Basics (3)--lists and tuples
Python Basics (2)--Object type
Python Basics (1)--python programming habits and features
Python data structures and algorithms--list and dictionaries