线性表
顺序表
#define MaxSize 100
typedef struct{
ElementType data[Maxsize];
int length;
}sqList;
-
相关操作
1. 在第i个位置插入元素e
bool insert(sqList &L,int i,ElementType e) { if(i<1||i>L.length+1) return false; for(int j=L.length;j>=i;j--) L.data[j]=L.data[j--]; L.data[i-1]=e; L.length++; return true; }
平均移动次数:n/2
2. 删除第i个元素
bool del(sqList &L,int i,ElementType &e) { if(i<1||i>L.length) return false; e=L.data[i-1]; for(int j=i;j<L.length;j++) L.data[j--]=L.data[j]; L.length--; return true; }
平均移动次数:(n-1)/2
3. 按值查找
int Locate(sqList L,ElementType e) { for(int i=0;i<L.length;i++) if(L.data[i]==e) return i+1; return 0; }
平均移动次数:(n+1)/2
单链表
-
数据结构
typedef struct LNode{ ElementType data; struct LNode *next; }LNode, *LinkList;
-
相关操作(有头结点)
1. 头插法建立单链表
LinkList List_HeadInsert(LinkList &L) { LNode *p;int x; L=new LNode; //创建头结点 L->next=NULL; cin>>x; while(!cin.eof()) { p=new LNode; p->data=x; p->next=L->next; L->next=p; } return L; }
2. 尾插法建立单链表
LinkList List_TailInsert(LinkList &L) { int x; L=new LNode; //创建头结点 LNode *p,*r=L; //尾指针 L->next=NULL; cin>>x; while(!cin.eof()) { p=new LNode; p->data=x; r->next=p; r=p; } r->next=NULL; return L; }
3. 按序号查结点
LNode *GetElem(LinkList L,int i) { int cnt=1; LNode *p=L->next; if(i==0) return L; if(i<1) return NULL; while(p&&cnt<j) { p=p->next; cnt++; } return p; }
4. 按值查结点
LNode *LocateElem(LinkList L,ElementType e) { LNode *p=L->next; while(p&&p->data!=e) p=p->next; return p; }
5. 在第i个位置插入结点
bool insert(LinkList L,ElementType e) { LNode *p=GetElem(L,i-1); if(p==NULL) return false; LNode *q=new LNode; q->next=p->next; p->next=q; return true; }
6. 删除第i个结点
bool del(LinkList L,ElementType e) { LNode *p=GetElem(L,i-1); if(p==NULL) return false; LNode *q=p->next; p->next=q->next; delete q; return true; }
双链表
-
数据结构
typedef struct DNode{ ElemType data; struct DNode *pre,*next; }DNode,*DLinklist;
-
相关操作
1. *p结点后插入 *s
void insert(DLinklist &L,DNode p,ElemType e) { DNode *s=new DNode; s->data=e; s->next=p->next; p->next->pre=s; p->next=s; s->pre=p; }
2. 删除*p结点后 *q
void del(DLinklist &L,DNode p) { DNode *q=p->next; p->next=q->next; q->next->pre=p; delete q; }
栈
顺序栈
-
数据结构
#define MaxSize 100 typedef struct { elemType data[MaxSize]; int top; //指向栈顶元素 }SqStack;
-
相关操作
1. 初始化
void initStack(SqStack &S) { S.top=-1; }
2. 判断栈空
void StackEmpty(SqStack S) { if(S.top=-1) return true; else return false; }
3. 进栈
bool push(SqStack &S,ElemType x) { if(S.top==MaxSize-1) return false; S.data[++S.top]=x; return true; }
4. 出栈
bool pop(SqStack &S,ElemType &x) { if(S.top==-1) return false; x=S.data[S.top++]; return true; }
5. 读栈顶
bool getTop(SqStack S,ElemType &x) { if(S.top==-1) return false; x=S.data[S.top]; return true; }
链栈
栈的应用
-
括号匹配
#include <iostream> #include <stack> #include <string> using namespace std; int main() { int cnt = 0; string s; stack<char> S; cout << "请输入判断的括号字符串:" << endl; cin >> s; for (int i = 0; i < s.length(); i++) { if (s[i] == '[' || s[i] == '(' || s[i] == '{') { S.push(s[i]); } else if (s[i] == ']') { if (S.top() == '[') { cnt++; S.pop(); } else break; } else if (s[i] == ')') { if (S.top() == '(') { cnt++; S.pop(); } } else if (s[i] == '}') { if (S.top() == '{') { cnt++; S.pop(); } } } if(S.empty()) cout << "配对成功,共" << cnt << "对括号"; else cout << "配对失败!"; }
-
求后缀表达式
#include <bits/stdc++.h>
using namespace std;
//栈内优先级
int isp(char c)
{
if (c == '#')
{
return 0;
}
else if (c == '(')
{
return 1;
}
else if (c == '+' || c == '-')
{
return 3;
}
else if (c == '*' || c == '/')
{
return 5;
}
else if (c == ')')
{
return 6;
}
}
//栈外优先级
int icp(char c)
{
if (c == '#')
{
return 0;
}
else if (c == '(')
{
return 6;
}
else if (c == '+' || c == '-')
{
return 2;
}
else if (c == '*' || c == '/')
{
return 4;
}
else if (c == ')')
{
return 1;
}
}
string change(string str)
{
string S;
stack<int> data;
stack<char> op;
op.push('#');
str += '#';
int index = 0;
while (index < str.size())
{
if (str[index]>='0'&&str[index]<='9')
{
string s2;
while(str[index]>='0'&&str[index]<='9') //防止数字被拆开压栈
{
s2+=str[index];
index++;
}
data.push(stoi(s2));
S+=to_string(data.top());
S+=" ";
}
else
{
if (icp(str[index]) == isp(op.top()))
{
op.pop();
index++;
}
else if (icp(str[index]) > isp(op.top()))
{ //运算符进栈
op.push(str[index]);
index++;
}
else
{
if (op.top() == ')')
{ //如果该运算符是右括号,则直接弹出
op.pop();
}
else
{
S += op.top(); //输出
S+=" ";
op.pop();
}
}
}
}
return S;
}
#include <bits/stdc++.h>
using namespace std;
//栈内优先级
int isp(char c)
{
if (c == '#')
{
return 0;
}
else if (c == '(')
{
return 1;
}
else if (c == '+' || c == '-')
{
return 3;
}
else if (c == '*' || c == '/')
{
return 5;
}
else if (c == ')')
{
return 6;
}
}
//栈外优先级
int icp(char c)
{
if (c == '#')
{
return 0;
}
else if (c == '(')
{
return 6;
}
else if (c == '+' || c == '-')
{
return 2;
}
else if (c == '*' || c == '/')
{
return 4;
}
else if (c == ')')
{
return 1;
}
}
int main()
{
cout << "请输入中缀表达式:" << endl;
string s, ss;
cin>>s;
ss = change(s);
cout << "后缀表达式为:" <<ss<< endl;
stack<int> data;
for (int i = 0; i < ss.length(); i++)
{
if (ss[i] >= '0' && ss[i] <= '9')
{
string s2;
while(ss[i]>='0'&&ss[i]<='9') //防止数字被拆开压栈,保持整数完整性
{
s2+=ss[i];
i++;
}
data.push(stoi(s2));
}
else if(ss[i]==' ')
continue;
else
{
int res = 0;
int x, y;
y = data.top();
data.pop();
x = data.top();
data.pop();
if (ss[i] == '+')
res = x + y;
else if (ss[i] == '-')
res = x - y;
else if (ss[i] == '*')
res = x * y;
else
res = x / y;
data.push(res);
}
}
cout << "表达式的结果为:" << data.top() << endl;
return 0;
}
#include <bits/stdc++.h>
using namespace std;
int opcmp(char a, char b)
{
if ((a == '*' || a == '/') && (b == '+' || b == '-' || b == '(' || b == '#'))
return 1;
else if ((a == '+' || a == '-') && (b == '(' || b == '#'))
return 1;
else
return 0;
}
//计算运算值栈顶两个元素(a栈顶第一个元素,b栈顶第二个元素)
int calculate(char c, int a, int b)
{
int res = 0;
switch (c)
{
case '+':
res = b + a;
break;
case '-':
res = b - a;
break;
case '*':
res = b * a;
break;
case '/':
res = b / a;
break;
}
return res;
}
int main()
{
stack<int> data;
stack<char> op;
op.push('#');
cout << "请输入中缀表达式:" << endl;
string s;
cin >> s;
int i = 0;
while (i < s.length())
{
if (s[i] >= '0' && s[i] <= '9') //数字直接进栈
{
string ss;
while (s[i] >= '0' && s[i] <= '9') //防止数字被拆开压栈,保持整数完整性
{
ss += s[i];
i++;
}
data.push(stoi(ss));
}
else //运算符
{
char x = s[i];
char y = op.top();
if (x == '(' || opcmp(x, y)) //优先级高入栈
op.push(x);
else
{
if (x == ')') //右括号,一直运算直到左括号出栈
{
while (y != '(')
{
int a = data.top();
data.pop();
int b = data.top();
data.pop();
data.push(calculate(y, a, b));
op.pop();
y = op.top();
}
op.pop();
}
else //优先级低运算出栈直到遇到高的再进栈
{
while (!opcmp(x, y))
{
int a = data.top();
data.pop();
int b = data.top();
data.pop();
data.push(calculate(y, a, b));
op.pop();
y = op.top();
}
op.push(x);
}
}
i++;
}
}
while (op.top()!='#')
{
char y = op.top();
int a = data.top();
data.pop();
int b = data.top();
data.pop();
data.push(calculate(y, a, b));
op.pop();
}
cout << "运算结果为:" << data.top() << endl;
}
队列
顺序队列
循环队列
-
数据结构
#define MaxSize 50 typedef struct{ ElemType data[MaxSize]; int front,rear; }SqQueue;
-
相关操作
1. 初始化
void init(SqQueue &Q) { Q.rear=Q.front=0; }
2. 判断队列是否空
bool empty(SqQueue Q) { if(Q.front==Q.rear) return true; else return false; }
3. 入队
bool enQueue(SqQueue &Q,ElemType x) { if((Q.rear+1)%MaxSize==Q.front) //队满 return false; Q.data[Q.rear]=x; Q.rear=(Q.rear+1)%MaxSize; return true; }
4. 出队
bool deQueue(SqQueue &Q,ElemType &x) { if(Q.front==Q.rear) //队空 return false; x=Q.data[Q.front]; Q.front=(Q.front+1)%MaxSize; return true; }
队满:(Q.rear+1)%MaxSize==Q.front
队空:Q.front==Q.rear
队中元素个数:(Q.rear-Q.front+MaxSize)%MaxSize
链队
-
数据结构
typedef struct LinkNode{ ElemType data; struct LinkNode *next; }LinkNode; typedef struct{ LinkNode *front,*rear; }LinkQueue;
-
相关操作(有头结点)
1. 初始化
void init(LinkQueue &Q) { Q.front=Q.rear=new LinkNode; //建立头结点 Q.front->next=NULL; }
2. 判队空
void empty(LinkQueue Q) { if(Q.front==Q.rear) return true; //建立头结点 return false; }
3. 入队
void enQueue(LinkQueue &Q,ElemType x) { LinkNode *p=new LinkNode; p->data=x; p->next=NULL; Q.rear->next=p; Q.rear=p; }
4. 出队
bool deQueue(LinkQueue &Q,ElemType &x) { if(Q.rear==Q.front) return false; LinkNode *p=Q.front->next; x=p->data; Q.font->next=p->next; if(Q.rear=p) //若只剩最后一个结点,尾指针头指针都指向头结点 Q.rear=Q.front; delete p; return true; }
树
二叉树
-
数据结构
typedef struct BiTNode { ElemType data; struct BiTNode *lchild, *rchild; }BiTNode,*BiTree;
-
相关操作
以下图为例
1 2 0 4 6 0 0 0 3 0 5 0 01. 初始化建树
void create(BiTree &T) { int x; cin >> x; if (x == 0) T = NULL; else { T = new BiTNode; T->data = x; create(T->lchild); create(T->rchild); } }
2. 先序遍历
void preOrder(BiTree T) { if(T!NULL) { visit(T); preOrder(T->lchild); preOrder(T->rchild); }
3. 中序遍历
void inOrder(BiTree T) { if(T!NULL) { inOrder(T->lchild); visit(T); inOrder(T->rchild); } }
4. 后序遍历
void postOrder(BiTree T) { if(T!NULL) { postOrder(T->lchild); postOrder(T->rchild); visit(T); } }
5. 统计度为0结点个数
void degree0(BiTree T, int &res) { if (T != NULL) { if (T->lchild == NULL && T->rchild == NULL) { T->visit(); res++; } degree0(T->lchild, res); degree0(T->rchild, res); } }
6. 统计度为1结点个数
void degree1(BiTree T, int &res) { if (T != NULL) { if (T->lchild == NULL && T->rchild != NULL || T->lchild != NULL && T->rchild == NULL) { T->visit(); res++; } degree1(T->lchild, res); degree1(T->rchild, res); } }
7. 统计度为2结点个数
void degree2(BiTree T, int &res) { if (T != NULL) { if (T->lchild != NULL && T->rchild != NULL) { T->visit(); res++; } degree2(T->lchild, res); degree2(T->rchild, res); } }
8. 树的高度
void height(BiTree T, int &res, int &cnt) { if (T != NULL) { cnt++; height(T->lchild, res, cnt); res = max(cnt, res); height(T->rchild, res, cnt); res = max(cnt, res); cnt--; } } int height(BiTree T) { if (T == NULL) return 0; int lh = height(T->lchild); int rh = height(T->rchild); return max(lh + 1, rh + 1); }
9. 树的宽度
queue<BiTree> Q; int width(BiTree T) { int res = 0, cnt = 0; Q.push(T); while (!Q.empty()) { cnt = Q.size(); res = max(res, cnt); for (int i = 0; i < cnt; i++) { BiTNode *p; p = Q.front(); Q.pop(); if (p->lchild != NULL) { Q.push(p->lchild); } if (p->rchild != NULL) { Q.push(p->rchild); } } } return res; }
10. 删除所有叶子结点
void delLeaf(BiTree &T, BiTree &t) { if (T != NULL) { if (T->lchild == NULL && T->rchild == NULL) { if(t!=NULL) //t为NULL时只有根节点,只需删除T指针,若不为根节点修改T的父节点的左右指针 { if (T == t->lchild) t->lchild = NULL; else t->rchild = NULL; } delete (T); return; } t = T; delLeaf(T->lchild, t); delLeaf(T->rchild, t); } }
11. 计算指定结点*p的层次
void doLevel(BiTree T, int x, int l, int &level) { if (T) { if (T->data == x) { level = l; return; } else { doLevel(T->lchild, x, l+1, level); doLevel(T->rchild, x, l+1, level); } } }
12. 计算二叉树结点中最大元素的值
void calMax(BiTree T, int &m) { if (T) { m = max(T->data, m); calMax(T->lchild, m); calMax(T->rchild, m); } }
13. 交换每个结点的孩子
void swap(BiTree &T) { if(T) { BiTNode *p; p = T->lchild; T->lchild=T->rchild ; T->rchild= p; swap(T->lchild); swap(T->rchild); } }
14. 先序次序输出所有结点数值及所在层次
void preLevel(BiTree T, int l) { if (T) { cout << "结点" << T->data << "的层次为:" << l << endl; preLevel(T->lchild, l+1); preLevel(T->rchild, l+1); } }
线索二叉树
-
数据结构
typedef struct ThreadNode { char data; ThreadNode *lchild; ThreadNode *rchild; int ltag; // 0表示有孩子,1表示线索 int rtag; } ThreadNode,* ThreadTree;
-
相关操作
以 1 2 0 4 6 0 0 0 3 0 5 0 0为例
1. 构造中序线索二叉树
void visit(ThreadTree &pre) { if (this->lchild == NULL) { this->lchild = pre; this->ltag = 1; } if (pre != NULL && pre->rchild == NULL) { pre->rchild = this; pre->rtag = 1; } pre = this; } void inThread(ThreadTree &T, ThreadTree &pre) { if (T) { inThread(T->lchild, pre); T->visit(pre); inThread(T->rchild, pre); } } void createInThread(ThreadTree T) { if (T) { ThreadNode *pre = NULL; inThread(T, pre); if(pre->rchild == NULL) //处理最后一个结点 pre->rtag = 1; } }
2. 遍历中序线索二叉树
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; } void inOrder(ThreadTree T) { for (ThreadNode *p = firstNode(T); p != NULL; p = nextNode(p)) p->visit(); }
3. 逆向遍历中序线索二叉树
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; } void reInOrder(ThreadTree T) { for (ThreadNode *p = lastNode(T); p != NULL; p = preNode(p)) p->visit();
4. 构造先序线索二叉树
void preThread(ThreadTree &T, ThreadTree &pre) { if (T) { T->visit(pre); if (T->ltag == 0) //防止先线索化后走到前驱结点遍历时再走回来,原地打圈 preThread(T->lchild, pre); if (T->rtag == 0) preThread(T->rchild, pre); //防止先线索化后走到后继结点遍历时再走回来,原地打圈 } } void createPreThread(ThreadTree T) { if (T) { ThreadNode *pre = NULL; preThread(T, pre); if(pre->rchild == NULL) //处理最后一个结点 pre->rtag = 1; } }
5. 遍历先序线索二叉树
ThreadNode *nextNode(ThreadNode *p) { if (p->rtag == 0) //未被线索化 { if (p->ltag == 0) return p->lchild; //有左孩子,后继为左孩子 } return p->rchild; //被线索化或没被线索化无左孩子,后继都为右孩子 } void preOrder(ThreadTree T) { for (ThreadNode *p = T; p != NULL; p = nextNode(p)) p->visit(); }
6. 构造后序线索二叉树
void postThread(ThreadTree &T, ThreadTree &pre) { if (T) { postThread(T->lchild, pre); postThread(T->rchild, pre); T->visit(pre); } } void createPostThread(ThreadTree T) { if (T) { ThreadNode *pre = NULL; postThread(T, pre); if(pre->rchild == NULL) //处理最后一个结点 pre->rtag = 1; } }
7. 逆向遍历后序线索二叉树
ThreadNode *preNode(ThreadNode *p) { if (p->ltag == 0) //未被线索化 { if (p->rtag == 0) return p->rchild; //有右孩子,前驱为右孩子 } return p->lchild; //被线索化或没被线索化无右孩子,后继都为左孩子 } void postOrder(ThreadTree T) { for (ThreadNode *p = T; p != NULL; p = preNode(p)) p->visit(); }
树的应用
-
并查集
-
数据结构
树(森林)的双亲表示
#define Size 100 int UFSet[Size]
-
相关操作
-
初始化
void init(int s[]) { for (int i = 0; i < size;i++) s[i] = -1; }
-
找某元素的根,用以判断元素是否在一个集合
最坏:O(n)
int find(int s[], int x) { while (s[x] >= 0) x = s[x]; return x; } 优化:先找到根结点,再把查找路径上的非根结点挂到根节点上
-
求两个不相交子集合的并集,合并两集合
void union(int s[],int root1,int root2) { s[root2] = root1; } 优化:小树合并到大树下,用根节点的绝对值表示树的结点总数 void union(int s[], int root1, int root2) { if (root1 == root2) return; if (s[root2] > s[root1]) //root2为小树 { s[root1] += s[root2]; s[root2] = root1; } else { s[root2] += s[root1]; s[root1] = root2; } } ```
-
-
-
二叉排序树
中序遍历可得到有序序列
- 查找
-
非递归
BSTNode *BST_Search(BiTree T,ElemType key) { while(T!=NULL&&key!=T->data) { if(key<T->data) T = T->lchild; else T = T->rchild; } return T; }
-
递归
BSTNode *search(BiTree T, int x) { if (!T) return NULL; else { if (T->key == x) return T; else if (T->key > x) return search(T->lchild, x); else if (T->key < x) return search(T->rchild, x); } }
-
插入
int insert(BiTree &T, int x) { if (T == NULL) { T = new BSTNode; T->key = x; T->lchild = T->rchild = NULL; return 1; } else if (x == T->key) return 0; else if (x < T->key) return insert(T->lchild, x); else return insert(T->rchild, x); }
-
构造
void create(BiTree &T,int x) { if (insert(T, x) == 0) cout << "存在相同的结点,插入失败!" << endl; }
-
删除
BSTNode *search(BiTree T, int x, BiTree &pre) { while (T != NULL && x != T->key) { pre = T; if (x < T->key) T = T->lchild; else T = T->rchild; } return T; } int rMin(BiTree p) { int m = p->key; while (p != NULL) { if (p->key <= m) { m = p->key; p = p->lchild; } } return m; } void del(BiTree &T, int x) { BiTree pre = NULL; BiTree p = search(T, x, pre); if (p == NULL) cout << "未查到此值,删除失败!" << endl; else { if (p->lchild == NULL) //无左孩子,直接用右孩子代替 { if (pre->lchild == p) //是前驱结点的左孩子 pre->lchild = p->rchild; else //是前驱结点的右孩子 pre->rchild = p->rchild; free(p); } else if (p->rchild == NULL) //无右孩子,直接用左孩子代替 { if (pre->lchild == p) //是前驱结点的左孩子 pre->lchild = p->lchild; else //是前驱结点的右孩子 pre->rchild = p->lchild; free(p); } else if (p->lchild == NULL&&p->rchild == NULL) //是叶子结点,直接删除 free(p); else { //左右孩子都有,先找到左子树的最大值或右子树的最小值赋给要删除结点,再利用前两种方法删除这个直接前驱或直接后继 int m = rMin(p->rchild); del(T, m); p->key = m; } }
图
-
数据结构
- 邻接矩阵
class MGraph{ char Vex[MaxSize]; //顶点表 int Edge[MaxSize][MaxSize]; //边表 int vexNum; //顶点数 int arcNum; //边数 }
- 邻接表
class arcNode //边表结点 { int adjvex; //该边所指向的顶点的位置 arcNode *next; //指向下一个边表结点的指针 int info; //边权值 }; typedef class vNode adjList[Maxsize]; class vNode //顶点表结点 { char data; //顶点信息 arcNode *first; //指向第一个与之相连的边表结点 }; class AlGraph { adjList vertices; //邻接表 int vexNum; //顶点数 int arcNum; //边数 };
-
相关操作
以 为例
1. 遍历
-
广度优先
void BFSTraverse(Graph G) { for (int i = 0; i < G.vexNum;i++) visited[i] = false; initQueue(Q); for (int i = 0; i < G.vexNum;i++) if(!visited[i]) //对每个连通分量使用一次BFS BFS(G, i); } void BFS(Graph G,int v) //从v出发遍历 { visit(v); //访问初始顶点 visited[v] = true; enQueue(Q, v); while(!isEmpty(Q)) { deQueue(Q, v); for (w = firstNeighbor(G, v); w >= 0; w = nextNeighbor(G,v,w)) { if(!visited[w]) { visit(w); visited[w] = true; enQueue(Q, w); } } } }
-
深度优先
void DFSTraverse(Graph G) { for (int i = 0; i < G.vexNum; i++) visited[i] = false; initQueue(Q); for (int i = 0; i < G.vexNum; i++) if (!visited[i]) //对每个连通分量使用一次DFS BFS(G, i); } void DFS(Graph G, int v) //从v出发遍历 { visit(v); //访问顶点 visited[v] = true; enQueue(Q, v); for (w = firstNeighbor(G, v); w >= 0; w = nextNeighbor(G, v, w)) if(!visited[w]) DFS(G, w); }
2. 求x的邻接顶点y的下一个邻接顶点
-
邻接矩阵
int nextNeighbor(MGraph G, int x, int y) { if (x != -1 && y != -1) { for (int j = y + 1; y < G.vexNum; j++) { if (G.Edge[x][j] > 0 && G.edge[x][j] < maxWight) //maxWight为正无穷 return j; } } return -1; }
-
邻接表
int nextNeighbor(ALGraph G, int x, int y) { if (x != -1) { arcNode *p = G.vertices[x].first; while (p != NULL && p->data != y) //寻找邻接顶点y p = p->next; if (p->next != NULL) //返回下一个邻接顶点 return p->next->data; } return -1; }
图的应用
-
拓扑排序(邻接表)
bool TopoLogicalSort(Graph G) { initStack(S); //暂存入度为0的顶点,栈和队列都可以 for (int i = 0; i < G.vexNUm; i++) { if (indegree[i] == 0) push(S, i); } int cnt = 0; while (!isEmpty(S)) { pop(S, i); visit(i); cnt++; for (p = G.vertices[i].first; p; p = p->next) { int v = p->adjvex; indegree[v]--; if (indegree[v]==0) push(S, v); } } if(cnt<G.vexNum) // 访问顶点数小于总顶点数,拓扑排序失败,存在回路 return false; else return true; }
排序算法
插入排序
部分有序
-
直接插入排序
void inserSort(int a[], int n) { for (int i = 2; i <= n; i++) { if (a[i] < a[i - 1]) { a[0] = a[i]; //第一个空出来当哨兵 int j; for (j = i - 1; a[0] < a[j]; j--) //大的往后挪 a[j + 1] = a[j]; a[j + 1] = a[0]; } } }
-
折半插入排序
void halfInserSort(int a[], int n) { int low, high, mid; for (int i = 2; i <= n; i++) { a[0] = a[i]; //哨兵 low = 1; high = i - 1; while (low <= high) //折半查找插入位置low { mid = (low + high) / 2; if (a[mid] > a[0]) high = mid - 1; else low = mid + 1; } for (int j = i - 1; j >= low; j--) // low后面的都有往后挪 a[j + 1] = a[j]; a[low] = a[0]; } }
-
希尔排序
void shellSort(int a[], int n) { for (int d = n / 2; d >= 1; d /= 2) //改变步长 { for (int i = d + 1; i <= n; i++) //给某一组排序 { if (a[i] < a[i - d]) { a[0] = a[i]; int j; for (j = i - d; j > 0 && a[0] < a[j]; j -= d) a[j + d] = a[j]; //向后挪查找插入位置 a[j + d] = a[0]; } } } }
交换排序
全局有序
-
冒泡排序
void bubbleSort(int a[], int n) //从0开始存 { for (int i = 0; i < n - 1; i++) // n个数排序 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; } }
-
快速排序
初始序列越无序越好,划分越均匀越好
int partition(int a[], int low, int high) { int p = a[low]; //设区间的第一个元素为枢轴 while (low < high) //划分确定枢轴最终位置,low=high时 { while (low < high && a[high] >= p) high--; a[low] = a[high]; //将找到的比枢轴小的元素移动到左边 while (low < high && a[low] <= p) low++; a[high] = a[low]; //将找到的比枢轴小的元素移动到左边 } a[low] = p; //确定枢轴最终位置; return low; } void quickSort(int a[], int low, int high) { if (low < high) { int p = partition(a, low, high); quickSort(a, low, p - 1); quickSort(a, p + 1, high); } }
选择排序
-
简单选择排序
比较次数始终为n(n-1)/2,与数据初始状态无关
void selectSort(int a[], int n) { for (int i = 0; i < n - 1; i++) { int m = i; for (int j = i + 1; j < n; j++) if (a[j] < a[m]) m = j; if (m != i) swap(a[i], a[m]); } }
-
堆排序
数据越多越好
-
大根堆:升序
void headAdjust(int a[],int k,int n) //a[]从1开始存数据 { a[0] = a[k]; //暂存待调整结点值 for (int i = 2 * k; i <= n;i*=2) //沿待调整结点一路往下调整 { if (i < n&&a[i]<a[i+1]) i++; //选较大的子结点 if(a[0]>=a[i]) break; //待调整结点更大,不必调整 else { a[k] = a[i]; //较大子结点的值变成待调整结点位置上的值 k = i; //继续往下调整 } } a[k] = a[0]; //找到待调整结点最终位置放入 } void buildMaxHeap(int a[],int n) { for (int i = n / 2; i >= 1;i--) //从最后一个非叶子结点开始逐个调整非叶子结点 headAdjust(a, i, n); } void HeapSort(int a[],int n) { buildMaxHeap(a,n); //建堆 for (int i = n; i > 1;i--) //n-1次交换与调整 { swap(a[i],a[1]); //堆顶与堆底元素交换,最大元素放最后 headAdjust(a, 1, i - 1); //最大元素之前的元素调整 } }
-
小根堆:降序
void headAdjust(int a[], int k, int n) // a[]从1开始存数据 { a[0] = a[k]; //暂存待调整结点值 for (int i = 2 * k; i <= n; i *= 2) //沿待调整结点一路往下调整 { if (i < n && a[i] > a[i + 1]) i++; //选较小的子结点 if (a[0] <= a[i]) break; //待调整结点更小,不必调整 else { a[k] = a[i]; //较小子结点的值变成待调整结点位置上的值 k = i; //继续往下调整 } } a[k] = a[0]; //找到待调整结点最终位置放入 } void buildMinHeap(int a[], int n) { for (int i = n / 2; i >= 1; i--) //从最后一个非叶子结点开始逐个调整非叶子结点 headAdjust(a, i, n); } void HeapSort(int a[], int n) { buildMinHeap(a, n); //建堆 for (int i = n; i > 1; i--) // n-1次交换与调整 { swap(a[i], a[1]); //堆顶与堆底元素交换,最大元素放最后 headAdjust(a, 1, i - 1); //调整最大元素之前的所有元素 } }
-
归并排序
int *b=new int[n] ;
void merge(int a[],int low,int mid,int high)
{
int i,j,k;
for (k = low; k <= high; k++)
b[k] = a[k];
for (i = low, j = mid + 1, k = i; i <=mid && j <= high;k++)
{
if(b[i]<=b[j])
a[k] = b[i++];
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);
}
}
基数排序
依据关键字排序,越关键越后排
🔅排序比较
最后给大家推荐一个包含数据结构里面所有算法的动态演示网站:
可以更生动的理解算法细节,click me!
阅读到这里要给你一个大大的赞,全部掌握的你太棒啦!继续在计算机学习领域加油吧!整理不易,别忘了点赞收藏评论哦~