數據結構知識?數據結構1. 概述,今天小編就來聊一聊關于數據結構知識?接下來我們就一起去研究一下吧!
數據結構
1. 概述
數據結構定義:
我們如何把現實中大量而複雜的問題以特定的數據類型和特定的存儲結構保存到主存儲器(内存)中,以及在此基礎上為實現某個功能(如元素的CURD、排序等)而執行的相應操作,這個相應的操作也叫算法。
數據結構 = 元素 元素的關系
算法 = 對數據結構的操作
算法:
算法就是:解決問題的方法和步驟
衡量算法有如下标準:
1.時間複雜度
程序要執行的次數,并非執行時間
2.空間複雜度
算法執行過程中大概要占用的最大内存
3.難易程度(可讀性)
4.健壯性
2. 數據結構的特點和地位
地位:
數據結構處于軟件中核心的地位。
地址線 : 确定操作哪個地址單元
控制線 : 控制該數據單元的讀寫屬性
數據線 : 傳輸 CPU 和内存之間的數據
指針的分類
1.基本類型的指針
int i = 10; // 定義一個 整形變量 i 初始值 10
int *p = i; // 定義一個 整形的指針變量 p , 變量 p 指向 i 的地址
int *p; // 這兩行等價于上面一行
p = &i;
1. p 存放了 i 的地址,我們就可以說“ p 指向了 i” ,但 p 和 i 是兩個不同的變量,修改一方不會影響另一個的值。
2. *p 等價于 i ,i 等價于 *p;兩者是一塊内存空間,裡面的值一變具變。
2.指針和函數
// 修改外部實參的值
void func(int * p)
{
*p = 100; // 函數内修改外部變量的值
}
// 修改外部實參的值,二級指針的值
void func2(int ** p)
{
*p = 100;
// 函數内修改外部變量的值 ,這裡實際修改的是指針的内部的地址,這裡直接自己修改并不嚴謹也不安全,隻是為了表達意思
}
int main(void)
{
// 修改外部實參
int i = 10;
func(&i);
printf("i = %d",i);
// 修改外部二級指針
int *p = i; // 等價于 int *p; p = &i;
func(&p);
printf("i = %d",i);
return 0;
}
// 通過函數調用,改變函數外部變量(實參)的值
3.指針和數組
【指針】 和 【一維數組】
int a[5] = {1,2,3,4,5 };
a[3] == *(a 3)
// 等價于 a[3] == *(3 a) == 3[a];
// 3[a] 這種寫法隻是不常用,從原理上來說是正确的 a 等價于 a[0];
// a 是數組中第一個元素,每個元素占用内存單位長度相同,
// a[i] 中的 i 實際代表的是單位長度的倍數
數組名:
一維數組名是個指針常量(它的值不可變)
它存放的是該一維數組的第一個元素的地址(一維數組名指向其第一個元素)
下标和指針的關系:
(1)、 a[i] 等價于 *(a i)
(2)、假設指針變量的名字為 p,
則 p i 的值為 p i * (p 所指向的變量所占字節數)
(3)、每個下标表示的是第 i 1 個元素,根據元素類型分配的字節長度不同(int 類型4個字節),每個字節都有對應的内存地址編号,指針變量 p 保存的是該元素首字節的地址。
指針變量的運算:
指針變量不能相加、相乘、相除
如果兩指針變量屬于同一數組,則可以相減
指針變量可以加減一個整數,前提是最終結果不能超過指針最大可訪問範圍
// 指針變量的運算
p i 的值是 p i*(所指向的變量所占字節數)
p - i 的值是 p - i*(所指向的變量所占字節數)
p 等價于 p 1
p-- 等價于 p - 1
// 下面是一個通過函數修改數組内部元素
void my_Array(int *a , int length)
{
for(int i = 0; i < length; i )
{
*a[i] ; // 給每個元素加 1
}
}
int main(void){
int a[5] = {1,2,3,4,5};
my_Array(a , 5); // 調用
}
結構體
為什麼會出現結構體、
為了表示一些複雜的數據,而普通的基本數據無法滿足要求.
什麼叫結構體
結構體是用戶根據實際需要,自己定義的複合數據類型
// 如學生類型
struct Student{
int age;
char * name; // name 不同,賦值方法不同
char name2[100]; // 這個隻能 strcpy(s.name2, "zhangwangdsd"); 字符串拷貝
double height;
};
如何使用結構體
總結起來有兩種結構體的使用方式:直接使用 && 通過指針使用
struct Student ss = {12,"xiaoyou",1.73,"xiaozhang"};
struct Student *pst = &ss;
ss.name ; 這裡直接操作結構體本身
pst -> name ; 這裡通過指針地址操作,更加節省空間
struct Student{ // 自定義結構體
int age;
char * name;
double height;
char name2[100];
};
int main(void) {
struct Student s = {12,"xiaoyou",1.73,"xiaozhang"};
// 直接使用
printf(" age = %d name = %s height = %.2f ",s.age,s.name,s.height);
s.age = 21;
s.name = "xiaozhu";
strcpy(s.name2, "zhangwangdsd"); // 字符串拷貝
s.height = 1.70;
printf(" age = %d name = %s height = %.2f %s ",s.age,s.name,s.height,s.name2);
// 以指針的方式使用
struct Student *pst = &ss;
pst -> name = "my new name";
printf(" name = %s ",pst->name);
printf(" name = %s ",(*pst)->name);
// pst -> name 等價于 (*pst).name ,
// 而(*pst).name 又等價于 ss.name
// 所以 pst -> name 等價于 ss.name
return 0;
}
注意事項
結構體變量的類型為: struct Student
結構體變量不能加減乘除,但是能夠相互賦值
普通結構體變量和結構體指針變量作為函數傳參的問題
typedef struct Student{ // 結構體定義
int age;
char * name;
char name2[100];
double height;
}myStudent;
// 直接傳遞整個結構體數據,耗時 && 浪費内存空間
void func(struct Student st);
// 直接傳遞 隻占用 4 byte 的指針,省時效率也高 <推薦用法>
void func2(struct Student * pst);
int main(void){
myStudent ss = {12,"xiaoyou",1.73};
func(ss);
func2(&ss);
return 0;
}
void func(struct Student st){
printf("age = %d name = %s",st.age,st.name);
}
void func2(struct Student * pst){
printf("age = %d name = %s",(*pst).age,(*pst).name);
printf("age = %d name = %s",pst->age,pst->name);
}
動态内存分配和釋放
平時直接創建數組的寫法都是靜态創建,創建完畢之後在整個程序的運行過程中,會固定占用對應的内存,不僅會造成内存空間浪費,還無法動态添加元素,所以局限性很大,而程序中我們為了避免這種情況,應該使用動态的方式創建和銷毀數組。
// 靜态創建數組
int a[5] = {1,2,3,4,5};
動态構造一維數組
動态構造一個 int 型的一維數組。
int *p = (int *)malloc(int length);
1. void * malloc(size_t __size) 函數,隻有一個 int 類型的形參,表示要求系統分配的字節數
2. malloc 函數的功能是請求系統 length 個字節的内存空間,如果請求完成則返回的是第一個字節的地址,
如果請求不成功,則返回NULL
3. malloc 函數能且隻能返回第一個字節的地址,所以我們需要把沒有實際意義的第一個字節地址(幹地址)轉化為一個有實際意義的地址,
所以 malloc 前面必須加(數據類型 *),表示把這個無意義的地址轉化為對應類型的地址
實例:
int *p = (int *)malloc(50);
表示将系統分配的 50 個字節的第一個字節的地址轉化為 int 類型的地址,準确的說是轉化為 4 個一組的地址的首地址,
這樣 p 就指向了第一個四個字節··· p i 就指向了第 i 1 個四個字節,p[0],p[i]也就分别是第一個,第i 1個元素。
double *p = (double *)malloc(80);
表示将系統分配的 80 個字節的第一個字節的地址轉化為 double 類型的地址,準确的說是轉化為 8 個一組的地址的首地址,
這樣 p 就指向了第一個八個字節··· p i 就指向了第 i 1 個八個字節,p[0],p[i]也就分别是第一個,第i 1個元素。
4. free(p);
釋放 p 所指向的内存,而不是釋放 p 本身所占用的内存
代碼示例如下:
void test2(void)
{
int len;
printf("請輸入你要動态創建的數組長度:");
scanf("%d",&len);
int *pArr = (int *)malloc(len); // 動态創建數組
*pArr = 4; // 相當于 a[0] = 4; 這裡 pArr 就等于數組首地址,等于數組名
pArr[2] = 5; // 相當于 a[2] = 5;
printf("pArr[0] = %d pArr[2] = %d ",pArr[0],pArr[2]);
free(pArr); // 使用完畢,釋放對應的數組空間
}
跨函數使用内存
在函數内部分配的局部變量,在函數調用完成之後就會被系統回收,其内存也會消失。但是程序中常常需要定義一塊内存,當我們用完之後再會回收。如 OC 語言中對象。所以需要保存住分配的内存,應該用動态分配内存,當用完之後再手動釋放。這也是C語言的一個不足之處:内存需要我們手動創建和手動釋放,這也是 OC 語言在開發 iOS 程序時候,我們所講的MRC。【蘋果也發現了這個不足,于 iOS 5 的時候推出了ARC 】
下面是一個跨函數使用内存的例子:
// 這個例子已經非常有面向對象的味道了
typedef struct Student{ // 自定義 student 結構體
int age;
char * name;
}myStudent;
myStudent * createStudent(void); // 創建 student
void showStudent(myStudent *); // 輸出 student
int main(void) {
myStudent *p = createStudent(); // 創建 student
showStudent(p); // 輸出 student
return 0;
}
myStudent * createStudent(void)
{
myStudent *p = (myStudent *)malloc(sizeof(myStudent));
p->age = 20;
p->name = "xiaoyou";
return p;
}
void showStudent(myStudent *p)
{
printf("student.age = %d student.name = %s ",p->age,p->name);
}
4. 小結
本文主要講解了數據結構的定義和簡介。
回顧了學習數據結構應該具備的一些 C語言 的基礎知識,如指針、結構體、和内存等。
後面會繼續開始對數據結構的講解。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!