栈stack和队列queue属于动态集合,使用策略:
stack: last-in, first-out, LIFO
queue: first-in, first-out, FIFO
- InitStack(S):初始化空栈S;
- StackEmpty(S):判断一个栈是否为空;
- Push(&S,x):进栈,若栈未满,则将x加入使之成为新栈顶;
- Pop(&S,&x):出栈,若栈非空,则将栈顶元素,并用x返回;
- GetTop(S,&x):读栈顶元素,若栈顶元素非空,则用x返回栈顶元素;
- DestroyStack(&S):销毁栈,并释放栈S占用的存储空间.
- InitQueue(&Q):初始化队列,构造一个空队列Q;
- QueueEmpty(Q):判断一个队列是否为空;
- EnQueue(&Q,x):入队,若队列未满,则将x加入使之成为新队尾;
- DeQueue(&Q,&x):出队,若队列非空,则将队首元素删除,并用x返回;
- GetHead(Q,&x):读队头元素,若栈顶元素非空,则用x返回栈顶元素.
二叉树(Binary Tree)每个节点至多只有两颗子树,并且二叉树的子树有左右之分,其次序不能任意颠倒.
//链式存储结构
typedef struct BiTrNode{
ElemType data;
struct BiTrNode *parent, *lchild, *rchild;
int height;
}BiTrNode,*BiTree;
//顺序存储结构
int bi_tree[]={A,B,C,D,E,F,G}; //按深度顺次记录
二叉树与度为2的有序树的区别:
- 度为2的树至少有三个结点,而二叉树可以为空
- 度为2的有序树的孩子结点左右次序是相对的,二叉树的结点次序是确定的
先序遍历:访问根结点,先序遍历左子树,先序遍历右子树
中序遍历:中序遍历左子树,访问根结点,中序遍历右子树
后序遍历:后序遍历左子树,后序遍历右子树,访问根结点
void visit(BiTree T){
printf("%d", T->data);
}
void PreOrder(BiTree T) {
if (T != nullptr) {
visit(T);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
void InOrder(BiTree T) {
if (T != nullptr) {
InOrder(T->lchild);
visit(T);
InOrder(T->rchild);
}
}
void PostOrder(BiTree T) {
if (T != nullptr) {
PostOrder(T->lchild);
PostOrder(T->rchild);
visit(T);
}
}
时间复杂度都为 O ( N ) O(\text{N}) O(N); 空间复杂度都为 O ( N ) O(\text{N}) O(N)
层次遍历:需要借助队列。先将二叉树根结点入队,然后出队,访问该结点。
void LevelOrder(BiTree T) {
if (T == nullptr) {
return;
}
Queue < BiTrNode * > q; //辅助队列
q.push(T); //将根结点入队
while (!q.empty()) { //队列不为空时
int sz = q.size();
for (int i = 0; i < sz; i++) {
BiTrNode *cur = Q.front();
q.pop(); //队头元素出队
if (p->lchild != nullptr) {
q.push(p->lchild);//左子树不为空时,左子树入队
}
if (p->rchild != nullptr) {
q.push(p->rchild);//右子树不为空时,右子树入队
}
}
}
}
计算搜索关键值的均长: A S L = ∑ i = 1 n p i c i ASL=\sum^{n}_{i=1}\textit{p}_{i}\textit{c}_{i} ASL=∑i=1npici ,其中 p i \textit{p}_{i} pi 是查找第 i i i 个值的概率, c i \textit{c}_{i} ci 是找到第 i i i 个关键值前进行的比较次数。
方便搜索使用,为难的是插入与删除:任何节点的键值一定大于其左子树中的每一个节点的键值,并小于其右子树的每一个节点的键值。
找起来很方便:
//search a given key in a given BST
struct node *search(struct node *root, int key) {
//Base Cases: root is null or key is present at root
if (root == NULL || root->key == key) {
return root;
}
//Key is greater than root's key
if (root->key < key) {
return search(root->rchild, key);
}
//Key is smaller than root's key
return search(root->lchild, key);
}
//insert a new node with given key in BST
struct node *insert(struct node *node, int key) {
if (node == NULL) { //If the tree is empty, return a new node
return newNode(key);
}
//Otherwise, recur down the tree
if (key < node->key) {
node->lchild = insert(node->lchild, key);
} else if (key > node->key) {
node->rchild = insert(node->rchild, key);
}
//return the (unchanged) node pointer
return node;
}
// deletes the key and returns the new root
struct node *deleteNode(struct node *root, int key) {
if (root == NULL) { return root; } // empty
// If key to be deleted < root's key
// then it lies in left subtree
if (key < root->key) {
root->lchild = deleteNode(root->lchild, key);
}
// If key to be deleted > root's key
// then it lies in right subtree
else if (key > root->key) {
root->rchild = deleteNode(root->rchild, key);
}
// if key == root's key
// the node is to be deleted
else {
// node with only one child or no child
if (root->lchild == NULL) {
struct node *temp = root->rchild;
free(root);
return temp;
} else if (root->rchild == NULL) {
struct node *temp = root->lchild;
free(root);
return temp;
}
// node with two children:
// Get the inorder successor
// smallest in the right subtree
struct node *current = root->rchild;
// loop down to find the leftmost leaf
while (current && current->lchild != NULL) {
current = current->lchild;
}
struct node *temp = current;
// Copy the inorder
// successor's content to this node
root->key = temp->key;
// Delete the inorder successor
root->rchild = deleteNode(root->rchild, temp->key);
}
return root;
}
插入方式 | 描述 | 旋转方式 |
---|---|---|
LL | root 的左子树节点的左子树上的节点破坏平衡 |
右旋转 |
RR | root 的右子树节点的右子树上的节点破坏平衡 |
左旋转 |
LR | root 的左子树节点的右子树上的节点破坏平衡 |
先左后右 |
RL | root 的右子树节点的左子树上的节点破坏平衡 |
先右后左 |
T1, T2, T3 and T4 are AVL subtrees.
1. Left Left Case
z y
/ \ / \
y T4 Right Rotate (z) x z
/ \ - - - - - - - - -> / \ / \
x T3 T1 T2 T3 T4
/ \
T1 T2
2. Left Right Case
z z x
/ \ / \ / \
y T4 Left Rotate (y) x T4 Right Rotate(z) y z
/ \ - - - - - - - - -> / \ - - - - - - - -> / \ / \
T1 x y T3 T1 T2 T3 T4
/ \ / \
T2 T3 T1 T2
3. Right Right Case
z y
/ \ / \
T1 y Left Rotate(z) z x
/ \ - - - - - - - -> / \ / \
T2 x T1 T2 T3 T4
/ \
T3 T4
4. Right Left Case
z z x
/ \ / \ / \
T1 y Right Rotate (y) T1 x Left Rotate(z) z y
/ \ - - - - - - - - -> / \ - - - - - - - -> / \ / \
x T4 T2 y T1 T2 T3 T4
/ \ / \
T2 T3 T3 T4
左或者右旋转:
// right rotate subtree rooted with y
struct node *rightRotate(struct node *y) {
struct node *x = y->left;
struct node *T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left), height(y->right)) + 1;
x->height = max(height(x->left), height(x->right)) + 1;
// Return new root
return x;
}
// left rotate subtree rooted with x
struct node *leftRotate(struct node *x) {
struct node *y = x->right;
struct node *T2 = y->left;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left), height(x->right)) + 1;
y->height = max(height(y->left), height(y->right)) + 1;
// Return new root
return y;
}
加上插入节点步骤:
// insert a key in the subtree rooted with node
// and returns the new root of the subtree.
struct node *insert(struct node *node, int key) {
// 1. Perform the BST insertion
if (node == NULL) {
struct node *node = (struct node *) malloc(sizeof(struct node));
node->key = key;
node->left = NULL;
node->right = NULL;
node->height = 1; // new node is initially added at leaf
return node;
}
if (key < node->key) node->left = insert(node->left, key);
else if (key > node->key) node->right = insert(node->right, key);
else return node;// Equal keys are not allowed in BST
// 2. Update height of its ancestor
node->height = 1 + max(height(node->left), height(node->right));
// 3. Check whether its ancestor node became unbalanced
int balance = 0;
if (node != NULL) {
balance = height(node->left) - height(node->right);
}
// unbalanced 4 cases:
// LL Case
if (balance > 1 && key < node->left->key)
return rightRotate(node);
// RR Case
if (balance < -1 && key > node->right->key)
return leftRotate(node);
// LR Case
if (balance > 1 && key > node->left->key) {
node->left = leftRotate(node->left);
return rightRotate(node);
}
// RL Case
if (balance < -1 && key < node->right->key) {
node->right = rightRotate(node->right);
return leftRotate(node);
}
// return the (unchanged) node pointer
return node;
}
删除一个节点
// delete a node with given key from subtree with given root
struct node *deleteNode(struct node *root, int key) {
// 1. BST deletion
if (root == NULL) return root;
// If the key to be deleted is smaller than the
// root's key, then it lies in left subtree
if (key < root->key) root->left = deleteNode(root->left, key);
// If the key to be deleted is greater than the
// root's key, then it lies in right subtree
else if (key > root->key) root->right = deleteNode(root->right, key);
// if key is same as root's key, then This is
// the node to be deleted
else {
// node with only one child or no child
if ((root->left == NULL) || (root->right == NULL)) {
struct node *temp = root->left ? root->left : root->right;
if (temp == NULL) {// No child case
temp = root;
root = NULL;
} else // One child case
*root = *temp; // Copy the contents of the non-empty child
free(temp);
} else {
// node with two children: Get the inorder
// successor (smallest in the right subtree)
struct node *current = root->right;
// loop down to find the leftmost leaf
while (current->left != NULL) {
current = current->left;
}
struct node *temp = current;
// Copy the inorder successor's data to this node
root->key = temp->key;
// Delete the inorder successor
root->right = deleteNode(root->right, temp->key);
}
}
if (root == NULL) return root; // empty
// 2. Update height of current node
root->height = 1 + max(height(root->left), height(root->right));
// 3. Check whether this node became unbalanced
int balance_root = 0, balance_left = 0, balance_right = 0;
if (root != NULL) balance_root = height(root->left) - height(root->right);
if (root->left != NULL) balance_left = height(root->left->left) - height(root->left->right);
if (root->right != NULL) balance_right = height(root->right->left) - height(root->right->right);
// unbalanced 4 cases:
// LL Case
if (balance_root > 1 && balance_left >= 0)
return rightRotate(root);
// LR Case
if (balance_root > 1 && balance_left < 0) {
root->left = leftRotate(root->left);
return rightRotate(root);
}
// RR Case
if (balance_root < -1 && balance_right <= 0)
return leftRotate(root);
// RL Case
if (balance_root < -1 && balance_right > 0) {
root->right = rightRotate(root->right);
return leftRotate(root);
}
return root;
}
树中结点常常被赋予一个表示某种意义的数值,称为该结点的权。从树根结点到任意结点的路径长度(经过的边数)与该结点上权值的乘积,称为该结点的带权路径长度。树中所有结点的带权路径长度之和称为全树的带权路径长度,记为: WPL = ∑ i = 1 n W i L i \displaystyle{\textit{WPL}=\sum_{i=1}^{n}W_iL_i} WPL=i=1∑nWiLi ,其中, W i W_i Wi 是第 i i i 个结点所带的权值, L i L_i Li 是该结点到根结点的路径长度。
在含有 n n n 个带权叶的二叉树中,其中带权路径长度 ( W P L ) (WPL) (WPL) 最小的二叉树称为哈夫曼树,也称最优二叉树。
void Select(HuffmanTree &HT, int n, int &min1, int &min2) {
int minnum;
for (int i = 1; i <= n; i++) { //find the minimum
if (HT[i].parent == 0) {
minnum = i;
break;
}
}
for (int i = 1; i <= n; i++) {
if (HT[i].parent == 0) if (HT[i].weight < HT[minnum].weight) minnum = i;
}
min1 = minnum;
for (int i = 1; i <= n; i++) { //second minimum
if (HT[i].parent == 0 && i != min1) {
minnum = i;
break;
}
}
for (int i = 1; i <= n; i++) {
if (HT[i].parent == 0 && i != min1) if (HT[i].weight < HT[minnum].weight) minnum = i;
}
min2 = minnum;
}
void CreatHuff(HuffmanTree &HT, int *weight, int count) {
int num, min1, min2;
num = count * 2 - 1; //the number of nodes
HT = (HuffmanTree) malloc(sizeof(HTNode) * num); //allocate the memory space
for (int index = 1; index <= count; index++) { //original sequence
HT[index].weight = weight[index];
HT[index].parent = 0;
HT[index].lchild = 0;
HT[index].rchild = 0;
}
for (int index = count + 1; index <= num; index++) { //initialize
HT[index].weight = 0;
HT[index].parent = 0;
HT[index].lchild = 0;
HT[index].rchild = 0;
}
printf("\nthe HuffmanTree is: \n");
for (int index = count + 1; index <= num; index++) {
//find the first two minimum nodes in the sequence of HT[1]~HT[i-1] as min1 min2
Select(HT, index - 1, min1, min2);
HT[min1].parent = index; //empty the nodes
HT[min2].parent = index;
HT[index].lchild = min1; //set the l/r child as min1/min2
HT[index].rchild = min2;
HT[index].weight = HT[min1].weight + HT[min2].weight; //weight of their parent
printf("%d (%d, %d)\n", HT[index].weight, HT[min1].weight, HT[min2].weight);
}
printf("\n");
}
邻接矩阵(Adjacency Matrix)的存储结构是用一维数组存储图中顶点的信息
e.g.图 G = ( V , E ) G=(V, E) G=(V,E) 有 n n n 个确定的顶点,即 V = { v 0 , v 1 , ⋯ , v n − 1 } V=\{v_0, v_1, \cdots, v_{n-1}\} V={v0,v1,⋯,vn−1} ,则表示 G G G 中各顶点相邻关系为一个 n × n n \times n n×n 的矩阵,矩阵的元素为 a r c [ i ] [ j ] = { 1 , 若 ( v i , v i ) ∈ E 或 < v i , v i > ∈ E ; 0 , 反 之 arc[i][j]=\begin{cases} 1, 若 (\textit{v}_{i}, \textit{v}_{i}) \in \textit{E} 或 <\textit{v}_{i}, \textit{v}_{i}> \in \textit{E};\\ 0, 反之 \end{cases} arc[i][j]={1,若(vi,vi)∈E或<vi,vi>∈E;0,反之
邻接表:
node v 0 v 1 v 2 v 3 v 4 v 0 v 1 v 2 v 3 v 4 ∣ 0 1 0 0 1 1 0 1 1 1 0 1 0 1 0 1 1 0 1 0 ∣ \begin{array}{cc} \text{node}\begin{array}{cccc} \textit{v}_0&\textit{v}_1&\textit{v}_2&\textit{v}_3&\textit{v}_4\\ \end{array}\\ \begin{array}{c} \textit{v}_0\\ \textit{v}_1\\ \textit{v}_2\\ \textit{v}_3\\ \textit{v}_4 \end{array} \left|\begin{array}{llcrr} 0&1&0&0&1 \\ 1&0&1&1&1 \\ 0&1&0&1&0 \\ 1&1&0&1&0 \\ \end{array}\right| \end{array} nodev0v1v2v3v4v0v1v2v3v4∣∣∣∣∣∣∣∣01011011010001111100∣∣∣∣∣∣∣∣
针对上示图,建立邻接表:
// A C Program to demonstrate adjacency list
// representation of graphs
#include
#include
// A structure to represent an adjacency list node
struct AdjListNode {
int dest;
struct AdjListNode *next;
};
// A structure to represent an adjacency list
struct AdjList {
struct AdjListNode *head;
};
// A structure to represent a graph. A graph
// is an array of adjacency lists.
// Size of array will be V (number of vertices
// in graph)
struct Graph {
int V;
struct AdjList *array;
};
// A utility function to create a new adjacency list node
struct AdjListNode *newAdjListNode(int dest) {
struct AdjListNode *newNode = (struct AdjListNode *) malloc(sizeof(struct AdjListNode));
newNode->dest = dest;
newNode->next = NULL;
return newNode;
}
// A utility function that creates a graph of V vertices
struct Graph *createGraph(int V) {
struct Graph *graph = (struct Graph *) malloc(sizeof(struct Graph));
graph->V = V;
// Create an array of adjacency lists. Size of
// array will be V
graph->array = (struct AdjList *) malloc(V * sizeof(struct AdjList));
// Initialize each adjacency list as empty by
// making head as NULL
int i;
for (i = 0; i < V; ++i) {
graph->array[i].head = NULL;
}
return graph;
}
// Adds an edge to an undirected graph
void addEdge(struct Graph *graph, int src, int dest) {
// Add an edge from src to dest. A new node is
// added to the adjacency list of src. The node
// is added at the beginning
struct AdjListNode *check = NULL;
struct AdjListNode *newNode = newAdjListNode(dest);
if (graph->array[src].head == NULL) {
newNode->next = graph->array[src].head;
graph->array[src].head = newNode;
} else {
check = graph->array[src].head;
while (check->next != NULL) {
check = check->next;
}
//graph->array[src].head = newNode;
check->next = newNode;
}
// Since graph is undirected, add an edge from
// dest to src also
newNode = newAdjListNode(src);
if (graph->array[dest].head == NULL) {
newNode->next = graph->array[dest].head;
graph->array[dest].head = newNode;
} else {
check = graph->array[dest].head;
while (check->next != NULL) {
check = check->next;
}
check->next = newNode;
}
//newNode = newAdjListNode(src);
//newNode->next = graph->array[dest].head;
//graph->array[dest].head = newNode;
}
构建方法:
int Find(int n) {
while(n!=pre[n])
n=pre[n];
return n;
}//寻找祖宗节点
void Merge_set(LINE node) {
int i=Find(node.mmp);
int j=Find(node.mvp);
if(i!=j) {
pre[i]=j;
coun++; //记录路数
sun+=node.weight;
}
}//这条弧入集
node:节点序号
selected:记录是否被加入MST中,初始为False
minDist:与当前操作的节点的最小路径,初始为 ∞ \infty ∞
parent:该节点最后相连的父节点,初始为-1
记顶点数 v v v,边数 e e e
90 % 90\% 90% 等同于Prim算法
时间复杂度: O ( e log v ) O(e \text{log} v) O(elogv)
应用于求任意两个顶点的最小路径,时间复杂度: O ( v 3 ) O(v^3) O(v3)
e.g. P − 1 0 1 2 3 0 1 2 3 0 5 ∞ 10 ∞ 0 3 ∞ ∞ ∞ 0 1 ∞ ∞ ∞ 0 \begin{array}{cc} \text{P}_{-1} \begin{array}{cccc} \text{ 0 }&\text{ 1 }&\text{ 2 }&\text{ 3 }\\ \end{array}\\ \begin{array}{c} 0\\1\\2\\3 \end{array} \boxed{\begin{array}{llcrr} 0 & 5 & \infin & 10\\ \infin & 0 & 3 & \infin\\ \infin & \infin & 0 & 1\\ \infin & \infin & \infin & 0\\ \end{array}} \end{array} P−1 0 1 2 3 01230∞∞∞50∞∞∞30∞10∞10,这是迭代前的两点直接连接的距离,类似于邻接矩阵。
思路:初始化解矩阵等于输入的图矩阵。依次将每一个顶点视为中间节点来更新所有最短路径。
if(k 不是从 i 到 j 的最短路径中的中间顶点){
保持 dist[i][j] 的值不变;
}
else if(k 是从 i 到 j 的最短路径中的中间顶点){
if(dist[i][j] > dist[i][k] + dist[k][j]){
(dist[i][j] = dist[i][k] + dist[k][j];
}
}
也就是最大长度的路径计算
一个很傻的简单方法 DFS(无向图)
时间复杂度: O ( v ⋅ ( v + e ) ) O(v \cdot (v + e)) O(v⋅(v+e))
设定max_length
记录DFS过程中的最大边长和,当访问了所有节点后的length_sum
大于max_length
,则更新max_length
当前值。
一些概念:
- DAG (directed acycline graph):有向无环图;使用并查集可以判断是否为无环图
- AOV网 (Activity On Vertex Network):在有向图中,用顶点表示活动,用边及其边长表示活动之间的优先关系。AOV网不应该出现环,即不存在某项活动是以自己为先决条件的
在一个有向图中,对所有的节点进行排序,要求没有一个节点指向它前面的节点(即入度为0)。
1. 统计所有节点的入度
2. 分离出入度为0的节点,把该节点指向的节点的入度减一
3. 循环2.直到所有的节点都被分离出来
4. 如果最后不存在入度为0的节点,说明有环—>不存在拓扑排序—>无解
一些概念:
- AOE网 (activity on edge network):以边表示活动,顶点表示事件的网。是一个带权、有向、无环图。权值可表示活动持续的时间/成本等
- 关键路径(critical path):从开始点到完成点的最长路径长度,表示了完整完成活动的时间/成本总量
e.g.
event(node) | v0 | v1 | v2 | v3 | v4 | v5 | v6 | v7 | v8 |
---|---|---|---|---|---|---|---|---|---|
v e a r l y v_{early} vearly | 0 | 6 | 4 | 5 | 7 | 7 | 16 | 14 | 18 |
v l a t e v_{late} vlate | 0 | 6 | 6 | 8 | 7 | 10 | 16 | 14 | 18 |
acti(edge) | a1 | a2 | a3 | a4 | a5 | a6 | a7 | a8 | a9 | a10 | a11 |
---|---|---|---|---|---|---|---|---|---|---|---|
e e e | 0 | 0 | 0 | 6 | 4 | 5 | 7 | 7 | 7 | 16 | 14 |
l l l | 0 | 2 | 3 | 6 | 6 | 8 | 7 | 7 | 10 | 16 | 14 |
每次从待排序列中选出一个最小(大)值,然后放在序列的起始位置,直到全部待排数据排完即可。p.s.其实也可以同时搞定min,max
时间: O ( N 2 ) O(\text{N}^2) O(N2); 空间: O ( 1 ) O(1) O(1)
void SelectSort(int *arr, int count) {
int begin = 0, end = count - 1;
while (begin < end) {
int max_index = begin; //保存最大值的下标
int min_index = begin; //保存最小值的下标
for (int index = begin; index <= end; index++) { //找出最大值和最小值的下标
if (arr[index] < arr[min_index]) {
min_index = index;
}
if (arr[index] > arr[max_index]) {
max_index = index;
}
}
swap(&arr[min_index], &arr[begin]); //最小值放在序列开头
if (begin == max_index) { //防止最大的数在begin位置被换走
max_index = min_index;
}
swap(&arr[max_index], &arr[end]); //最大值放在序列结尾
begin++; end--; //向中间收拢待排序列
}
}
选出左右孩子中小的哪一个,跟父亲交换,小的往上浮,大的往下沉,如果要建大堆则相反。
建堆时间: O ( N ) O(\text{N}) O(N);
向下调整算法的时间: O ( log 2 N ) O(\textit{log}_{2}\text{N}) O(log2N);
堆排序的时间: O ( N ⋅ log 2 N ) O(\text{N}\cdot\textit{log}_{2}\text{N}) O(N⋅log2N)
//堆向下调整算法
//建小堆
void AdjustDown(int *heap, int count, int root) {
int parentI = root;
int childI = parentI * 2 + 1;
while (childI < count) { //孩子在数组下标范围内
if (heap[childI + 1] < heap[childI] && childI + 1 < count) {//防止没有右孩子
++childI;
}
if (heap[childI] < heap[parentI]) { //小的往上浮,大的往下浮
int temp = heap[parentI];
heap[parentI] = heap[childI];
heap[childI] = temp;
parentI = childI;
childI = parentI * 2 + 1;
} else { //中途child>parent则已满足小堆,直接break
break;
}
}
}
//堆的向上调整算法,插入新数据时使用
void AdjustUp(int *heap, int childI) {
int parentI = (childI - 1) / 2;
while (childI > 0) {
if (heap[childI] < heap[parentI]) {
int temp = heap[parentI];
heap[parentI] = heap[childI];
heap[childI] = temp;
childI = parentI;
parentI = (childI - 1) / 2;
} else {
break;
}
}
}
//降序
void HeapSort(int *heap, int count) {
for (int index = (count - 1 - 1) / 2; index >= 0; --index) {
AdjustDown(heap, count, index);
}
int end = count - 1;
//把最小的换到最后一个位置,不把最后一个数看作堆里的
//每次选出剩下数中最小的
//从后往前放
while (end > 0) {
int temp = heap[end];
heap[end] = heap[0];
heap[0] = temp;
//选出次小的数
AdjustDown(heap, end, 0);
end--;
}
}
由num[i]开始,取temp=num[i],i由0开始往后移动直至n-1;
temp=num[i]由num[i-1]开始往前扫描,直至number[0],若temp更小(大)则交换,非则插入不动。最后得到升(降)序表。
时间 O ( N 2 ) O(\text{N}^{2}) O(N2); 空间 O ( 1 ) O(1) O(1)
void InsertSort(int *arr, int count) {
for (int index = 0; index < count - 1; index++) {
int end = index; //记录有序序列最后一个元素的下标
int tem = arr[end + 1]; //待插入的元素
while (end >= 0) { //单趟排
if (tem < arr[end]) { //比插入的数大就向后移
arr[end + 1] = arr[end];
end--;
} else { //比插入的数小,跳出循环
break;
}
}
arr[end + 1] = tem; //tem放到比插入的数小的数的后面
}
}
分组进行预排序,使得排序接近有序,再进行插入排序。分组依次为 n 2 i \frac{n}{2^i} 2in 个。
时间: O ( N 1.5 ) O(\text{N}^{1.5}) O(N1.5); 空间: O ( 1 ) O(1) O(1)
void ShellSort(int *arr, int count) {
int gap = count;
while (gap > 1) {
gap = gap / 2; //每次对gap折半操作
for (int index = 0; index < count - gap; index++) { //单趟排序
int end = index;
int temp = arr[end + gap];
while (end >= 0) { //依次对比
if (temp < arr[end]) {
arr[end + gap] = arr[end];
end -= gap;
} else {
break;
}
}
arr[end + gap] = temp; //插入数据
}
}
}
左边大于右边交换一趟排下来最大的在右边
时间: O ( N 2 ) O(\text{N}^{2}) O(N2); 空间: O ( 1 ) O(1) O(1)
/*Partition method which selects a pivot
and places each element which is less than the pivot value to its left
and the elements greater than the pivot value to its right
arr[] --- array to be partitioned
lower --- lower index
upper --- upper index
*/
int partition(int arr[], int lower, int upper) {
int i = (lower - 1);
int pivot = arr[upper]; // Selects last element as the pivot value
int j;
for (j = lower; j < upper; j++) {
if (arr[j] <= pivot) { // if current element is smaller than the pivot
i++; // increment the index of smaller element
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[upper]);
//places the last element i.e, the pivot to its correct position
return (i + 1);
}
/*This is where the sorting of the array takes place
arr[] --- Array to be sorted
lower --- Starting index
upper --- Ending index
*/
void quickSort(int arr[], int lower, int upper) {
if (upper > lower) {
// partitioning index is returned by the partition method , partition
// element is at its correct poition
int partitionIndex = partition(arr, lower, upper);
// Sorting elements before and after the partition index
quickSort(arr, lower, partitionIndex - 1);
quickSort(arr, partitionIndex + 1, upper);
}
}