自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

帶你了解數(shù)據(jù)結(jié)構(gòu)的定義和簡介

大數(shù)據(jù)
我們?nèi)绾伟熏F(xiàn)實中大量而復(fù)雜的問題以特定的數(shù)據(jù)類型和特定的存儲結(jié)構(gòu)保存到主存儲器(內(nèi)存)中,以及在此基礎(chǔ)上為實現(xiàn)某個功能(如元素的CURD、排序等)而執(zhí)行的相應(yīng)操作,這個相應(yīng)的操作也叫算法。

1. 概述

數(shù)據(jù)結(jié)構(gòu)定義:

我們?nèi)绾伟熏F(xiàn)實中大量而復(fù)雜的問題以特定的數(shù)據(jù)類型和特定的存儲結(jié)構(gòu)保存到主存儲器(內(nèi)存)中,以及在此基礎(chǔ)上為實現(xiàn)某個功能(如元素的CURD、排序等)而執(zhí)行的相應(yīng)操作,這個相應(yīng)的操作也叫算法。

[[212985]]

  • 數(shù)據(jù)結(jié)構(gòu) = 元素 + 元素的關(guān)系
  • 算法 = 對數(shù)據(jù)結(jié)構(gòu)的操作

算法:

  • 算法就是:解決問題的方法和步驟

衡量算法有如下標(biāo)準(zhǔn):

  • 時間復(fù)雜度
  • 程序要執(zhí)行的次數(shù),并非執(zhí)行時間
  • 空間復(fù)雜度
  • 算法執(zhí)行過程中大概要占用的最大內(nèi)存
  • 難易程度(可讀性)
  • 健壯性

2. 數(shù)據(jù)結(jié)構(gòu)的特點和地位

地位:

數(shù)據(jù)結(jié)構(gòu)處于軟件中核心的地位。

如計算機(jī)內(nèi)存中棧和堆的區(qū)別,不懂?dāng)?shù)據(jù)結(jié)構(gòu)的人可能會認(rèn)為內(nèi)存就是分兩大部分,一塊叫棧,一塊叫堆,顯然這是非常膚淺且不正確的結(jié)論。

實際上如果一塊內(nèi)存是以壓棧出棧的方式分配的內(nèi)存,那么這塊內(nèi)存就叫棧內(nèi)存,如果是以堆排序的方式分配的內(nèi)存,那么這塊內(nèi)存就叫堆內(nèi)存,其最根本的區(qū)別還是其內(nèi)存分配算法的不同。

例如,函數(shù)的調(diào)用方式也是通過壓棧出棧的方式來調(diào)用的,或者操作系統(tǒng)中多線程操作有隊列的概念,隊列用于保證多線程的操作順序,這也是數(shù)據(jù)結(jié)構(gòu)里面的內(nèi)容、或者計算機(jī)編譯原理里面有語法樹的概念,這實際上就是數(shù)據(jù)結(jié)構(gòu)里面的樹,比如軟件工程、數(shù)據(jù)庫之類都有數(shù)據(jù)結(jié)構(gòu)的影子。

特點:

  • 數(shù)據(jù)結(jié)構(gòu)修煉的是內(nèi)功,并不能直接立竿見影的可以解決現(xiàn)實問題,但是有了這門內(nèi)功會在其他方面的學(xué)習(xí)中對你大有益處。
  • 預(yù)備知識(C語言)

學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)應(yīng)該具備如下知識:

  • 指針
  • 結(jié)構(gòu)體
  • 動態(tài)內(nèi)存的分配和釋放
  • 跨函數(shù)使用內(nèi)存

本小節(jié)主要介紹學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)應(yīng)該有的基礎(chǔ),并對相關(guān)知識稍作講解。

  • 指針
  • 指針是 C語言 的靈魂,重要性不需多言。
  • 指針定義

地址:

  • 地址是內(nèi)存單元的編號
  • 其編號是從 0 開始的非負(fù)整數(shù)
  • 范圍: 0 – 0xFFFFFFFF (232 - 1) 注:此指x86平臺,x64平臺下最大內(nèi)存地址為 (264 - 1)

