王道考研 -- 數據結構 筆記


在這里插入圖片描述
上面這張圖來自課件,發現這張圖將計算機四大基礎學科之間的關系很好的體現出來了,故貼在這。

第一章 緒論

1.1 數據結構的基本概念

在這里插入圖片描述

數據元素、數據項

數據元素是數據的基本單位。數據元素由數據項組成。
如,在飯館排隊的顧客,可用以下數據元素和數據項表示:
在這里插入圖片描述

數據結構、數據對象

數據結構是相互之間存在一種或多種特定關系的數據元素的集合。
數據對象是具有相同性質的數據元素的集合,是數據的一個子集。

在這里插入圖片描述
索引存儲:

第二章 線性表

2.1 線性表的定義和操作

2.1.1 線性表的定義(邏輯結構)

線性表是具有相同數據類型的 n 個數據元素的有限序列,其中 n 為表長,當 n = 0 時,線性表是一個空表。若用 L 命名線性表,則一般表示為:L = {a1, a2, ... , an}。
位序:也就是元素在線性表中的位置。位序從 1 開始,在編程時,數組從 0 開始。
表頭元素為 a1 和表尾元素為 a2。
除頭尾元素外,每個元素都有一對直接前驅直接后驅

2.1.2 線性表的基本操作

InitList(&L):初始化表。構造一個空的線性表 L,並分配內存空間。
DestroyList(&L):銷毀表,並釋放線性表 L 占用的內存空間。

ListInsert(&L, i, &e):插入操作。在表 L 的第 i 個位置插入指定元素 e 。
ListDelete(&L, i, &e):刪除操作。刪除表 L 中第 i 個位置的元素,並用 e 返回刪除元素的值。

LocateElem(L, e):按值查找。在表 L 中查找具有給定元素值的元素。
GetElem(L, i):按位查找。獲取表 L 中第 i 個位置的元素的值

其他常用操作
Length(L):求表長。返回線性表 L 的長度,即表中元素的個數。
PrintList(L):打印表。按順序輸出線性表 L 的所有元素值。
Empty(L):判斷是否為空。若 L 為空表,則返回 true,否則返回 false。

Tips:
操作數據結構的思路:創銷、增刪改查。
實際開發中,可根據實際需求定義其他操作。
關於引用 &:引用運算符是 C++ 中的運算符,C 中沒有這種操作。

比起學會“How”(怎么做),更重要的是想明白“Why”(為什么要這么做)。

2.2 線性表的順序表示

如何獲取數據元素的長度?
使用 sizeof() 函數。

2.2.1 順序表的定義

用順序存儲的方式實現線性表。順序存儲,也就是將邏輯上相鄰的元素存儲在相鄰的物理位置上。

2.2.2 順序表的實現

靜態分配

用靜態分配的方式實現順序表,表的長度后續不可再發生改變。

代碼實現示例:

#define MaxSize 10 // 定義最大長度 

typedef struct {
	int data[MaxSize]; // ElemType = int, * 用靜態的“數組”存訪數據元素 
	int length; // 順序表的當前長度 
} SqList;

// 初始化順序表 
void InitList(SqList &L) {
	L.length = 0; // 順序表初始化為0 
}

int main() {
	SqList L; // 聲明一個順序表 
	InitList(L); // 初始化順序表 
	
	return 0;
}
動態分配

malloc() 函數的作用:會申請一片存儲空間,並返回存儲空間第一個位置的地址,也就是該位置的指針。

在這里插入圖片描述

#define InitSize 10 // 順序表的初始長度
typedef struct {
	int * data; // ElemType = int, * 聲明動態分配數組的指針 
	int MaxSize; // 順序表的最大容量
	int length; // 順序表的當前長度 
} SqList;

// 初始化順序表 
void InitList(SqList &L) {
	// 用 malloc 函數申請一片連續的存儲空間 
	L.data = (int *)malloc(InitSize * sizeof(int));
	L.length = 0;
	L.MaxSize = InitSize;
}

// 增加動態數組的長度 
void IncreaseSize(SqList &L, int len) {
	int * p = L.data;
	L.data = (int *)malloc((L.MaxSize + len) * sizeof(int));
	for (int i = 0; i < L.length; i++)
		L.data[i] = p[i]; // 將數據復制到新區域 
	L.MaxSize = L.MaxSize + len; // 順序表最大長度增加len 
	free(p); // 釋放原來的內存空間 
}

int main() {
	SqList L; // 聲明一個順序表 
	InitList(L); // 初始化順序表 
	
	IncreaseSize(L, 5);
	
	return 0;
}

2.2.3 順序表的特點

  • 可隨機訪問,查找元素所需時間復雜度為 O(1)
  • 存儲密度高,每個節點只存儲數據元素。
  • 拓展容量不方便(即使使用動態分配的方式實現,拓展長度的時間復雜度也比較高,因為需要把數據復制到新的區域)。
  • 插入刪除操作不方便,需移動大量元素:O(n)

靜態分配與動態分配的對比

靜態分配無法拓展容量,動態分配可以拓展容量。

2.2.4 順序表的基本操作

