士別三日當(dāng)刮目相待,不好意思鴿了好久了,因?yàn)閷W(xué)習(xí)的時(shí)間不連續(xù),所以我一直攢著,我又回來繼續(xù)更新了
沒有繼續(xù)學(xué)習(xí)浙大的數(shù)據(jù)結(jié)構(gòu)了,對(duì)比了青島大學(xué)的王老師的這個(gè)教程我覺得更適合我一些,更入門,更詳細(xì)。
課程連接:數(shù)據(jù)結(jié)構(gòu)與算法基礎(chǔ)(青島大學(xué)-王卓)
下面是整理的第一部分筆記,有些地方直接用截圖了(偷懶ing)
Data Structure
程序=數(shù)據(jù)結(jié)構(gòu)+算法
數(shù)據(jù)基本概念
數(shù)據(jù)(data)
- 數(shù)值型
- 非數(shù)值型(文字,圖像…)
數(shù)據(jù)元素(data element)
- 數(shù)據(jù)的基本單位,在程序中當(dāng)做一個(gè)整體進(jìn)行考慮和處理(如表中的一行包含多列信息)
- 是數(shù)據(jù)這個(gè)集合的個(gè)體
數(shù)據(jù)項(xiàng)(data item)
- 構(gòu)成數(shù)據(jù)元素的不可分割的最小單位()
數(shù)據(jù)對(duì)象(data object)
- 性質(zhì)相同的數(shù)據(jù)元素的集合,是數(shù)據(jù)(集合)的一個(gè)子集。
數(shù)據(jù)結(jié)構(gòu)(data structure)定義
數(shù)據(jù)元素之間的關(guān)系稱為結(jié)構(gòu)
相互之間存在一種或者多種特定關(guān)系的數(shù)據(jù)元素集合
數(shù)據(jù)結(jié)構(gòu)是帶結(jié)構(gòu)的數(shù)據(jù)元素的集合
是計(jì)算機(jī)中存儲(chǔ),組織數(shù)據(jù)的方法。通常情況下,精心選擇的數(shù)據(jù)結(jié)構(gòu)可以帶來最有效率的算法。
解決問題的效率跟 數(shù)據(jù)的組織方式, 跟空間的利用率, 算法的巧妙程度有關(guān)。
數(shù)據(jù)邏輯結(jié)構(gòu)
劃分方法一:
- 線性結(jié)構(gòu)(有且僅有一個(gè)開始和一個(gè)終端節(jié)點(diǎn),并且所有節(jié)點(diǎn)最多只有一個(gè)直接前趨和一個(gè)直接后繼, 如線性表,棧,隊(duì)列,串)
- 非線性結(jié)構(gòu)(一個(gè)節(jié)點(diǎn)可能有多個(gè)直接前趨和多個(gè)直接后繼,如樹,圖)
劃分方法二
- 集合結(jié)構(gòu)(除同屬一個(gè)集合外無其他關(guān)系)
- 線性結(jié)構(gòu)(一對(duì)一)
- 樹形結(jié)構(gòu)(一對(duì)多的層次關(guān)系)
- 圖狀結(jié)構(gòu)或網(wǎng)狀結(jié)構(gòu)(多對(duì)多)
數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)種類
- 順序存儲(chǔ)(一組聯(lián)系的存儲(chǔ)單元依次存儲(chǔ)數(shù)據(jù)元素,C中用數(shù)組來實(shí)現(xiàn)順序存儲(chǔ))
- 鏈?zhǔn)酱鎯?chǔ)(一組任意的存儲(chǔ)單元存儲(chǔ)元素,之間的邏輯關(guān)系用指針表示, C中用指針實(shí)現(xiàn),前一個(gè)元素包含后一個(gè)元素的指針位置)
- 索引存儲(chǔ)(存儲(chǔ)節(jié)點(diǎn)信息的同時(shí)還建立附加的索引表,索引項(xiàng)-關(guān)鍵字-地址)
- 散列存儲(chǔ)(根據(jù)節(jié)點(diǎn)的關(guān)鍵字直接計(jì)算出該節(jié)點(diǎn)的存儲(chǔ)地址)
數(shù)據(jù)類型
-
使用高級(jí)語言編寫程序時(shí),必須對(duì)程序中出現(xiàn)的每個(gè)變量常量,表達(dá)式,明確說明他們的數(shù)據(jù)類型,如c中
- int,char,float,double等基本數(shù)據(jù)類型
- 數(shù)組,結(jié)構(gòu),共用體,枚舉等構(gòu)造數(shù)據(jù)類型
- 指針,void類型
- typedef自定義類型
-
數(shù)據(jù)類型作用:約束變量或者常量的取值范圍,以及操作。eg: int(-65536, 65535) + - * /
-
定義:是一組性質(zhì)相同的值的集合以及定義于這個(gè)值的集合上的一組操作的總稱
-
抽象數(shù)據(jù)類型(Abstract Data Type, ADT): 指一個(gè)數(shù)字模型以及定義在此數(shù)據(jù)模型上的一組操作
-
形式定義:
ADT 抽象數(shù)據(jù)類型名{ 數(shù)據(jù)對(duì)象:<數(shù)據(jù)對(duì)象的定義> 數(shù)據(jù)關(guān)系:<數(shù)據(jù)關(guān)系的定義> 數(shù)據(jù)操作:<基本操作的定義> } ADT 抽象數(shù)據(jù)類型名 # 參數(shù)表說明:賦值參數(shù),引用參數(shù)(以&打頭, 可輸入和返回結(jié)果) 基本操作名(參數(shù)表) 初始條件 <初始條件描述> 操作結(jié)果 <操作結(jié)果描述> EG: ADT Circle{ 數(shù)據(jù)對(duì)象:D={r,x,y|r,x,Y均為實(shí)數(shù)} 數(shù)據(jù)關(guān)系:{<r,x,Y>|r是半徑,<x,y>是圓心坐標(biāo)} 基本操作: Circle(&C,r,x,y) 操作結(jié)果:構(gòu)造一個(gè)圓。 double Area(C) 初始條件:圓已存在。 操作結(jié)果:計(jì)算面積。 double Circumference(C) 初始條件:圓已存在。 操作結(jié)果:計(jì)算周長。 ... } ADT Circle
-
抽象數(shù)據(jù)類型的復(fù)數(shù)的實(shí)現(xiàn)
typede struct{ float realpart; float imagpart; } Complex /* 構(gòu)造復(fù)數(shù) */ void assign(Complex * A, float real, float imag){ A->realpart = real; A->imagpart = imag } /* 加法c = A+B */ void add(Complex * c, Complex A, Complex B){ c->realpart = A.realpart + B.realpart; c->imagpart = A.imagpart + B.imagpart; } /* 減法c = A-B */ /* Complex 是我們定義的結(jié)構(gòu)體,帶*的變量是指針變量,指向complex類的指針,不帶*的是普通變量 */ void add(Complex * c, Complex A, Complex B){ c->realpart = A.realpart - B.realpart; c->imagpart = A.imagpart - B.imagpart; } /* 乘法c = A*B */ void multiply(Complex * c, Complex A, Complex B){ c->realpart = A.realpart * B.realpart; c->imagpart = A.imagpart * B.imagpart; } /* 除法c = A/B */ /* 真實(shí)環(huán)境下這里是要先判斷除數(shù)是否為0的 */ void devide(Complex * c, Complex A, Complex B){ c->realpart = A.realpart / B.realpart; c->imagpart = A.imagpart / B.imagpart; }
how to calculate
z = ( 8 + 6 i ) ( 4 + 3 i ) ( 8 + 6 i ) + ( 4 + 3 i ) z = \frac {(8+6i)(4+3i)} {(8+6i)+(4+3i)} z=(8+6i)+(4+3i)(8+6i)(4+3i)?# include <stdio.h> void main() { complex z1,z2,z3,z4,z; float RealPart, ImagPart; assign(z1, 8.0, 6.0); assign(z2, 4,0, 3.0); add(z1,z2,z3); multiply(z1,z2,z4); if (divide(z4,z3)) { GetReal(z, RealPart); GetImag(z, ImagPart); }//if }
-
-
Summary:
算法
算法(algorithm)定義
-
對(duì)特定問題求解方法的一種描述,是指令的有限序列。其中每個(gè)指令表示一個(gè)或多個(gè)操作。(簡而言之,算法是解決問題的方法和步驟)
-
描述方法:自然語言(中英),流程圖(傳統(tǒng)&NS流程圖),偽代碼,程序代碼
-
算法和程序的關(guān)系:算法是解決問題的一種方法或者一個(gè)過程,程序時(shí)用高級(jí)語言對(duì)算法的具體實(shí)現(xiàn)
-
算法特性:
-
有窮性: 執(zhí)行有窮步,有窮時(shí)間完成
-
確定性:每一條命令有確切的含義
-
可行性:可執(zhí)行的
-
輸入:有零個(gè)或者多個(gè)輸入
-
輸出:有一個(gè)或者多個(gè)輸出
-
-
**空間復(fù)雜度S(n) 一 根據(jù)算法寫成的程序在執(zhí)行時(shí)占用存儲(chǔ)單元的長度。**這個(gè)長度往往與輸入數(shù)據(jù)的規(guī)模有關(guān)??臻g復(fù)雜度過高的算法可能導(dǎo)致使用的內(nèi)存超限,造成程序非正常中斷。
-
**時(shí)間復(fù)雜度T(n) 一 根據(jù)算法寫成的程序在執(zhí)行時(shí)耗費(fèi)時(shí)間的長度。**這個(gè)長度往往也與輸入數(shù)據(jù)的規(guī)模有關(guān)。時(shí)間復(fù)雜度過高的低效算法可能導(dǎo)致我們?cè)谟猩甓嫉炔坏竭\(yùn)行結(jié)果。
空間復(fù)雜度例子:
比如下面這個(gè)遞歸實(shí)現(xiàn)的函數(shù),如果N
特別大,那么每次調(diào)用的PrintN
都會(huì)先把所有東西存在內(nèi)存,然后等下個(gè)執(zhí)行,這樣會(huì)導(dǎo)致很容易就吃完了內(nèi)存,最后直接終止掉了,而通過普通循環(huán)實(shí)現(xiàn)函數(shù),無論N多大始終只有一個(gè)函數(shù),所以沒問題。
時(shí)間復(fù)雜度例子:
下面是兩個(gè)多項(xiàng)式求和公式f(x)=a0+a1X+a2X^2+a3X^3+....a(n-1)X^(n-1)+anX^n
在運(yùn)算中,加減法的速度遠(yuǎn)快于乘除法,所以下面的程序我們關(guān)注乘法,第一個(gè)程序中每次for
循環(huán)都會(huì)執(zhí)行(pow
函數(shù)執(zhí)行i-1
次乘法,a[i]
執(zhí)行一次)i
次乘法,所以總的次數(shù)為(n+1)n/2
次乘法,而第二種每 次for
循環(huán)只執(zhí)行一次乘法,所以總共n
次,這樣就可以知道第二種方法在N很大時(shí)候耗時(shí)更少,在時(shí)間復(fù)雜度上占優(yōu)。
什么是好的算法:
分析一般算法效率時(shí)關(guān)注:
- 最壞情況復(fù)雜度Tworst(n)
- 平均復(fù)雜度Tavg(n)
- Tavg(n)<=Tworst(n)
復(fù)雜度的漸進(jìn)表示法:
算法時(shí)間復(fù)雜度定義:算法中基本語句重復(fù)執(zhí)行的次數(shù)是問題規(guī)模n的某個(gè)函數(shù)f(n),算法的時(shí)間量度:T(n)=O(f(n)) --> 漸進(jìn)時(shí)間復(fù)雜度(T(n)增長率和f(n)的增長率一致 )
n越大算法的執(zhí)行時(shí)間越長
排序:n為記錄數(shù)
矩陣:n為矩陣的階數(shù)
多項(xiàng)式:n為多項(xiàng)式的項(xiàng)數(shù)
集合:n為元素個(gè)數(shù)
樹:n為樹的結(jié)點(diǎn)個(gè)數(shù)
圖:n為圖的頂點(diǎn)數(shù)或邊數(shù)
線性結(jié)構(gòu)
線性表
線性表是具有相同特性的數(shù)據(jù)元素的一個(gè)有限序列。
線性表的類型定義
抽象數(shù)據(jù)類型的線性表定義如下:
ADT List{
數(shù)據(jù)對(duì)象:D={ai|ai屬于Elemset,(i=1,2,...,n>=0)}
數(shù)據(jù)關(guān)系:R={<ai-l,ai>|ai-l,ai屬于D,(i=2,3,...,n)}
基本操作:
InitList(&L); # 初始化構(gòu)造一個(gè)空的線性表L
DestroyList(&L); # 銷毀已存在線性表L
ClearList(&L); # 將線性表L重置為空表
IsEmpty(L); # 若線性表為空則返回true,否則false
ListLength(L); # 返回表中元素個(gè)數(shù)
GetElem(L,i,&e); # 用e返回線性表L中第i個(gè)元素的值
LocateElem(L,e,compare()); # 返回L中第一個(gè)與e滿足comapre()的數(shù)據(jù)元素的位序,不存在的話返回0
PriorElem(L,cur_e,&pre_e); # 返回前驅(qū)
NextElem(L,cur_e,&next_e); # 返回后繼
Listlnsert(&L,i,e); # 在L的第i個(gè)位置之前插入新的數(shù)據(jù)元素e,ai變成后繼了
ListDeIete(&L,i,&e); # 刪除L中第i各元素,并用e返回
ListTraverse(&L,visited()); # 依次對(duì)線性表中的每個(gè)元素調(diào)用visited()
}ADT List
線性表的順序存儲(chǔ)表示
順序存儲(chǔ)結(jié)構(gòu)或者順序映像:把邏輯上相鄰的數(shù)據(jù)元素存儲(chǔ)在物理上相鄰的存儲(chǔ)單元中的存儲(chǔ)結(jié)構(gòu)。
-
其中第一個(gè)數(shù)據(jù)元素的a1的存儲(chǔ)位置稱為基地址(起始位置)
-
存儲(chǔ)時(shí)地址必須時(shí)連續(xù)的。
-
所有數(shù)據(jù)元素的存儲(chǔ)位置均可由第一個(gè)數(shù)據(jù)元素的存儲(chǔ)位置得到:
LOC(ai) = LOC(a1) + (i-1)xL (L表示每個(gè)元素需占的存儲(chǔ)單元)
-
線性表長度可變,但是數(shù)組長度不可動(dòng)態(tài)定義(C中 一維數(shù)組定義方式:類型說明符 數(shù)組名[常量表達(dá)式])
-
所以可以用一個(gè)變量來表示順序表的長度屬性,定義如下:
#define LIST_INIT_SIZE 100 //線性表存儲(chǔ)空間的初始分配量 typedef struct{ ElemType elem[LIST_INIT_SIZE]; int length; //當(dāng)前長度 }SqList;
eg: 圖書表的順序存儲(chǔ)結(jié)構(gòu)定義
#define MAXSIZE 10000 //圖書表可能達(dá)到的最大長度
typedef struct{ //圖書信息定義
char no[20]; //圖書ISBN
char name[50]; //圖書名字
float price; //圖書價(jià)格
}Book;
typedef struct{
Book *elem; //存儲(chǔ)空間的基地址
int length; //圖書表中當(dāng)前圖書個(gè)數(shù)
}SqList; //圖書表的順序存儲(chǔ)結(jié)構(gòu)類型為SqList
操作算法1
用到的預(yù)定義常量和類型:
//函數(shù)結(jié)果狀態(tài)代碼
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//Status 是函數(shù)的類型,其值是函數(shù)結(jié)果狀態(tài)代碼
typedef int Status;
typedef Char ElemType;
-
線性表L的初始化(參數(shù)引用)
StatusInitListSq(SqList&L){ //構(gòu)造一個(gè)空的順序表L L.elem=new ElemType[MAXSlZE]; //為順序表分配空間 if(!L.elem) exit(OVERFLOW); //存儲(chǔ)分配失敗 L.length=0; //空表長度為0 return OK; }
-
銷毀線性表L
void DestroyList(SqList &L) { if (L.elem) delete L.elem; //釋放空間 }
-
清空線性表L
void ClearList(SqList &L) { L.length=0; //線性表長度置為0 }
-
求線性表L長度和判斷L是否為空
int GetLength(SqList L){ return(L.ength); } int IsEmpty(SqList L){ if (L.length==0) return 1; else return 0; }
-
順序表的取值(根據(jù)位置i獲取相應(yīng)位置數(shù)據(jù)元素的內(nèi)容)
int GetElem(SqList L,int i,EIemType &e){ if(i<1 || i>L.length) return ERROR; //判斷i值是否合理,若不合理,返回ERROR //第i一1的單元存儲(chǔ)著第i個(gè)數(shù)據(jù) e=L.elem[i-1]; return OK; }
操作算法2
-
順序表的查找
int LocateELem(SqList L,ElemType e){ //在線性表L中查找值為e的數(shù)據(jù)元素,返回其序號(hào)(是第幾個(gè)元素) for(i=0;i<L.length;i++) if(L.elem[i]==e) return i+1; //查找成功,返回序號(hào)(下標(biāo)和序號(hào)差一) return0;//查找失敗,返回0 } int LocateElem(SqList L, ElemType e){ i=0; while (i<L.length && L.elem[i]!=e) i++; //查找成功后跳出while循環(huán)了 if (i < L.length) return i+1; return 0; }
-
查找算法分析
- 平均查找長度ASL(average search length): 為了確定記錄在表中的位置,需要與給定值進(jìn)行比較的關(guān)鍵字的個(gè)數(shù)的期望值叫做查找算法的ASL。
-
-
平均查找長度(Pi = 1/n)
- ASL=p1+2P2+3P3+…(n-1)P(n-1)+nPn=(n+1)/2
-
時(shí)間復(fù)雜度
- O(n)
-
順序表的插入(插入最后,中間,最前,后繼元素位置得向后移動(dòng),長度隨增減)
Status ListInsert_Sq(SqList &L, int i, ElemType e){ if (i<1 || i>L.length+1) return ERROR; //i值不合法 if (L.length ==MAXSIZE) return ERROR; //當(dāng)前存儲(chǔ)空間已滿 for (j=L.length-1;j>=i-1;j--) L.elem[j+1]=L.elem[j] //插入位置及之后的元素后移 L.elem[i-1]=e; //新元素e放到第i個(gè)位置(下標(biāo)i-1) L.length++; //表長+1 return OK; }
-
時(shí)間復(fù)雜度
-
插在尾結(jié)點(diǎn),無需移動(dòng)
-
插在首節(jié)點(diǎn)之前,所有元素后移
-
插在中間,移動(dòng)次數(shù)為n/2 (出現(xiàn)概率為1/(n+1))
-
-
- O(n)
-
順序表的刪除
Status ListDelete_Sq(SqList &L, int i, ElemType e){ if (i<1 || i>L.length+1) return ERROR; //i值不合法 e=L.elem[i-1]; //被刪除元素i放到e中 for (j=i;j<=L.length-1;j++) L.elem[j-1]=L.elem[j] //插入位置及之后的元素后移 L.length--; //表長-1 return OK; }
-
時(shí)間復(fù)雜度
- 平均移動(dòng)次數(shù)
-
- O(n)
- 以上操作的空間復(fù)雜度S(n)=O(1) , 沒有占用輔助空間
順序表的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 存儲(chǔ)密度大(結(jié)點(diǎn)本身所占存儲(chǔ)量/結(jié)點(diǎn)結(jié)構(gòu)所占存儲(chǔ)量)
- 可以隨機(jī)存取表中任一元素
缺點(diǎn):(克服缺點(diǎn)用 鏈表)
- 在插入、刪除某一元素時(shí),需要移動(dòng)大量元素
- 浪費(fèi)存儲(chǔ)空間
- 屬于靜態(tài)存儲(chǔ)形式,數(shù)據(jù)元素的個(gè)數(shù)不能自由擴(kuò)充
類C語言的有關(guān)操作
數(shù)組定義:
//數(shù)組靜態(tài)分配
typedef struct {
ElemType data[MaxSize]; //存放data[0]位置
int length;
} SqList;
//數(shù)組動(dòng)態(tài)分配
typedef struct {
ElemType *data; //指針
int length;
} SqList;
為數(shù)組動(dòng)態(tài)分配空間:
SqList;
L.data=(ElemType*)malloc(sizeof(ElemType)*MaxSize);
malloc(m)函數(shù),開辟m字節(jié)長度的地址空間,并返回這段空間的首地址sizeof(x)運(yùn)算,計(jì)算變量×的長度
ElemType* 表示分配的空間以什么數(shù)據(jù)類型進(jìn)行劃分(char/int/float...)
L.data 就是最后得到的基地址
free(p)函數(shù),釋放指針p所指變量的存儲(chǔ)空間,即徹底刪除一個(gè)變量
需要加載頭文件:<stdlib.h>
- C++的動(dòng)態(tài)存儲(chǔ)分配:
new 類型名T(初值列表)
功能:
申請(qǐng)用于存放T類型對(duì)象的內(nèi)存空間,并依初值列表賦以初值
結(jié)果值:
成功T類型的指針,指向新分配的內(nèi)存
失敗,0(NULL)
delete 指針P
功能:
釋放指針P所指向的內(nèi)存。P必須時(shí)new操作的返回值
eg:
int *p1 = new int; //無初值,指針給到p1
或int *pl = new int(10); //初值10
-
C++中的參數(shù)傳遞文章來源:http://www.zghlxwxcb.cn/news/detail-436623.html
- 函數(shù)調(diào)用時(shí)傳送給形參表的實(shí)參必須與形參三個(gè)一致: 類型、個(gè)數(shù)、順序 。
- 參數(shù)傳遞有兩種方式 。
- 傳值方式(參數(shù)為整型、實(shí)型、字符型等)
- 傳地址
- 參數(shù)為指針變量
- 參為引用類型
- 參數(shù)為數(shù)組名
//傳值方式 - 形參的變化不會(huì)影響實(shí)參a,b的 #include <iostream.h> void swap(float m, float n){ float temp; temp = m; m = n; n = temp; } void main(){ float a,b; cin>>a>>b; swap(a,b); cout<<a<<endl<<b<<endl; }
//指針變量作參數(shù)
// 形參變化影響實(shí)參 - 形參所指的具體數(shù)發(fā)生變化影響了實(shí)參
#include <iostream.h>
void swap(float *m, float *n){
float t;
t = *m; // 指針?biāo)妇唧w內(nèi)容發(fā)生變化
*m = *n;
*n = t;
}
void main(){
float a,b,*p1,*p2;
cin>>a>>b;
p1=&a; p2=&b; // a,b的指針設(shè)為p1,p2
swap(p1,p2);
cout<<a<<endl<<b<<endl;
}
// 形參變化不影響實(shí)參 - 形參中只有指針的變化不會(huì)影響實(shí)參
#include <iostream.h>
void swap(float *m, float *n){
float *t;
t = m; // 指針發(fā)生交換而已
m = n;
n = t;
}
void main(){
float a,b,*p1,*p2;
cin>>a>>b;
p1=&a; p2=&b; // a,b的指針設(shè)為p1,p2
swap(p1,p2);
cout<<a<<endl<<b<<endl;
}
文章來源地址http://www.zghlxwxcb.cn/news/detail-436623.html
//引用類型作為參數(shù)
#include <iostream.h>
void swap(float &m, float &n){ //形參為引用類型,和實(shí)參指向同一塊地址,所以會(huì)一起變
float temp;
temp = m;
m = n;
n = temp;
}
void main(){
float a,b;
cin>>a>>b;
swap(a,b);
cout<<a<<endl<<b<<endl;
}
- 總結(jié): 引用類型作為形參,在內(nèi)存中不產(chǎn)生副本,直接對(duì)實(shí)參操作;而一般變量作為參數(shù)需要不通的存儲(chǔ)單元,當(dāng)傳遞數(shù)據(jù)量較大時(shí)會(huì)影響空間效率。指針參數(shù)能達(dá)到同樣效果但是閱讀性差因?yàn)樾枰貜?fù)使用
*變量名
操作。
TO BE CONTINUED…
到了這里,關(guān)于數(shù)據(jù)結(jié)構(gòu)與算法基礎(chǔ)(青島大學(xué)-王卓)(1)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!