指針:

  • 指針就是地址,地址就是指針。
  • 指針變量是存放內(nèi)存單元地址的變量,它內(nèi)部保存的值是對應(yīng)的地址,地址就是內(nèi)存單元的編號(如內(nèi)存地址值:0xffc0)。
  • 指針的本質(zhì)是一個操作受限的非負(fù)整數(shù)

在計算機(jī)系統(tǒng)中,CPU 可以直接操作內(nèi)存,關(guān)于 CPU 對內(nèi)存的操作與控制原理可以簡單理解如下圖

  • 地址線 : 確定操作哪個地址單元
  • 控制線 : 控制該數(shù)據(jù)單元的讀寫屬性
  • 數(shù)據(jù)線 : 傳輸 CPU 和內(nèi)存之間的數(shù)據(jù)

指針的分類

基本類型的指針

  • int i = 10; // 定義一個 整形變量 i 初始值 10
  • int *p = i; // 定義一個 整形的指針變量 p , 變量 p 指向 i 的地址
  • int *p; // 這兩行等價于上面一行
  • p = &i;

p 存放了 i 的地址,我們就可以說“ p 指向了 i” ,但 p 和 i 是兩個不同的變量,修改一方不會影響另一個的值。

*p 等價于 i ,i 等價于 *p;兩者是一塊內(nèi)存空間,里面的值一變具變。

指針和函數(shù)

 

  1. // 修改外部實參的值  
  2. void func(int * p)  
  3.  
  4. *p = 100; // 函數(shù)內(nèi)修改外部變量的值  
  5.  
  6. // 修改外部實參的值,二級指針的值  
  7. void func2(int ** p)  
  8.  
  9. *p = 100;  
  10. // 函數(shù)內(nèi)修改外部變量的值 ,這里實際修改的是指針的內(nèi)部的地址,這里直接自己修改并不嚴(yán)謹(jǐn)也不安全,只是為了表達(dá)意思  
  11.  
  12. int main(void)  
  13.  
  14. // 修改外部實參  
  15. int i = 10;  
  16. func(&i);  
  17. printf(“i = %d”,i);  
  18. // 修改外部二級指針  
  19. int *p = i; // 等價于 int *p; p = &i;  
  20. func(&p);  
  21. printf(“i = %d”,i);  
  22. return 0;  
  23.  
  24. // 通過函數(shù)調(diào)用,改變函數(shù)外部變量(實參)的值 

指針和數(shù)組

【指針】 和 【一維數(shù)組】

 

  1. int a[5] = {1,2,3,4,5 };  
  2. a[3] == *(a + 3)  
  3. // 等價于 a[3] == *(3 + a) == 3[a];  
  4. // 3[a] 這種寫法只是不常用,從原理上來說是正確的 a 等價于 a[0];  
  5. // a 是數(shù)組中第一個元素,每個元素占用內(nèi)存單位長度相同,  
  6. // a[i] 中的 i 實際代表的是單位長度的倍數(shù) 

數(shù)組名:

一維數(shù)組名是個指針常量(它的值不可變)

它存放的是該一維數(shù)組的第一個元素的地址(一維數(shù)組名指向其第一個元素)

下標(biāo)和指針的關(guān)系:

(1)、 a[i] 等價于 *(a + i)

(2)、假設(shè)指針變量的名字為 p,

則 p + i 的值為 p + i * (p 所指向的變量所占字節(jié)數(shù))

(3)、每個下標(biāo)表示的是第 i+1 個元素,根據(jù)元素類型分配的字節(jié)長度不同(int 類型4個字節(jié)),每個字節(jié)都有對應(yīng)的內(nèi)存地址編號,指針變量 p 保存的是該元素首字節(jié)的地址。