1. 插入
#define MaxSize 10 // 定義最大長度 

typedef struct {
	int data[MaxSize]; // 用靜態的“數組”存訪數據元素 
	int length; // 順序表的當前長度 
} SqList;

bool ListInsert(SqList &L, int i, int e) {
	if (i < 1 || i > L.length+1) // 判斷i的范圍是否有效 
		return false;
	if (L.length >= MaxSize) // 判斷存儲空間是否已滿 
		return false;
	for (int j = L.length; j >= i; j--) // 將第i個元素之后的元素后移 
		L.data[j] = L.data[j-1];
	L.data[i-1] = e; // 在位置i處放入e 
	L.length++; // 長度+1 
	return true;
} 

int main() {
	SqList L;
	InitList(L);
	ListInsert(L, 3, 3);
	
	return 0; 
} 

時間復雜度分析

  • 最好的情況:在表尾插入,無需移動元素。O(1) 。
  • 最壞的情況:在表頭插入,需移動所有元素。O(n) 。
  • 平均情況:所有位置插入的可能性都為 p = 1/(n+1) ,則平均時間復雜度 = O[np + (n-1)p + ··· + 0*p] = O(n/2),也就是 O(n) 。
2. 刪除
#define MaxSize 10 // 定義最大長度 

typedef struct {
	int data[MaxSize]; // 用靜態的“數組”存訪數據元素 
	int length; // 順序表的當前長度 
} SqList;

bool ListInsert(SqList &L, int i, int e) {
	if (i < 1 || i > L.length+1) // 判斷i的范圍是否有效 
		return false;
	if (L.length >= MaxSize) // 判斷存儲空間是否已滿 
		return false;
	for (int j = L.length; j >= i; j--) // 將第i個元素之后的元素后移 
		L.data[j] = L.data[j-1];
	L.data[i-1] = e; // 在位置i處放入e 
	L.length++; // 長度+1 
	return true;
} 

bool ListDelete(SqList &L, int i, int &e) {
	if (i < 1 || i > L.length)
		return false;
	e = L.data[i-1]; // 將被刪除的元素賦值給e 
	for (int j = i; j < L.length; j++) //將第i個位置后的元素前移 
		L.data[j-1] = L.data[j];
	L.length--;
	
	return true; 
}

int main() {
	SqList L;
	InitList(L);
	int e = -1;
	if (ListDelete(L, 3, e))
		printf("已刪除第3個元素,刪除元素值為%d\n", e);
	else
		printf("位序i不合法,刪除失敗\n"); 
	
	return 0; 
} 

在這里插入圖片描述
時間復雜度分析

  • 最好時間復雜度:刪除表尾,O(1)。
  • 最壞時間復雜度:刪除表頭,后續 n-1 個元素全部前移,O(n)。
  • 平均時間復雜度:每個元素被刪除的概率都為 p = 1/n,O[(n-1)p + (n-2)p + ··· + 0*p] = O[(n-1)/2] = O(n)
3. 查找

在這里插入圖片描述
在這里插入圖片描述

a. 按位查找

GetElem(L, i)

/* 靜態分配的按位查找 */ 

#define MaxSize 10 // 定義最大長度 
typedef struct {
	ElemType data[MaxSize]; // 用靜態的“數組”存訪數據元素 
	int length; // 順序表的當前長度 
} SqList;

ElemType GetElem(SqList L, int i) {
	return L.data[i-1];
}
/* 動態分配的按位查找 */ 

#define InitSize 10 // 順序表的初始長度 
typedef struct {
	ElemType * data; // ElemType = int, * 聲明動態分配數組的指針 
	int MaxSize; // 順序表的最大容量
	int length; // 順序表的當前長度 
} SqList;

ElemType GetElem(SqList L, int i) {
	return L.data[i-1];
}

時間復雜度分析

由於元素連續存放,可以根據起始地址和元素大小立刻找到元素——隨機存取特性。

最好時間復雜度 = 最壞時間復雜度 = 平均時間復雜度 = O(1)

b. 按值查找

LocateElem(L, e)

#define InitSize 10 // 順序表的初始長度 
typedef struct {
	ElemType * data; // ElemType = int, * 聲明動態分配數組的指針 
	int MaxSize; // 順序表的最大容量
	int length; // 順序表的當前長度 
} SqList;

// 查找第一個元素值為e的元素,並返回其位序 
int LocateElem(SqList L, ElemType e) {
	for (int i = 0; i < L.length; i++)
		if (L.data[i] == e)
			return i+1; // 數組下標為i的元素值等於e,返回其位序i+1 
	return 0; // 沒有查找到 
}

時間復雜度分析

  • 最好時間復雜度:目標在表頭,O(1) 。
  • 最壞時間復雜度:目標在表尾,O(n) 。
  • 平均時間復雜度:目標元素在任何位置的概率都為 p = 1/n,則平均時間復雜度為 O[1 * 1/n + 2 * 2/n + ··· + n * 1/n] = O[(n+1)/2] = O(n) 。

C 中不能用 == 判斷兩個結構體是否相等


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM