排序
插入排序
直接插入排序
//直接插入排序
void InsertSort(int A[], int n) {
int i, j, temp;
for (i = 1; i < n; i++) { //将各元素插入已经排好序的序列中
if (A[i] < A[i - 1]) { //若A[i]关键字小于前驱
temp = A[i]; //用temp暂存A[i]
for (j = i - 1; j >= 0 && A[j] > temp;
j--) { //检查所有前面已拍好序的元素
A[j + 1] = A[j]; //所有大于temp的元素都向后移动
}
A[j + 1] = temp; //复制到插入位置
}
}
}
//直接插入排序(带哨兵)
void InsertSort2(int A[], int n) {
int i, j;
for (i = 2; i <= n; i++) { //元素下标为1-n,n个元素长度为n+1,所有此处i<=n
if (A[i] < A[i - 1]) {
A[0] = A[i];
for (j = i - 1; A[j] > A[0]; j--) {
A[j + 1] = A[j];
}
A[j + 1] = A[0];
}
}
}
折半插入排序
//折半插入排序(带哨兵)
void InsertSort3(int A[], int n) {
int i, j, low, high, mid;
for (i = 2; i <= n; i++) {
A[0] = A[i];
low = 1, high = i - 1; //设置折半查找范围
//查找要插入的位置
while (low <= high) {
mid = (low + high) / 2;
if (A[mid] > A[0])
high = mid - 1;
else
low = mid + 1;
}
//将low到i-1位置的元素依次往后移
for (j = i - 1; j >= low; j--) {
A[j + 1] = A[j];
}
A[low] = A[0];
}
}
希尔排序
//希尔排序
void ShellSort(int A[], int n) {
int i, j, d;
//A[0]只是暂存单元,不是哨兵
for (d = n / 2; d >= 1; d /= 2) { //增量变化
for (i = d + 1; i <= n; i++) {
if (A[i] < A[i - d]) {
A[0] = A[i];
for (j = i - d; j > 0 && A[0] < A[j]; j -= d) {
A[j + d] = A[j];
}
A[j + d] = A[0];
}
}
}
}
交换排序
冒泡排序
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
//从后往前:每趟处理都会将最小元素放在最终位置
void BubbleSort(int A[], int n) {
for (int i = 0; i < n - 1; i++) { //共进行n-1趟排序
bool flag = false;
for (int j = n - 1; j > i; j--) { //一趟冒泡过程
if (A[j - 1] > A[j]) { //若为逆序
swap(A[j - 1], A[j]); //交换
flag = true;
}
}
if (flag == false) { //本趟遍历后没有发生变化,说明表已经有序
return;
}
}
}
//从前往后:每趟处理都会将最大元素放在最终位置
void BubbleSort2(int A[], int n) {
for (int i = 0; i < n - 1; i++) {
bool flag = false;
for (int j = 0; j < n - 1 - i; j++) {
if (A[j] > A[j + 1]) {
swap(A[j], A[j + 1]);
flag = true;
}
}
if (flag == false) { //本趟遍历后没有发生变化,说明表已经有序
return;
}
}
}
快速排序
//使用第一个元素将排序序列划分成左右两个部分
int Partition(int A[], int low, int high) {
int pivot = A[low]; //用第一个元素作为枢纽
/*
*确定枢纽元素位置的思路:
*移动high指针,直到找到比枢纽元素小的元素,执行A[low] = A[high]
*然后移动low指针,直到找到比枢纽元素大的元素,执行A[high] = A[low]
*然后再移动high指针.......,循环以上操作,直到low=high为止,
*low或high即为枢纽元素位置
*/
while (low < high) { //找出枢纽元素的位置
while (low < high &&
A[high] >= pivot) //移动high指针,直到找到比枢纽元素小的元素
--high;
A[low] = A[high];
while (low < high &&
A[low] <= pivot) //移动low指针,直到找到比枢纽元素大的元素
++low;
A[high] = A[low];
}
A[low] = pivot; //枢纽元素存放到最终位置
return low;
}
void QuickSort(int A[], int low, int high) {
if (low < high) {//递归跳出的条件
int pivotpos =Partition(A, low, high); //划分,获取枢纽元素的位置
QuickSort(A, low, pivotpos-1);//划分左子表
QuickSort(A, pivotpos+1, high);//划分右子表
}
}
选择排序
直接选择排序
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
//选择排序
void SelectSort(int A[], int n) {
for (int i = 0; i < n; i++) {
int min = i; //最小元素下标
for (int j = i + 1; j < n; j++) {
if (A[j] < A[min]) {
min = j; //更新最小元素下标
}
}
if (min != i) {
swap(A[i], A[min]);
}
}
}
堆排序
/**
*大根堆:递增序列
*小根堆:递减序列
*/
//将以k为根的子树调整为大根堆
void HeapAdjust(int A[], int k, int len) {
A[0] = A[k]; // A[0]暂存子树的根节点
for (int i = 2 * k; i <= len; i *= 2) {
if (i < len && A[i] < A[i + 1]) //沿k较大的子节点向下筛选
i++;
if (i < len && A[0] >= A[i])
break;
else {
A[k] = A[i]; //将A[i]调整到父节点上
k = i; //修改k值,继续向下筛选
}
}
A[k] = A[0];//被筛选结点的值放入最终位置
}
//建立大根堆
void BuildMaxHeap(int A[], int len) {
for (int i = (len / 2); i > 0; i--) {
HeapAdjust(A, i, len); //从后往前调整所有非终端节点
}
}
//堆排序的完整逻辑
void HeapSort(int A[], int len) {
BuildMaxHeap(A, len); //初始建堆
for (int i = len; i > 1; i--) {//n-1趟的交换和建堆过程
swap(A[i], A[1]); //堆顶元素和堆底元素进行交换
HeapAdjust(A, 1, len - 1);//调节剩余元素为堆
}
}
归并排序
/**
*算法执行思想:将两个有序序列合并为有序序列
* 对一个序列来说,其单个的元素即分别为单独的有序序列
* 所以第一趟处理是将整个序列分成n个单独的子序列
* 然后再递归的执行合并相邻的有序序列
*/
int n;
int* B = (int*)malloc(n * sizeof(int)); //辅助数组B
// A[low..mid]和A[mid+1...high]各自有序.将两部分合并
void Merge(int A[], int low, int mid, int high) {
int i, j, k;
for (k = low; k <= high; k++) {
B[k] = A[k]; //将A中所有元素复制到B中
}
/**
*以mid为界,B序列中[low,mid]及[mid+1,high]为两个有序序列
*i指向B中第一个序列的首元素
*j指向B中第2个序列的首元素
*k指向A序列中待存放元素的位置
*/
for (i = low, j = mid + 1, k = i; i <= mid && j <= high; k++) {
if (B[i] <= B[j]) {
A[k] = B[i++]; //将较小值复制到A中
} else {
A[k] = B[j++];
}
}
while (i <= mid) {
A[k++] = B[i++];
}
while (j <= high) {
A[k++] = B[j++];
}
}
void MergeSort(int A[], int low, int high) {
if (low < high) {
int mid = (low + high) / 2; //从中间划分
MergeSort(A, low, mid); //对左半部分归并排序
MergeSort(A, mid + 1, high); //对右半天归并排序
Merge(A, low, mid, high); //归并
}
}
查找
顺序查找
#define ElemType int
#define MaxSize 10
typedef struct {
ElemType* elem; //动态数组基地址
int TableLen; //表长
} SSTable;
int Search_Seq1(SSTable L, ElemType key) {
L.elem[0] = key;
int i;
for (i = L.TableLen; L.elem[i] != key; --i)
; //从后往前找
return i; //若表中不存在关键字为key的元素,将查找到i为0时退出for循环
}
int Search_Seq2(SSTable L, ElemType key) {
int i;
for (int i = 0; i < L.TableLen && L.elem[i] != key; i++)
;
return i == L.TableLen ? -1 : i;
}
折半查找
#define ElemType int
#define MaxSize 10
typedef struct {
ElemType* elem; //动态数组基地址
int TableLen; //表长
} SSTable;
//折半查找
int Binary_Search(SSTable L, ElemType key) {
int low = 0, high = L.TableLen - 1, mid;
while (low <= high) {
mid = (high + low) / 2;
if (L.elem[mid] == key) {
return mid;
} else if (L.elem[mid] > key) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
二叉排序树
typedef struct BSTNode {
int key;
int length;
struct BSTNode *lchild, *rchild;
} BSTNode, *BSTree;
//在二叉排序树中查找-非递归实现
BSTNode* BST_Search(BSTree T, int key) {
while (T != NULL && key != T->key) {
if (key < T->key)
T = T->lchild;
else
T = T->rchild;
}
return T;
}
//在二叉排序树中查找-递归实现
BSTNode* BST_Search2(BSTree T, int key) {
if (T == NULL) {
return NULL;
}
if (key == T->key) {
return T;
} else if (key > T->key) {
return BST_Search(T->rchild, key);
} else {
return BST_Search(T->lchild, key);
}
}
//二叉排序树的插入
bool Bst_Insert(BSTree& T, int key) {
if (T == NULL) {
T = (BSTNode*)malloc(sizeof(BSTNode));
T->key = key;
T->lchild = NULL;
T->rchild = NULL;
return true;
} else if (key == T->key) {
return false;
} else if (key > T->key) {
return Bst_Insert(T->rchild, key);
} else {
return Bst_Insert(T->lchild, key);
}
return true;
}
//二叉排序树的构造
//按照str[]中的关键字序列建立二叉排序树
void Create_BST(BSTree& T, int str[], int n) {
T = NULL; //初始时T为空树
int i = 0;
while (i < n) {
Bst_Insert(T, str[i]);
i++;
}
}
int main() {
BSTree T;
int str[4];
Create_BST(T, str, 4);
}
树
递归遍历
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
struct ElemType {
int data;
};
typedef struct BiTNode {
ElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
void visit(BiTree& T) { cout << "当前根节点" << T->data.data << endl; }
//先序遍历
void PreOrder(BiTree T) {
if (T != NULL) {
visit(T);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
//中序遍历
void InOrder(BiTree T) {
if (T != NULL) {
PreOrder(T->lchild);
visit(T);
PreOrder(T->rchild);
}
}
//后续遍历
void PostOrder(BiTree T) {
if (T != NULL) {
PreOrder(T->lchild);
PreOrder(T->rchild);
visit(T);
}
}
//求树的深度
int treeDepth(BiTree T) {
if (T == NULL) {
return 0;
} else {
int l = treeDepth(T->lchild);
int r = treeDepth(T->rchild);
return l > r ? l + 1 : r + 1;
}
}
非递归遍历
//中序遍历
void Inoreder2(BiTree T) {
InitStack(S); //初始化栈S
BiTree p = T; // P是遍历指针
while (p || !IsEmpty(S)) { //栈不空或p不空时循环
if (p) { //一路向左
push(S, p); //当前结点入栈
p = p->lchild; //左孩子不空,一直向左走
} else { //出战,并转向出战结点的右子树
Pop(S, p); //栈顶元素出战
visit(p); //访问出栈结点
p = p->rchild; //向右子树走,p赋值为当前结点的右孩子
} //返回while循环继续进入 if-else语句
}
}
//先序遍历
void PreOrder2(BiTree T) {
InitStack(S); //初始化栈S
BiTree p = T; // P是遍历指针
while (p || !IsEmpty(S)) { //栈不空或p不空时循环
if (p) { //一路向左
visit(p); //访问出栈结点
push(S, p); //当前结点入栈
p = p->lchild; //左孩子不空,一直向左走
} else { //出战,并转向出战结点的右子树
Pop(S, p); //栈顶元素出战
p = p->rchild; //向右子树走,p赋值为当前结点的右孩子
} //返回while循环继续进入 if-else语句
}
}
/**
* 后序遍历:
* 思想:1.沿着根的左孩子,依次入栈,直到左孩子为空
* 2.读栈顶元素:若其右孩子不空且未被访问过,将右子树转执行,否则,栈顶元素出栈并访问
*/
void PostOrder2(BiTree T) {
InitStack(S);
BiTNode* P = T;
BiTNode* r = NULL;
while (P || !IsEmpty(S)) {
if (p) //走到最左边
{
push(S, p);
p = p->lchild;
} else { //向右
GetTop(S, p); //读栈顶顶点(非出栈)
if (p->rchild && p->rchild != r) //若右子树存在,且未被访问过
{
p = p->rchild; //转向右
} else { //否则,弹出结点并访问
pop(S, p); //将结点弹出
visit(p->data); //访问该结点
r = p; //记录最近访问过的结点
p = NULL; //结点访问完后,重置p指针
}
}
}
}
层序遍历
#include <cstddef>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <ostream>
#include <stdio.h>
#include <stdlib.h>
/**
*算法思想:
*1.初始化一个辅助队列
*2.根节点入队
*3.若队列非空,则队头结点出队,访问该结点,并将其左右结点插入队尾
*4.重复3直至队列为空
**/
typedef struct BiTNode {
int data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
typedef struct LinkNode {
BiTNode* data; //存储的是结点
struct LinkNode* next;
} LinkNode;
typedef struct {
LinkNode *front, *rear;
} LinkQueue;
void EnQueue(LinkQueue& Q, BiTree& T) {
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = T;
s->next = NULL;
if (Q.front == NULL) {
Q.front = s;
Q.rear = s;
} else {
Q.rear->next = s;
Q.rear = s;
}
}
bool DeQueue(LinkQueue& Q, BiTree& T) {
if (Q.front == NULL) { //空队
return false;
}
LinkNode* q = Q.front;
T = q->data;
Q.front = q->next;
if (Q.rear == q) {
Q.rear = NULL;
Q.front = NULL;
}
free(q);
return true;
}
void InitQueue(LinkQueue& Q) {
Q.front = NULL;
Q.rear = NULL;
}
bool IsEmpty(LinkQueue& Q) {
if (Q.front == NULL) {
return true;
} else {
return false;
}
}
void visit(BiTree& T) { printf("%d\n", T->data); }
//层序遍历
void LevelOrder(BiTree T) {
LinkQueue Q;
InitQueue(Q);//初始化辅助队列
BiTree p;
EnQueue(Q, T);//将根节点入队
while (!IsEmpty(Q)) {//队列不空则循环
DeQueue(Q, p);//队头结点出队
visit(p);//访问出队结点
if (p->lchild != NULL) {
EnQueue(Q, p->lchild);//左结点入队
}
if (p->rchild != NULL) {
EnQueue(Q, p->rchild);//右结点入队
}
}
}
中序线索二叉树
#include <cstddef>
#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
struct ElemType {
int data;
};
typedef struct ThreadNode {
ElemType data;
struct ThreadNode *lchild, *rchild;
int ltag, rtag; //左右线索标志
} ThreadNode, *ThreadTree;
//全局变量pre,指向当前访问节点的前驱
ThreadNode* pre = NULL;
void visit(ThreadTree& p) {
if (p->lchild == NULL) { //左子树为空,建立前驱线索
p->lchild = pre;
p->ltag = 1;
}
if (pre != NULL && pre->rchild == NULL) {
pre->rchild = p; //建立前驱节点的后继线索
pre->rtag = 1;
}
pre = p;
}
void InThread(ThreadTree T) {
if (T != NULL) {
InThread(T->lchild);
visit(T);
InThread(T->rchild);
}
}
void CreateInThread(ThreadTree& T) {
pre = NULL;
if (T != NULL) {
InThread(T); //中序线索化二叉树
if (pre->rchild == NULL) {
pre->rtag = 1; //处理遍历的最后一个结点
}
}
}
//寻找中序后继
//找到以p为根的子树中,第一个被中序遍历的结点
ThreadNode* FirstNode(ThreadNode* p) {
//循环找到最左下结点(不一定是叶结点)
while (p->ltag == 0) {
p = p->lchild;
}
return p;
}
//寻找指定结点的后继结点
ThreadNode* Nextnode(ThreadNode* p) {
if (p->rtag == 0) {
return FirstNode(p->rchild);
} else {
return p->rchild; // rtag==1直接返回后继线索
}
}
//对中序线索二叉树进行中序遍历(非递归算法)
void Inorder(ThreadNode* T) {
/**
*FirstNode(T):找到以p为根的子树中,第一个被中序遍历的结点
*Nextnode(p):找当前结点的中序后继
*空间复杂度:O(1)
*/
for (ThreadNode* p = FirstNode(T); p != NULL; p = Nextnode(p)) {
visit(p);
}
}
//寻找中序前驱
//找到以p为根的子树中,最后一个被中序遍历的结点
ThreadNode* LastNode(ThreadNode* p) {
//循环找到最右下结点(不一定是叶结点)
while (p->rtag == 0) {
p = p->rchild;
}
return p;
}
//寻找指定结点的前驱节点
ThreadNode* PreNode(ThreadNode* p) {
if (p->ltag == 0) {
return LastNode(p->lchild);
} else {
return p->lchild; // ltag==1直接返回前继线索
}
}
//对中序线索二叉树进行逆向中序遍历
void RevInorder(ThreadNode* T) {
/**
*LastNode(T):找到以p为根的子树中,最后一个被中序遍历的结点
*PreNode(p):找当前结点的中序前驱
*空间复杂度:O(1)
*/
for (ThreadNode* p = LastNode(T); p != NULL; p = PreNode(p)) {
visit(p);
}
}
先序线索二叉树
#include <cstddef>
#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
/**
*只有先序遍历才会出现循环指向问题
*/
struct ElemType {
int data;
};
typedef struct ThreadNode {
ElemType data;
struct ThreadNode *lchild, *rchild;
int ltag, rtag; //左右线索标志
} ThreadNode, *ThreadTree;
//全局变量pre,指向当前访问节点的前驱
ThreadNode* pre = NULL;
void visit(ThreadTree& p) {
if (p->lchild == NULL) { //左子树为空,建立前驱线索
p->lchild = pre;
p->ltag = 1;
}
if (pre != NULL && pre->rchild == NULL) {
pre->rchild = p; //建立前驱节点的后继线索
pre->rtag = 1;
}
pre = p;
}
void PreThread(ThreadTree T) {
if (T != NULL) {
visit(T);
/*解决先序遍历中的循环指向问题
*左孩子指针一旦线索化,它所指向的节点就是当前节点的前驱节点,
*然后再遍历该节点的左孩子将会陷入循环
*
**/
if (T->ltag == 0) { // lchild不是前驱线索
PreThread(T->lchild);
}
PreThread(T->rchild);
}
}
void CreatePreThread(ThreadTree& T) {
pre = NULL;
if (T != NULL) {
PreThread(T); //中序线索化二叉树
if (pre->rchild == NULL) {
pre->rtag = 1; //处理遍历的最后一个结点
}
}
}
//寻找先序后继
//找到以p为根的子树中,第一个被中序遍历的结点
ThreadNode* FirstNode(ThreadNode* p) {
//循环找到最左下结点(不一定是叶结点)
while (p->ltag == 0) {
p = p->lchild;
}
return p;
}
//寻找指定结点的后继结点
ThreadNode* Nextnode(ThreadNode* p) {
/**
* p->rtag == 0:说明一定有右节点,但有没有左节点不确定
* 根据先序遍历规则,根左右,当左结点存在时,即为当前节点后继
* 当只有右结点时,后继节点即为右节点
*/
if (p->rtag == 0) {
if (p->ltag == 0) {
return p->lchild;
} else {
return p->rchild;
}
} else {
return p->rchild; // rtag==1直接返回后继线索
}
}
/**寻找指定结点的前驱结点
*1.若p->ltag==1,则pre=p->lchild
*2.若p->ltag==0,说明p必有左节点,但按照先序遍历的规则
* 不能往回找
* 解决方式:
* 1.采用传统的先序遍历方式,即重新进行一遍先序遍历
* 2.创建带有父指针的三叉链表
* 可能出现的情况:
1.如果能找到p的父节点,且p是左孩子
p的父节点即为其前驱
2.如果能找到p的父节点,且p是右孩子,其左兄弟为空
p的父节点即为其前驱
3.如果能找到p的父节点,且p是右孩子,其做兄弟非空
p的前驱为左兄弟子树中最后一个被先序遍历的节点
4.如果p是根节点,则p没有先序前驱
*/
后序线索二叉树
#include <cstddef>
#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
struct ElemType {
int data;
};
typedef struct ThreadNode {
ElemType data;
struct ThreadNode *lchild, *rchild;
int ltag, rtag; //左右线索标志
} ThreadNode, *ThreadTree;
//全局变量pre,指向当前访问节点的前驱
ThreadNode* pre = NULL;
void visit(ThreadTree& p) {
if (p->lchild == NULL) { //左子树为空,建立前驱线索
p->lchild = pre;
p->ltag = 1;
}
if (pre != NULL && pre->rchild == NULL) {
pre->rchild = p; //建立前驱节点的后继线索
pre->rtag = 1;
}
pre = p;
}
void PostThread(ThreadTree T) {
if (T != NULL) {
PostThread(T->lchild);
PostThread(T->rchild);
visit(T);
}
}
void CreatePosThread(ThreadTree& T) {
pre = NULL;
if (T != NULL) {
PostThread(T); //中序线索化二叉树
if (pre->rchild == NULL) {
pre->rtag = 1; //处理遍历的最后一个结点
}
}
}
/**寻找指定结点的前驱结点
*1.若p->ltag==1,则pre=p->lchild
*2.若p->ltag==0,说明p必有左节点,但有没有右节点不一定
* 根据后序遍历规则,左右根,当右结点存在时,即为当前节点前驱
* 当只有左结点时,后继节点即为左节点
*/
//寻找指定结点的前驱结点
ThreadNode* PreNode(ThreadNode* p) {
if (p->ltag == 0) {
if (p->rtag == 0) {
return p->rchild;
} else {
return p->lchild;
}
} else {
return p->lchild; // rtag==1直接返回后继线索
}
}
/**寻找指定结点的后继结点
*1.若p->rtag==1,则next=p->rchild
*2.若p->rtag==0,说明p必有右节点,但按照后序遍历的规则
* 左右节点只能是它的前驱,不能是它的后继
* 解决方式:
* 1.采用传统的后续序遍历方式,即重新进行一遍先序遍历
* 2.创建带有父指针的三叉链表
* 可能出现的情况:
1.如果能找到p的父节点,且p是右孩子
p的父节点即为其后继
2.如果能找到p的父节点,且p是左孩子,其右兄弟为空
p的父节点即为其后继
3.如果能找到p的父节点,且p是左孩子,其右兄弟非空
p的后继为右兄弟子树中第一个被后序遍历的节点
4.如果p是根节点,则p没有后序后继
*/