日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

c++ list 修改_Cpython源码阅读17-list自动扩容原理

發布時間:2024/9/15 python 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++ list 修改_Cpython源码阅读17-list自动扩容原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

list是python的高級特性,今天我們來學習一下list的底層結構。list(列表)就像一個大倉庫,里邊什么都可以放,學習過底層結構之后,就會認同這句話。python中一切皆對象,先點出來,列表中存放的元素其實是泛型指針PyObject*,所以什么都可以放。根據我們列表的直觀感受,每個列表中的元素個數可能會不一樣,所以列表示一個變長對象;列表中的元素可以進行添加、刪除、修改等操作,所以列表是一個可變對象。

列表常用的操作

其中,需要注意的是性能問題,pop從尾部彈出一個元素,時間復雜度為O(1);從頭部彈出一個元素,后面的元素都需要移動,時間復雜度為O(n)。

先看一下List 對象的底層結構,PyListObject,通過前面的學習,這個很簡單了。

typedef struct { PyObject_VAR_HEAD//變長對象公共頭部信息 PyObject **ob_item;//二級指針,指向一個PyObject*類型的指針數組, //這個指針數組保存的是對象指針 Py_ssize_t allocated;//列表底層使用C數組,列表的容量,非實際大小} PyListObject;

通過前面的學習,我們知道一個變長對象是通過ob_size字段來指示對象的實際大小的。列表多了一個字段allocated來表示容量,之所以要有容量這個概念,是因為列表需要動態添加元素。在動態添加元素時,如果每添加一個元素,就申請一次數組,將所有元素都拷貝一次,性能太低。加了容量這個字段,添加新元素,發現底層數組已滿,會將底層數組申請的長一些,添加元素的時候不用每次都申請新的數組。

PyListObject示意圖

可以看出,此時列表中有兩個元素,但是列表的容量是6。我們再append兩個元素,如下示意圖,可以看出容量最大為6,不需要重新申請數組。

尾部添加元素示意圖

在此基礎上再增加三個元素在尾部,實際元素個數為7,容量為6,需要擴容,看一下示意圖:原來的容量為6,元素個數為4,append3個元素后,假設容量為10,元素個數為7。擴容的時候把容量申請的比實際元素大一些。然后將原來數組中的PyObject*按照順序依次拷貝到新的數組里邊,再將ob_item指向新的數組,再將ob_size加3。這就是列表擴容的過程。看一下實際源碼

list對象擴容底層示意圖

//代碼位置cpython-masterObjectslistobject.clist_resize(PyListObject *self, Py_ssize_t newsize)//參數self就是列表,newsize是元素添加或者減少之后的ob_size{ PyObject **items;//這個二級指針,用來指向指針數組 size_t new_allocated, num_allocated_bytes;//新的容量和對應的內存大小 Py_ssize_t allocated = self->allocated;//獲取原來的容量 //如果newsize達到了總量的一半,但是還沒有超過容量,說明newsize和容量的匹配的,不會擴容 if (allocated >= newsize && newsize >= (allocated >> 1)) { assert(self->ob_item != NULL || newsize == 0); Py_SET_SIZE(self, newsize); return 0; }//走到這里說明容量和ob_size不匹配,要進行擴容或者縮容 //新申請的底層數組的容量由下邊的公式決定 new_allocated = ((size_t)newsize + (newsize >> 3) + 6) & ~(size_t)3; //也不能過度分配 if (newsize - Py_SIZE(self) > (Py_ssize_t)(new_allocated - newsize)) new_allocated = ((size_t)newsize + 3) & ~(size_t)3; //如果newsize為0,那么容量也會清空 if (newsize == 0) new_allocated = 0; //數組中存放的是PyObject*,所以要計算內存 num_allocated_bytes = new_allocated * sizeof(PyObject *); //申請相應大小的內存,賦值給指針items items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes); //申請失敗 if (items == NULL) { PyErr_NoMemory(); return -1; } //指向新的數組,實現擴容或者縮容 self->ob_item = items; //元素的實際個數 Py_SET_SIZE(self, newsize); //原來容量的大小設置為新的大小 self->allocated = new_allocated; return 0;}

new_allocated = ((size_t)newsize + (newsize >> 3) + 6) & ~(size_t)3;

從這個公式的注釋得到擴容的規律:The growth pattern is: 0, 4, 8, 16, 24, 32, 40, 52, 64, 76, ...

總結

以上是生活随笔為你收集整理的c++ list 修改_Cpython源码阅读17-list自动扩容原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。