數據結構概述
定義
算法
1. 時間複雜度 大概程序執行的次數,而非執行的時間
2. 空間複雜度 所佔內存
3. 難易程度
4. 健壯性
計算算法時間複雜度 推倒大o階方法
- 用常數1取代運行時間中的所有加法常數
- 在修改後的運行次數函數中 只保留最高階項
- 如果最高階項存在且不是1 則去除與這個項相乘的常數
常數階
線性階 (單循環)
平方階(嵌套循環)
對數階
- 數據類型
- 原子類型 整形 浮點型 字符型
- 結構類型 整形數組
預備知識
指針
定義
地址 內存單元的編號
指針 指針變量是存放內存單元地址的變量
分類
1: 基本類型指針
int i=10;
int *p = &i; // 等價於 int *p; p=&i;
詳解這兩部操作:
1) p存放了i的地址.所以我們說p指向了i
2) p和i是完全不同的兩個變量,修改其中的任意一個變量的值不相互影響
3) p指向i *p就是i變量本身
指針變量也是變量 他存放的不是內存單元的內容, 只能存放內存單元的地址
普通變量前不能加*
常量和表達是前不能加&
如何通過被調函數修改主調函數中普通變量的值
1) 實參爲相關變量的地址
2) 形參爲以該變量的類型爲類型的指針變量
3) 在被調函數中通過 *形參變量名 的方式就可以修改主函數相關變量的值
1). 修改 i 中的內容
# include <stdio.h>
void f(int *p) //不是定義了一個名字叫*p的形參,而是定義了一個形參,該形參的名字叫做p,他的類型是int*
{
*p = 100;
}
int main(void)
{
int i = 9;
f(&i);
printf("i = %d\n", i);
return 0;
}
2). 修改指針 p 的地址
# include <stdio.h>
void f(int **q);
int main(void)
{
int i = 9;
int *p = &i;//int *p; p = &i;
printf("%p\n", p);
f(&p);
printf("%p\n", p);
return 0;
}
void f(int **q)
{
*q = (int *)0xffffffff;
}
2: 指針和數組的關係
指針和一維數組
數組名
一維數組名是個指針常量,
他存放的是一維數組第一個元素的地址
他的值不能被改變
一維數組名指向的是數組的第一個元素
下標和指針的關係
a[i] << == >> *(a+i)
假設指針變量的名字爲p
則p+i的值是p+i*(p所指向的變量所佔的字節數)
指針變量的運算
指針變量不能相加,不能相乘,不能相除
如果兩指針變量屬於同一數組,則可以相減
指針變量可以加減一整數,前提是最終結果不能超過指針的長度
# include <stdio.h>
void show_array(int *p, int len)
{
//p[0] = -1; //p[0] == *p p[2] == *(a+2) == a[2]
//p[i] 就是主函數的a[i]
int i = 0;
for (i = 0; i < len; i++)
printf("%d\n", p[i]);
}
int main(void)
{
int a[5] = { 1, 2, 3, 4, 5 };
show_array(a, 5);
//printf("%d\n", a[0]);
return 0;
}
如何通過被調函數修改主調函數中一維數組的內容
兩個參數
存放數組首元素的指針變量
存放數組元素長度的整形變量
結構體
如何使用(兩種使用)
1. 第一種定義使用
# include <stdio.h>
struct Student
{
int sid;
char name[200];
int age;
};//分號不能省略
int main(void)
{
struct Student st = { 1000, "zhangsan", 20 };
printf("%d %s %d\n", st.sid, st.name, st.age);
st.sid = 99;
//st.name = "lisi"; //error
strcpy(st.name, "lisi");
st.age = 22;
printf("%d %s %d\n", st.sid, st.name, st.age);
return 0;
}
2. 第二種定義使用
# include <stdio.h>
struct Student
{
int sid;
char name[200];
int age;
};//分號不能省略
int main(void)
{
struct Student st = { 1000, "zhangsan", 20 };
printf("%d %s %d\n", st.sid, st.name, st.age);
struct Student *pst = &st; // struct Student *pst; pst = &st;
(*pst).sid = 99;
strcpy(pst->name, "lisi");
pst->age = 22;
printf("%d %s %d\n", st.sid, st.name, st.age);
return 0;
}
3. 函數傳參
# include <stdio.h>
struct Student
{
int sid;
char name[200];
int age;
};//分號不能省略
void f(struct Student *pst);
void g(struct Student st);
void g2(struct Student *pst);
int main(void)
{
struct Student st;
f(&st);
g(st);
g2(&st);
return 0;
}
void f(struct Student *pst)
{
(*pst).sid = 99;
strcpy(pst->name, "zhangsan");
pst->age = 22;
}
void g(struct Student st)//耗時間 耗內存 不推薦
{
printf("%d %s %d\n", st.sid, st.name, st.age);
}
void g2(struct Student *pst)
{
printf("%d %s %d\n", (*pst).sid, (*pst).name, (*pst).age);
}
注意事項
結構體變量不能加減乘除, 但可以相互賦值
普通結構體變量和結構體指針變量作爲函數傳參的問題
動態內存的分配和釋放
# include <stdio.h>
# include <malloc.h>
int main(void)
{
int a[5] = { 4, 10, 2, 8, 6 };
int len;
printf("請輸入你需要分配數組的長度:len= ");
scanf_s("%d", &len);
int *pArr = (int*)malloc(sizeof(int)*len);
// 將分配返回的的第一個地址強制轉換
//*pArr = 4; //類似於 a[0]=4;
//pArr[1] = 10;//類似於 a[1] = 10;
for(int i=0; i<len; i++)
{
scanf_s("%d", &pArr[i]);
};
for (int i=0; i < len; i++)
{
printf("%d\n", *(pArr + i));
};
free(pArr);//把pArr所代表的動態分配的20個字節的內存釋放
return 0;
}
跨函數分配內存
調用函數fun 使main函數中的指針變量p指向一個合法的整型單元
main()
{
int *p;
fun1(&p);// p指向分配出的一塊合法內存
fun2(&p);//p在fun2函數運行時分配出一塊合法內存,func2運行結束後內存被釋放
...
}
int fun1(int **q);
{
int *q = (int *)malloc(4);
}
int fun2(int **q);
{
int s;
*q = &s;
}
實例
# include <stdio.h>
# include <malloc.h>
struct Student
{
int sid;
int age;
};
struct Student *CreateStudent(void); //定義一個函數 返回值爲結構體的地址
void ShowStudent(struct Student *pst);//傳入一個結構體的地址 顯示
int main(void)
{
struct Student *ps;
ps = CreateStudent();
ShowStudent(ps);
}
void ShowStudent(struct Student *pst)
{
printf("%d %d\n", pst->sid, pst->age);
}
struct Student *CreateStudent(void)
{
struct Student *p = (struct Student*)malloc(sizeof(struct Student));//分配一塊內存Student結構體大小的內存
p->sid = 20;
p->age = 44;
return p;
}