指針變量的運算:

  • 指針變量不能相加、相乘、相除
  • 如果兩指針變量屬于同一數(shù)組,則可以相減
  • 指針變量可以加減一個整數(shù),前提是最終結(jié)果不能超過指針最大可訪問范圍

 

  1. // 指針變量的運算  
  2. p + i 的值是 p + i*(所指向的變量所占字節(jié)數(shù))  
  3. p - i 的值是 p - i*(所指向的變量所占字節(jié)數(shù))  
  4. p++ 等價于 p + 1  
  5. p– 等價于 p - 1  
  6. // 下面是一個通過函數(shù)修改數(shù)組內(nèi)部元素  
  7. void my_Array(int *a , int length)  
  8.  
  9. for(int i = 0; i < length; i++)  
  10.  
  11. *a[i]++; // 給每個元素加 1  
  12.  
  13.  
  14. int main(void){  
  15. int a[5] = {1,2,3,4,5}; 
  16.  my_Array(a , 5); // 調(diào)用  

結(jié)構(gòu)體

為什么會出現(xiàn)結(jié)構(gòu)體?

為了表示一些復(fù)雜的數(shù)據(jù),而普通的基本數(shù)據(jù)無法滿足要求.

什么叫結(jié)構(gòu)體

結(jié)構(gòu)體是用戶根據(jù)實際需要,自己定義的復(fù)合數(shù)據(jù)類型

 

  1. // 如學(xué)生類型  
  2. struct Student{  
  3. int age;  
  4. char * name; // name 不同,賦值方法不同  
  5. char name2[100]; // 這個只能 strcpy(s.name2, “zhangwangdsd”); 字符串拷貝  
  6. double height;  
  7. }; 

如何使用結(jié)構(gòu)體

總結(jié)起來有兩種結(jié)構(gòu)體的使用方式:直接使用 && 通過指針使用

 

  1. struct Student ss = {12,”xiaoyou”,1.73,”xiaozhang”};  
  2. struct Student *pst = &ss;  
  3. ss.name ; 這里直接操作結(jié)構(gòu)體本身  
  4. pst -> name ; 這里通過指針地址操作,更加節(jié)省空間  
  5. struct Student{ // 自定義結(jié)構(gòu)體  
  6. int age;  
  7. char * name 
  8. double height;  
  9. char name2[100];  
  10. };  
  11. int main(void) {  
  12. struct Student s = {12,”xiaoyou”,1.73,”xiaozhang”};  
  13. // 直接使用  
  14. printf(” age = %d \n name = %s \n height = %.2f \n”,s.age,s.name,s.height);  
  15. s.age = 21;  
  16. s.name = “xiaozhu”;  
  17. strcpy(s.name2, “zhangwangdsd”); // 字符串拷貝  
  18. s.height = 1.70;  
  19. printf(” age = %d \n name = %s \n height = %.2f \n %s \n”,s.age,s.name,s.height,s.name2);  
  20. // 以指針的方式使用  
  21. struct Student *pst = &ss;  
  22. pst -> name = “my new name”;  
  23. printf(” name = %s\n”,pst->name);  
  24. printf(” name = %s\n”,(*pst)->name);  
  25. // pst -> name 等價于 (*pst).name ,  
  26. // 而(*pst).name 又等價于 ss.name  
  27. // 所以 pst -> name 等價于 ss.name  
  28. return 0;  

注意事項

結(jié)構(gòu)體變量的類型為: struct Student

結(jié)構(gòu)體變量不能加減乘除,但是能夠相互賦值

普通結(jié)構(gòu)體變量和結(jié)構(gòu)體指針變量作為函數(shù)傳參的問題

 

  1. typedef struct Student{ // 結(jié)構(gòu)體定義  
  2. int age;  
  3. char * name 
  4. char name2[100];  
  5. double height;  
  6. }myStudent;  
  7. // 直接傳遞整個結(jié)構(gòu)體數(shù)據(jù),耗時 && 浪費內(nèi)存空間  
  8. void func(struct Student st);  
  9. // 直接傳遞 只占用 4 byte 的指針,省時效率也高 <推薦用法>  
  10. void func2(struct Student * pst);  
  11. int main(void){  
  12. myStudent ss = {12,"xiaoyou",1.73};  
  13. func(ss);  
  14. func2(&ss);  
  15. return 0;  
  16.  
  17. void func(struct Student st){  
  18. printf("age = %d \n name = %s",st.age,st.name);  
  19.  
  20. void func2(struct Student * pst){  
  21. printf("age = %d \n name = %s",(*pst).age,(*pst).name);  
  22. printf("age = %d \n name = %s",pst->age,pst->name);  

動態(tài)內(nèi)存分配和釋放

平時直接創(chuàng)建數(shù)組的寫法都是靜態(tài)創(chuàng)建,創(chuàng)建完畢之后在整個程序的運行過程中,會固定占用對應(yīng)的內(nèi)存,不僅會造成內(nèi)存空間浪費,還無法動態(tài)添加元素,所以局限性很大,而程序中我們?yōu)榱吮苊膺@種情況,應(yīng)該使用動態(tài)的方式創(chuàng)建和銷毀數(shù)組。

 

  1. // 靜態(tài)創(chuàng)建數(shù)組  
  2. int a[5] = {1,2,3,4,5}; 

動態(tài)構(gòu)造一維數(shù)組

動態(tài)構(gòu)造一個 int 型的一維數(shù)組。

  1. int p = (int )malloc(int length); 

void * malloc(size_t __size) 函數(shù),只有一個 int 類型的形參,表示要求系統(tǒng)分配的字節(jié)數(shù)

malloc 函數(shù)的功能是請求系統(tǒng) length 個字節(jié)的內(nèi)存空間,如果請求完成則返回的是第一個字節(jié)的地址,

如果請求不成功,則返回NULL

malloc 函數(shù)能且只能返回第一個字節(jié)的地址,所以我們需要把沒有實際意義的第一個字節(jié)地址(干地址)轉(zhuǎn)化為一個有實際意義的地址,

所以 malloc 前面必須加(數(shù)據(jù)類型 *),表示把這個無意義的地址轉(zhuǎn)化為對應(yīng)類型的地址

實例:

  1. int p = (int )malloc(50); 

表示將系統(tǒng)分配的 50 個字節(jié)的第一個字節(jié)的地址轉(zhuǎn)化為 int 類型的地址,準(zhǔn)確的說是轉(zhuǎn)化為 4 個一組的地址的首地址,

這樣 p 就指向了第一個四個字節(jié)··· p+i 就指向了第 i+1 個四個字節(jié),p[0],p[i]也就分別是第一個,第i+1個元素。

  1. double *p = (double *)malloc(80); 

表示將系統(tǒng)分配的 80 個字節(jié)的第一個字節(jié)的地址轉(zhuǎn)化為 double 類型的地址,準(zhǔn)確的說是轉(zhuǎn)化為 8 個一組的地址的首地址,

這樣 p 就指向了第一個八個字節(jié)··· p+i 就指向了第 i+1 個八個字節(jié),p[0],p[i]也就分別是第一個,第i+1個元素。

  1. free(p); 

釋放 p 所指向的內(nèi)存,而不是釋放 p 本身所占用的內(nèi)存

代碼示例如下:

 

  1. void test2(void)  
  2.  
  3. int len;  
  4. printf(“請輸入你要動態(tài)創(chuàng)建的數(shù)組長度:”);  
  5. scanf(“%d”,&len);  
  6. int *pArr = (int *)malloc(len); // 動態(tài)創(chuàng)建數(shù)組  
  7. *pArr = 4; // 相當(dāng)于 a[0] = 4; 這里 pArr 就等于數(shù)組首地址,等于數(shù)組名  
  8. pArr[2] = 5; // 相當(dāng)于 a[2] = 5;  
  9. printf("pArr[0] = %d \npArr[2] = %d\n",pArr[0],pArr[2]);  
  10. free(pArr); // 使用完畢,釋放對應(yīng)的數(shù)組空間  

跨函數(shù)使用內(nèi)存

在函數(shù)內(nèi)部分配的局部變量,在函數(shù)調(diào)用完成之后就會被系統(tǒng)回收,其內(nèi)存也會消失。但是程序中常常需要定義一塊內(nèi)存,當(dāng)我們用完之后再會回收。如 OC 語言中對象。所以需要保存住分配的內(nèi)存,應(yīng)該用動態(tài)分配內(nèi)存,當(dāng)用完之后再手動釋放。這也是C語言的一個不足之處:內(nèi)存需要我們手動創(chuàng)建和手動釋放,這也是 OC 語言在開發(fā) iOS 程序時候,我們所講的MRC?!咎O果也發(fā)現(xiàn)了這個不足,于 iOS 5 的時候推出了ARC 】

下面是一個跨函數(shù)使用內(nèi)存的例子:

 

  1. // 這個例子已經(jīng)非常有面向?qū)ο蟮奈兜懒?nbsp; 
  2. typedef struct Student{ // 自定義 student 結(jié)構(gòu)體  
  3. int age;  
  4. char * name 
  5. }myStudent;  
  6. myStudent * createStudent(void); // 創(chuàng)建 student  
  7. void showStudent(myStudent *); // 輸出 student  
  8. int main(void) {  
  9. myStudent *p = createStudent(); // 創(chuàng)建 student  
  10. showStudent(p); // 輸出 student  
  11. return 0;  
  12.  
  13. myStudent * createStudent(void)  
  14.  
  15. myStudent p = (myStudent )malloc(sizeof(myStudent));  
  16. p->age = 20;  
  17. p->name = “xiaoyou”;  
  18. return p;  
  19.  
  20. void showStudent(myStudent *p)  
  21.  
  22. printf(“student.age = %d \nstudent.name = %s\n”,p->age,p->name);  

小結(jié)

本文主要講解了數(shù)據(jù)結(jié)構(gòu)的定義和簡介。

回顧了學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)應(yīng)該具備的一些 C語言 的基礎(chǔ)知識,如指針、結(jié)構(gòu)體、和內(nèi)存等。

責(zé)任編輯:未麗燕 來源: 網(wǎng)絡(luò)大數(shù)據(jù)
相關(guān)推薦

2023-02-28 07:34:12

數(shù)據(jù)庫索引

2020-03-08 16:45:58

數(shù)據(jù)挖掘學(xué)習(xí)數(shù)據(jù)量

2023-12-22 08:56:01

Java編程語言鏈表

2021-03-10 08:55:42

Go數(shù)據(jù)語言

2018-09-06 16:10:37

數(shù)據(jù)庫大數(shù)據(jù)區(qū)塊鏈

2011-04-06 14:37:37

2020-04-17 10:45:21

數(shù)據(jù)中心IT技術(shù)

2013-01-09 14:29:09

數(shù)據(jù)治理Informatica

2021-01-07 08:12:47

數(shù)據(jù)結(jié)構(gòu)二叉樹

2022-02-22 15:27:46

數(shù)據(jù)結(jié)構(gòu)容器算法

2010-02-04 11:15:12

數(shù)據(jù)交換技術(shù)

2021-02-21 22:26:15

數(shù)據(jù)庫測試數(shù)據(jù)庫

2020-10-20 08:14:08

算法與數(shù)據(jù)結(jié)構(gòu)

2020-10-12 11:48:31

算法與數(shù)據(jù)結(jié)構(gòu)

2020-08-12 08:30:20

數(shù)據(jù)結(jié)構(gòu)算法

2022-09-01 16:27:19

JavaScriptWeb開發(fā)

2023-12-26 15:13:09

以太網(wǎng)交換機(jī)

2022-06-08 00:10:33

數(shù)據(jù)治理框架

2023-06-29 15:35:44

數(shù)據(jù)中心IT設(shè)備

2023-04-23 15:59:10

數(shù)據(jù)中心存儲
點贊
收藏

51CTO技術(shù)棧公眾號