期末複習
易錯點
葉子結點以外的結點稱為分支結點
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-06\Ori\9d5f4aefd34e1d8587152f79b567d05a.jpeg)
時間複雜度
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-05\Ori\4cb6f5297e5f4c3c977d0e0a7b1ba811.jpeg)
1.4
(1) \(O(nm)\)
(2) \(O(n^2)\)
(3) \(O(n^2)\)
(4) \(O(log_3n)\)
線性表
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-05\Ori\4d76e88acec7cf93e3aa1f078d9dae26.jpeg)
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-05\Ori\7a84e78d0465dda3d3ae587caf7f35d6.jpeg)
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-05\Ori\1a89bf3dcccc1ab8550a0af1a3b23823.jpeg)
棧與佇列
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-05\Ori\c03e31102df4a4c59fa8ea846aa39b00.jpeg)
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-05\Ori\35a6a3f2a22c251866cace88b24f6734.jpeg)
String類
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-05\Ori\382d6c69512ab3b2a98ad6e8ae7bd61a.jpeg)
樹與二叉樹
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-06\Ori\dc9194c4c4765324f08d84d29b54f53f.jpeg)
樹的定義與二叉樹的性質
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-05\Ori\f58f19fecfe96568c0e4bdb5aebddeec.jpeg)
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-05\Ori\baef45294f2d67fb7472b09eba058faf.jpeg)
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-05\Ori\bd1c694da0cd89b0a352951ed95ab054.jpeg)
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-05\Ori\2ac4ff01a08375650d45f379410903a4.jpeg)
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-05\Ori\e10ebaeef44d8c6e7636bb9fd7edeaad.jpeg)
二叉樹遍歷的過程
先序遍歷:中 左 右
中序遍歷:左 中 右
後序遍歷:左 右 中
二叉樹遍歷的遞迴演算法
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-05\Ori\5dbcb49ed8a09e587b3d49d4d531a0ab.png)
二叉樹遍歷的非遞迴演算法
層次遍歷二叉樹
二叉樹的建立
對於完全二叉樹,可以把樹儲存在一個陣列中
但是對於大多數的二叉樹,需要用鏈的形式來儲存來減少空間的浪費
節點型別的定義
template <typename T>
struct BTNode{
T data;
BTNode<T> *left;
BTNode<T> *right;
BTNode(const T& k):data(k),left(nullptr),right(nullptr){};
BTNode():data{},left(nullptr),right(nullptr){};
~BTNode(){ }
};
二叉樹類的定義
template <typename T>
class BTree {
protected:
BTNode<T>* _root;
public:
BTree():_root(nullptr){}
const BTNode<T>* root() const { return _root; }
BTNode<T>*& root() { return _root; }
void dispose()//刪除二叉樹
{
if (_root != nullptr)
{
dispose(_root);
_root = nullptr;
}
}
void dispose(BTNode<T>* p)
{
if (p != nullptr)
{
dispose(p->left);
dispose(p->right);
}
delete p;
}
};
根據順序表建立二叉樹
template <typename T>
void byArray(const T* pt, int cnt, BTree<T>* bt)
{
int n = cnt;
if (n == 0)
bt->root() = nullptr;
int i, j;
BTNode<T>** q = new BTNode<T>*[n];
for (i = 0; i < n; i++)
q[i] = new BTNode<T>(pt[i]);
for (i = 0; i < n; i++)
{
j = 2 * i + 1;
if (j < n)
q[i]->left = q[j];
else
q[i]->left = nullptr;
j++;
if (j < n)
q[i]->right = q[j];
else
q[i]->right = nullptr;
}
bt->root() = q[0];
}
根據廣義表構建二叉樹
template <typename T>
struct ListFlags {
T NullSubtreeFlag;
T LeftDelimitFlag;
T RightDelimitFlag;
T MiddleDelimitFlag;
};
static int idx = 0;
static void* pListFlags = nullptr;
template <typename T>
BTNode<T>* rootByGList(T* sList)
{
BTNode<T>* p = nullptr;
T nodeData = sList[idx];
ListFlags<T>* pFlags = (ListFlags<T>*)pListFlags;
if (isData(nodeData, pFlags))
{
p = new BTNode<T>(nodeData);
idx++;
nodeData = sList[idx];
if (nodeData == pFlags->LeftDelimitFlag)
{
idx++;
p->left = rootByGList(sList);
idx++;
p->right = rootByGList(sList);
idx++;
}
}
if (nodeData == pFlags->NullSubtreeFlag)
idx++;
return p;
}
template <typename T>
void byGList(T* sList, int cnt, BTree<T>* bt, const ListFlags<T>* pCustomListFlags = nullptr)
{
idx = 0;
ListFlags<T> DefaultFlags{ '^','(',')',',' };
if (cnt > 0)
{
ListFlags<T>* p;
if (pCustomListFlags != nullptr)
p = (ListFlags<T>*)pCustomListFlags;
else
p = &DefaultFlags;
pListFlags = p;
bt->root() = rootByGList(sList);
}
else
bt->root() = nullptr;
return;
}
template <typename T>
bool isData(const T& nodeValue, const ListFlags<T>* pFlags)
{
if (nodeValue == pFlags->NullSubtreeFlag) return false;
if (nodeValue == pFlags->LeftDelimitFlag) return false;
if (nodeValue == pFlags->RightDelimitFlag) return false;
if (nodeValue == pFlags->MiddleDelimitFlag) return false;
else return true;
}
根據先根和中根次序建立二叉樹
template <typename T>
BTNode<T>* rootBy2Lists(vector<T>& preList, vector<T>& inList) {
BTNode<T>* p = nullptr;
vector<T> presub, insub;
int n = preList.size();
if (n > 0) {
T rootData = preList[0];
p = new BTNode<T>(rootData);
int k = 0;
while (k < n && inList[k] != rootData)
k++;
for (int i = 0; i < k; i++)
presub.push_back(preList[i+1]);
for (int i = 0; i < k; i++)
insub.push_back(inList[i]);
p->left = rootBy2Lists(presub, insub);
presub.clear();
insub.clear();
for (int i = 0; i < n - k - 1; i++)
presub.push_back(preList[i + k + 1]);
for (int i = 0; i < n - k - 1; i++)
insub.push_back(inList[i + k + 1]);
p->right = rootBy2Lists(presub, insub);
}
return p;
}
template <typename T>
void by2Lists(vector<T>& preList, vector<T>& inList, BTree<T>* bt) {
bt->root() = rootBy2Lists(preList, inList);
}
課後習題
9.1
1)
聯立可得
9.2
二叉樹有左子樹和右子樹的區別,度為2的數只是最大有兩個子樹而已
9.3
先序遍歷:1 2 3 4 5 6 7 8 9
中序遍歷:2 3 4 1 6 7 9 8 5
後序遍歷:4 3 2 9 8 7 6 5 1
9.4
排序
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-05\Ori\023c8a827659d76a00d886aa5c9c48ab.jpeg)
5.1
排序演算法穩定性:
演算法 | 平均時間複雜度 | 空間複雜度 | 是否穩定 |
---|---|---|---|
直接插入排序 | \(O(n^2)\) | \(O(1)\) | 穩定 |
氣泡排序 | \(O(n^2)\) | \(O(1)\) | 穩定 |
快速排序 | \(O(nlog_2n)\) | \(O(1)\) | 不穩定 |
選擇排序 | \(O(n^2)\) | \(O(1)\) | 不穩定 |
歸併排序 | \(O(nlog_2n)\) | \(O(n)\) | 穩定 |
排序演算法的形式
直接插入排序
void InsertSort(T* items, int cnt) {
T k;
int m, n = cnt;
int i, j;
for (m = 1; m < n; m++)
{
k = items[m];
for (i = 0; i < m; i++)
{
if (k < items[i]) {
for (int j = m - 1; j >= i; j--)
items[j + 1] = items[j];
items[i] = k;
break;
}
}
}
}
最佳化過的插入排序
由於前面的m-1個數字已經處於排序狀態,所以可以運用查詢的方法來進行最佳化尋找下一個數插入位置的方法,因此經過最佳化的插入排序的時間複雜度為 \(O(nlog_2n)\)
template <typename T>
inline int BinarySearch(T k, T* items, int cnt, int si = 0, int length = -16) {
if (length == -16)
length = cnt;
int mid = 0, left = si;
int right = left + length - 1;
while (left <= right) {
mid = (left + right) / 2;
if (k == items[mid])
return mid;
else if (k < items[mid]) {
right = mid - 1;
}
else
left = mid + 1;
}
if (k > items[mid])
mid++;
return ~mid;
}
template <typename T>
void InsertSortBS(T* items, int cnt) {
T k;
int i, j, m, n = cnt;
for (m = 1; m < n; m++) {
k = items[m];
//i = lower_bound(items, items + m, k) - items;
i = BinarySearch(k, items, cnt, 0, m);
if (i < 0)
i = ~i;
for (j = m - 1; j >= i; j--)
items[j + 1] = items[j];
items[i] = k;
}
}
氣泡排序
template <typename T>
void myswap(T& x, T& y) {
T t;
t = x;
x = y;
y = t;
}
template <typename T>
void BubbleSort(T* items, int cnt) {
for (int i = cnt-1; i > 0; i--) {
bool exchanged = false;
for (int j = 0; j < i; j++)
{
if (items[j] > items[j + 1])
{
exchanged = true;
myswap(items[j], items[j+1]);
}
}
if (!exchanged)
break;
}
}
選擇排序
template <typename T>
void myswap(T& x, T& y) {
T t;
t = x;
x = y;
y = t;
}
template <typename T>
void SelectSort(T* items, int cnt) {
for (int i = 0; i < cnt; i++)
{
T minidx = i ;
for (int j = i + 1; j < cnt; j++) {
if (items[j] < items[minidx])
minidx = j;
}
myswap(items[minidx], items[i]);
}
}
快速排序的原理
1.首先確定一個基準值 \(pilot\) 一般為第一個元素
2.使用兩個地址位,第二個元素的地址位為 \(i\) ,最後一個元素的地址位為 \(j\)
3.對 \(i\) 遞增操作,直到找到一個 \(i\) 地址位的元素使得其值大於基準值,對 \(j\) 遞減操作,只打找到一個 \(j\) 地址位的元素使得其值小於基準值
4.交換 \(i\) 與 \(j\) 兩個地址位的元素,重複3中過程,直到不滿足 \(i< j\)
5.\(i++,j--\) 然後交換基準元素與 \(j\) 地址位的元素,並以基準值元素為界來分別對左邊的元素和右邊的元素進行1到5的操作,直到只剩下一個元素為止
歸併排序的原理
1.二分割槽間,把兩邊的序列認為是已經有序的序列,並將兩個有序的序列合成一個有序的序列
2.對於每個想要其有序的序列,對其進行歸併排序再合併
3.遞迴下去,就得到了一個有序的序列
排序的趟數
初始序列並不是第一趟
氣泡排序的最後一趟要跟倒數第二趟一模一樣
雜湊查詢
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-06\Ori\3c133f0a5fdf0413e89921ee4b4b647c.jpeg)
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-06\Ori\e13068a43d93ef4360a11ff104ddeed5.jpeg)
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-06\Ori\86f091129330f87f534b297e41a5840b.jpeg)
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-06\Ori\d9179f727410fa6ac5c8046cc8adc1ca.jpeg)
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-06\Ori\2679dc1123672baead525e0c8d1de1df.jpeg)
探測定址法
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-06\Ori\b1a15dd9574e152cc639bb0e1c721597.jpeg)
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-06\Ori\bace006c201e38ac122c0851e940b2ce.jpeg)
雜湊鏈法
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-06\Ori\0a66ca69d8d15fc77f0e89b595396bdc.jpeg)
雜湊表的實現(雜湊鏈法)
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-06\Ori\fdda1875299e820a78bfb690d51b6393.jpeg)
![img](file:///D:\qq訊息記錄\2844938982\nt_qq\nt_data\Pic\2024-06\Ori\ff7f86aa62a5c915a1468a9f3f41923f.jpeg)
順序查詢
template <typename IIT,typename T>
int Index(IIT first, IIT end, const T& k) {
int i = 0;
auto pitems = first;
while (pitems < end && (*pitems) != k) {
i++;
pitems++;
}
if (pitems == end)
return -1;
return i;
}
template <typename IIT,typename Predicate>
int IndexIf(IIT first, IIT end, Predicate pred) {
int i = 0;
auto pitems = first;
while (pitems < end && !pred(*pitems))
{
i++;
pitems++;
}
if (pitems == end)
return -1;
return i;
}
二分查詢
前提:序列已經成為有序狀態
template <typename T>
int BinarySearch1(const T& k,T* items, int len) {
int left = 0;
int right = len - 1;
int mid = 0;
while (left <= right) {
mid = (left + right) / 2;//最跡在這裡打i宣告,不然就寄了
if (k == items[mid])
return mid;
else if (k < items[mid])
right = mid - 1;
else
left = mid + 1;
}
if (k > items[mid])
mid++;
return ~mid;
}
如果遇到不存在的數,返回的數字是這個數應該插入的地方取反
例如輸出為-6,則是正確的插入位置為 \(6-1=5\)
分塊查詢
把資料按照某種規律儲存在不同的塊裡面,查詢的時候再對應塊查詢就可以了
二叉查詢樹、排序樹與判定樹
二叉查詢樹和二叉排序樹是一樣的,只是同一個東西的不同名字
二分判定樹則是每次二分查詢中 \(mid\) 的值