目录
字符串匹配(朴素算法)-附加代码模式(2023年数据结构补题-AX)
KMP算法中的模式串移动数组(2023年数据结构补题-AU)
后面写得有点潦草了,大家随便看看吧🥹🥹🥹
1.线性表
顺序表:数组(略)
链表:
1.结构体定义
struct node{
int data;
node* next;
};
typedef node* List;
2.基本操作
初始化(带头结点):
void Init(List &list){
list=new node;
list->next=NULL;
}
添加新节点(尾插法):
void Addnode(List &list,int v){
List p=list;
List a=new node;
a->data=v;
a->next=NULL;
while(p->next){
p=p->next;
}
p->next=a;
}
添加新节点(头插法):
void Addnodehead(List &list,int v){
List a=new node;
a->data=v;
a->next=list->next;
list->next=a;
}
输出链表:
void PrintList(List &list){
List p=list->next;
while(p){
cout<<p->data;
p=p->next;
}
}
销毁链表:
void Destroy(List &list){
List p;
while(list){
p=list;
list=p->next;
delete p;
}
}
3.一般操作
⭐有序单链表的有序合并(2023年数据结构补题-L)
List MergeList(List &lista,List &listb){
List listc;
Init(listc);
List a=lista->next;//我写的链表都是默认带头结点的
List b=listb->next;
while(a||b){
if(a==NULL){
while(b){
Addnode(listc,b->data);
b=b->next;
}
}else if(b==NULL){
while(a){
Addnode(listc,a->data);
a=a->next;
}
}else{
if(a->data<b->data){
Addnode(listc,a->data);
a=a->next;
}else{
Addnode(listc,b->data);
b=b->next;
}
}
}
return listc;
}
有序单链表删除重复结点(2023年数据结构补题-U)
void Remove Duplicate(List &list){
List p=list->next;
while(p->next){
if(p->data==p->next->data){
p->next=p->next->next;
}else{
p=p->next;
}
}
}
⭐单链表反转(2023年数据结构补题-X)
void ReverseList(List &list){
List p=list->next;
List res=NULL;
while(p){
List temp=p->next;
p->next=res;
res=p;
p=temp;
}
list->next=res;
}
两个有序链表序列的交集(2023年数据结构补题-AB)
这个交上去补题可能有点小bug,但大概没有问题
List GetIntersection(List &lista, List &listb) {
List listc;
InitList(listc);
List a = lista->next;
List b = listb->next;
while (a && b) {
if (a->data < b->data)
a = a->next;
else if (b->data < a->data)
b = b->next;
else {
AddNode(listc, a->data);
a = a->next;
b = b->next;
}
}
return listc;
}
2.栈和队列
可以用链式栈、链式队列,或STL实现。
栈和队列都是操作受限的线性表,栈FILO,队列FIFO。
1.栈
链式栈、链式队列我觉得有点难,写了一下没运行出来,就先不放上来了,遇到的话就先用STL吧。明天我再更新这一部分。这里我给出典型例题的STL方法求解。
⭐括号匹配问题(2023年数据结构补题-AI):
#include <bits/stdc++.h>
using namespace std;
int check(string s) {
stack<char> q;
for (int i = 0; i < s.size(); i++) {
if (s[i] == '(') {
q.push(s[i]);
} else if (s[i] == ')') {
if (q.empty())
return 0;
q.pop();
}
}
if (q.empty())
return 1;
return 0;
}
int main() {
string s;
while (cin >> s) {
if (check(s))
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
八进制数(2023年数据结构补题-AG):
#include <bits/stdc++.h>
using namespace std;
void print(stack<int> s) {
while (!s.empty()) {
cout << s.top();
s.pop();
}
cout << endl;
}
void conversion(int n) {
stack<int> s;
while (n) {
int a = n % 8;
n /= 8;
s.push(a);
}
print(s);
}
int main() {
int n;
while (cin >> n) {
conversion(n);
}
return 0;
}
行编辑程序(2023年数据结构补题-AH)
#include <bits/stdc++.h>
using namespace std;
void print(stack<char> s) {
stack<char> q;
while (!s.empty()) {
q.push(s.top());
s.pop();
}
while (!q.empty()) {
cout << q.top();
q.pop();
}
cout << endl;
}
void lineedit(string t) {
stack<char> s;
for (int i = 0; i < t.size(); i++) {
if (t[i] == '#')
s.pop();
else if (t[i] == '@') {
while (!s.empty()) {
s.pop();
}
} else
s.push(t[i]);
}
print(s);
}
int main() {
string s;
while (getline(cin, s)) {
lineedit(s);
}
return 0;
}
四则运算实在是比较难,但要掌握方法,会画表格。
2.递归
直接做经典例题,重点是掌握思想吧,后面做到图和树理解会更深。
n阶汉诺塔问题(2023年数据结构补题-AO):
#include <bits/stdc++.h>
using namespace std;
int i = 1;
void move(char x, int n, char z) {
printf("%2d. Move disk %d from %c to %c\n", i++, n, x, z);
}
void hanoi(int n, char x, char y, char z) {
if (n == 1)
move(x, 1, z);
else {
hanoi(n - 1, x, z, y);
move(x, n, z);
hanoi(n - 1, y, x, z);
}
}
int main() {
int n;
while (cin >> n) {
i = 1;
hanoi(n, 'X', 'Y', 'Z');
cout << endl;
}
return 0;
}
3.队列
了解双向队列、循环队列。
约瑟夫问题(2023年数据结构补题-AD):
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
cout << endl;
queue<int> q;
for (int i = 1; i <= n; i++)
q.push(i);
int number = 1;
while (q.front() != q.back()) {
if (number == m) {
cout << q.front() << " ";
q.pop();
} else {
int top = q.front();
q.pop();
q.push(top);
}
number++;
if (number == m + 1)
number = 1;
}
cout << q.front();
return 0;
}
3.字符串模式匹配
求子串第一次匹配位置的下标。
1.朴素算法
最好用while循环,因为这在后面运用KMP时只用做很少的改动。
字符串匹配(朴素算法)-附加代码模式(2023年数据结构补题-AX)
int findPos(char s[], char t[]) {
int m = strlen(s), n = strlen(t);
int i = 0, j = 0;
while (i < m && j < n) {
if (s[i] == t[j]) {//单个字符匹配时,i,j都后移
i++;
j++;
} else {//遇到不匹配时,i回溯到匹配之前的下一个位置
i = i - j + 1;
j = 0;
}
}
if (j == n) {//j=n表明子串完成匹配
return i - j;
} else {//j!=n表明退出循环的原因是i==m,则i直到最后都没有匹配
return -1;
}
}
2.KMP算法
⭐会写next数组,nextval数组,用next或nextval数组做模式匹配(江某某说考这个,我们敬请期待)
KMP算法中的模式串移动数组(2023年数据结构补题-AU)
void getNext(char t[], int next[]) {
next[0] = -1;
int i = 0, j = -1;
while (i < strlen(t)) {
if (j == -1 || t[i] == t[j])
next[++i] = ++j;
else
j = next[j];
}
}
改进的nextVal向量(2023年数据结构补题-AT)
void getValNext(char t[], int next[]) {
getNext(t, next);
for (int i = 1; i < strlen(t); i++) {
if (t[i] == t[next[i]])
next[i] = next[next[i]];
}
}
⭐字符串匹配KMP算法(没有题,可以试着交到朴素算法验证)
int kmp(char s[], char t[]) {
int next[max];
getValNext(t, next);
int m = strlen(s), n = strlen(t);
int i = 0, j = 0;
while (i < m && j < n) {
if (j == -1 || s[i] == t[j]) {
i++;
j++;
} else {
j = next[j];
}
}
if (j >= n) {
return i - j;
} else {
return -1;
}
}
4.数组和广义表
1.稀疏矩阵
将非零元用三元组的形式表示。
1.三元组、稀疏矩阵定义
struct TriNode{//r:行,c:列,v:值
int r,c,v;
};
struct TriMatrix{
int mu,nu,tu;
vector<TriNode> data;//三元组
vector<int> rsum;//每行非零元个数
vector<int> rpos;//行向量:每行第一个非零元下标
};
2.基本操作
输入(二维数组转三元组):
void input(TriMatrix &m){
cin>>m.mu>>m.nu;
int a[m.mu][m.nu],m.tu=0;
for(int i=0;i<m.mu;i++){
for(int j=0;j<m.nu;j++){
int b;
cin>>b;
if(b!=0){
m.data.push_back({i,j,b});
m.tu++;
}
}
}
}
计算每行非零元个数(填充rsum):
void Calcrsum(TriMatrix &m){
for(int i=0;i<m.mu;i++)
m.rsum.push_back(0);
for(int i=0;i<m.tu;i++)
m.rsum[m.data[i].r]++;
}
⭐计算行向量 (每行第一个非零元素下标):
void Calcrpos(TriMartix &m){
for(int i=0;i<m.mu;i++)
m.rpos.push_back(0);
for(int i=1;i<m.mu;i++)
m.rpos[i]=m.rpos[i-1]+m.rsum[i-1];
}
⭐稀疏矩阵乘法(2023年数据结构补题二-D):
void AddNode(TrtMatrix &m,int r,int c,int v){//添加新节点
int flag=0;
for(int i=0;i<m.tu;i++){
if(m.data[i].r==r&&m.data[i].c==c){//如果对应位置有值则相加
m.data[i].v+=v;
flag=1;
}
}
if(flag==0){//如果没有,则新增加结点
m.data.push_back({r,c,v});
m.tu++;
}
}
void MulMatrix(TriMatrix &m1,TriMatrix &m2){
TriMatrix m3;
m3.mu=m1.mu;
m3.nu=m2.nu;
m3.tu=0;
for(int i=0;i<m1.tu;i++){
int a=m1.data[i].c;
for(int j=m2.rpos[a];j<m2.rpos[a]+m2.rsum[a];j++){
AddNode(m3,m1.data[i].r,m2.data[j].c,m1.data[i].v*m2.data[j].v);
}
}
}
⭐稀疏矩阵转置:
void FastTranspose(TriMatrix &m, TriMatrix &n) {
n.mu = m.nu;
n.nu = m.mu;
n.tu = m.tu;
//统计n的每行非零元素个数
for (int i = 0; i < n.mu; i++) {
n.rsum.push_back(0);
}
for (int i = 0; i < m.tu; i++) {
n.rsum[m.data[i].c]++;
}
//计算n的行向量
n.rpos.push_back(0);
for (int i = 1; i < n.mu; i++) {
n.rpos[i] = n.rpos[i - 1] + n.rsum[i - 1];
}
//填写n的data,以行优先顺序
for (int i = 0; i < n.tu; i++)
n.data.push_back({0, 0, 0});
for (int i = 0; i < m.tu; i++) {
int a = n.rpos[m.data[i].c];
n.data[a].r = m.data[i].c;
n.data[a].c = m.data[i].r;
n.data[a].v = m.data[i].v;
n.rpos[m.data[i].c]++;
}
}
2.数组(多维数组下标换算)
⭐公式:
定义数组:
struct Array {
int dims;//维数
int dimlength[maxsize];//各维长度
int partlength[maxsize + 1]; //换算辅助数组
};
数组赋值初始化(分别填写dimlength、partlength):
void InitArray(int n, Array &a, int dim[]) {
a.dims = n;
for (int i = 0; i < n; i++)
a.dimlength[i] = dim[i];
a.partlength[n - 1] = 1;
for (int i = n - 2; i >= 0; i--) {
a.partlength[i] = a.partlength[i + 1] * dim[i + 1];
}
}
计算一维数组下标:
int result(Array &a, int index[]) {
int ans = 0;
for (int i = 0; i < a.dims; i++) {
ans += (index[i] * a.partlength[i]);
}
return ans;
}
5.二叉树
二叉树:度不大于2的有向树。
1.性质
⭐设、、分别为度为0,1,2的结点,则
- 第层最多有个结点
- 深度为h的树,最少有h个结点,最多有个结点
- 结点数为n,深度最大为n,最小为
2.结构体定义
struct BiNode{
int data;
BiNode *lchild;
BiNode *rchild;
};
typedef *BiNode BiTree;
3.基本操作
创建二叉树(带虚结点的前序遍历序创建)
char* CreateBiTree(BiTree &T,char *str){
if(*str=="#"){
T=NULL;
return str+1;
}
T=new BiNode;
T->data=*str;
char*leftstr=CreateBiTree(T->lchild,str+1);
return CreateBiTree(T->rchild,leftstr);
}
销毁二叉树
void DestroyBiTree(BiTree &T){
if(T==NULL)return;
DestroyBiTree(T->lchild);
DestroyBiTree(T->rchild);
delete T;
T=NULL;
}
求二叉树深度
int Depth(BiTree &T){
if(T==NULL)return 0;
return max(Depth(T->lchild),Depth(T->rchild))+1;
}
求二叉树结点数
int NodeSum(BiTree &T){
if(T==NULL)return 0;
return NodeSum(T->lchild)+NodeSum(T->rchild)+1;
}
⭐前序遍历
递归:
void PreTraverse(BiTree &T){
if(T==NULL)
return;
visit(T);
PreTraverse(T->lchild);
PreTraverse(T->rchild);
}
非递归:
void PreTraverse(BiTree &T){
stack<BiTree> s;
BiTree t=T;
while(!s.empty()||t!=NULL){
while(t!=NULL){
s.push(t);
visit(t);
t=t->lchild;
}
t=s.top();
s.pop();
t=t->rchild;
}
}
⭐中序遍历
递归:
void PreTraverse(BiTree &T){
if(T==NULL)
return;
PreTraverse(T->lchild);
visit(T);
PreTraverse(T->rchild);
}
非递归:
void Intraverse(BiTree &T){
stack<BiTree> s;
BiTree t=T;
while(t!=NULL||!s.empty()){
while(t!=NULL){
s.push(t);
t=t->lchild;
}
t=s.top();
visit(t);
s.pop();
t=t->rchild;
}
}
⭐后序遍历
递归:
void PreTraverse(BiTree &T){
if(T==NULL)
return;
PreTraverse(T->lchild);
PreTraverse(T->rchild);
visit(T);
}
非递归(主要思想是用前序遍历的思路先得到“根右左”,再将“根右左”逆序输出):
void Suctraverse(BiTree &T){
stack<BiTree> s,temp;
BiTree t=T;
while(t!=NULL||!s.empty()){//得到temp为根右左
while(t!=NULL){
s.push(t);
temp.push(t);
t=t->rchild;
}
t=s.top();
s.pop();
t=t->lchild;
}
//逆序输出temp
while(!temp.empty()){
visit(temp.top());
temp.pop();
}
}
⭐层次遍历
void Leveltraverse(BiTree &T){
if(T==NULL)return;
queue<BiTree> q;
BiTree t=T;
q.push(t);
while(!q.empty()){
BiTree top=q.front();
visit(top);
q.pop();
if(top->lchild)q.push(lchild);
if(top->rchild)q.push(rchild);
}
}
⭐前序/后序+中序还原二叉树
4.哈夫曼树
先易后难,先搁置一下。。。写不完了。。。
6.图
1.结构体定义
邻接矩阵
struct Graph{
int vexnumber;
string vexinfo[maxsize];
int adjmatrix[maxsize][maxsize];
};
邻接表
struct ArcNode{
int weigh;
int adj;
ArcNode* nextarc;
};
struct VexNode{
string info;
ArcNode* firstarc;
};
struct LinkGraph{
VexNode* vexes;
int vexnumber;
};
邻接矩阵转邻接表
void Create(LinkGraph &LG, Graph &G) {
//初始化LG的VexNode数组
LG.vexes = new VexNode[maxsize];
LG.vexnumber = G.vexnumber;
for (int i = 0; i < LG.vexnumber; i++)
LG.vexes[i].firstarc = NULL;
//填写邻接表
for (int i = 0; i < LG.vexnumber; i++) {
LG.vexes[i].info = G.vexinfo[i];
for (int j = 0; j < LG.vexnumber; j++) {
if (G.adjmatrix[i][j]) {//添加一条边,使用头插法,不含头结点
ArcNode *p = new ArcNode;
p->adj = j;
p->weigh = G.adjmatrix[i][j];
p->nextarc = NULL;
if (LG.vexes[i].firstarc == NULL)
LG.vexes[i].firstarc = p;
else {
p->nextarc = LG.vexes[i].firstarc;
LG.vexes[i].firstarc = p;
}
}
}
}
}
2.遍历
1.DFS
邻接矩阵递归:
void DFS(Graph &G,int v0,int visited[]){//以v0为起点做一趟DFS
visit(G.vexinfo[v0]);
visited[v0]++;
for(int i=0;i<G.vexnumber;i++){
if(G.adjmatrix[v0][i]&&!visited[i]){
DFS(G,i,visited);
}
}
}
void DFS(Graph &G){//对整个图做DFS
int visited[G.vexnumber];
memset(visited,0,sizeof(visited));
for(int i=0;i<G.vexnumber;i++){
if(!visited[i])
DFS(G,i,visited);
}
}
邻接矩阵非递归(参考二叉树遍历):
int findadj(Graph &G, int v0, int visited[]) {//返回v0的未被访问过的邻接点
for (int i = 0; i < G.vexnumber; i++) {
if (!visited[i] && G.adjmatrix[v0][i]) {
return i;
}
}
return -1;//没有未被访问的邻接点,返回-1
}
void DFS_non(Graph &G, int v0, int visited[]) {
int p = v0;
stack<int> s;
while (p >= 0 || !s.empty()) {
while (p >= 0) {
visited[p]++;
visit(G.vexinfo[p]);
s.push(p);
p = findadj(G, p, visited);
}
p = s.top();
s.pop();
p = findadj(G, p, visited);
}
}
void DFS_non(Graph &G) {
int visited[G.vexnumber];
memset(visited, 0, sizeof(visited));
for (int i = 0; i < G.vexnumber; i++) {
if (!visited[i])
DFS_non(G, i, visited);
}
}
邻接表递归:
void DFS2(LinkGraph &LG, int v0, int visited[]) {
visit(LG.vexes[v0].info);
visited[v0]++;
ArcNode *p = LG.vexes[v0].firstarc;
while (p != NULL) {
if (!visited[p->adj])
DFS2(LG, p->adj, visited);
p = p->nextarc;
}
}
void DFS2(LinkGraph &LG) {
int visited[LG.vexnumber];
memset(visited, 0, sizeof(visited));
for (int i = 0; i < LG.vexnumber; i++) {
if (!visited[i])
DFS2(LG, i, visited);
}
}
2.BFS
邻接矩阵:
void BFS(Graph &G, int v0, int visited[]) {
queue<int> q;
int p = v0;
q.push(p);
while (!q.empty()) {
p = q.front();
q.pop();
visit(G.vexinfo[p]);
visited[p]++;
int a = findadj(G, p, visited);
while (a != -1) {
q.push(a);
visited[a]++;
a = findadj(G, p, visited);
}
}
}
void BFS(Graph &G) {
int visited[G.vexnumber];
memset(visited, 0, sizeof(visited));
for (int i = 0; i < G.vexnumber; i++) {
if (!visited[i])
BFS(G, i, visited);
}
}
邻接表:
void BFSLG(LinkGraph &LG, int v0, int visited[]) {
int p = v0;
queue<int> q;
q.push(p);
while (!q.empty()) {
p = q.front();
q.pop();
visited[p]++;
visit(LG.vexes[p].info);
for (ArcNode *a = LG.vexes[p].firstarc; a; a = a->nextarc) {
if (!visited[a->adj]) {
visited[a->adj]++;
q.push(a->adj);
}
}
}
}
void BFSLG(LinkGraph &LG) {
int visited[LG.vexnumber];
memset(visited, 0, sizeof(visited));
for (int i = 0; i < LG.vexnumber; i++) {
if (!visited[i])
BFSLG(LG, i, visited);
}
}
3.强连通分量
步骤:先求完成序,再倒序选择起点进行反向DFS
完成序求解(将DFS中的visit换个位置):
void Finished_DFS(Graph &G, int v0, int visited[]) {
visited[v0]++;
for (int i = 0; i < G.vexnumber; i++) {
if (!visited[i] && G.adjmatrix[v0][i]) {
Finished_DFS(G, i, visited);
}
}
visit(G.vexinfo[v0]);
}
void Finished_DFS(Graph &G) {
int visited[G.vexnumber];
memset(visited, 0, sizeof(visited));
for (int i = 0; i < G.vexnumber; i++) {
if (!visited[i]) {
Finished_DFS(G, i, visited);
}
}
}
3.关键路径
1.拓扑排序
void findindegree(Graph &G, int indegree[]) {
for (int i = 0; i < G.vexnumber; i++) {
for (int j = 0; j < G.vexnumber; j++) {
if (G.adjmatrix[j][i])
indegree[i]++;
}
}
}
int TopoSort(Graph &G) {
int indegree[G.vexnumber];
memset(indegree, 0, sizeof(indegree));
findindegree(G, indegree);
stack<int> s;
//入度为0,入栈
for (int i = 0; i < G.vexnumber; i++) {
if (indegree[i] == 0)
s.push(i);
}
int count = 0; //对输出结点计数,判断成环
while (!s.empty()) {
int p = s.top();
s.pop();
visit(G.vexinfo[p]);
count++;
for (int i = 0; i < G.vexnumber; i++) {
if (G.adjmatrix[p][i]) {
indegree[i]--;
if (indegree[i] == 0)
s.push(i);
}
}
}
if (count < G.vexnumber)
return 0;
return 1;
}
2.结点最早发生时间
struct edge{
int forws;//前驱
int backws;//后继
int val;//权值
};
void EarliestNode(Graph &G) {
struct edge a[maxsize];
int ve[G.vexnumber];
memset(ve, 0, sizeof(ve));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) { //找前驱
if (a[j].backws == topo[i])
ve[topo[i]] = max(ve[topo[i]], ve[a[j].forws] + a[j].val);
}
}
for (int i = 0; i < m; i++)
cout << ve[i] << endl;
}
3.结点最晚发生时间
void LatestNode(Graph &G){
struct edge a[maxsize];
//求最早发生时间
int ve[G.vexnumber];
memset(ve, 0, sizeof(ve));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) { //找前驱
if (a[j].backws == topo[i])
ve[topo[i]] = max(ve[topo[i]], ve[a[j].forws] + a[j].val);
}
}
//求最晚发生时间
int vl[m+5];
for(int i=0;i<m;i++)vl[i]=ve[i];
for(int i=m;i>=0;i--){
int minn=INFINITY,flag=0;
for(int j=0;j<n;j++){//找后继
if(a[j].forws==topo[i]){
minn=min(minn,vl[a[j].backws]-a[j].val);
flag=1;
}
}
if(flag)
vl[topo[i]]=minn;
}
for(int i=0;i<m;i++)cout<<vl[i]<<endl;
}
4.边最早发生时间
void EarliestNode(Graph &G) {
struct edge a[maxsize];
int ve[G.vexnumber];
memset(ve, 0, sizeof(ve));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) { //找前驱
if (a[j].backws == topo[i])
ve[topo[i]] = max(ve[topo[i]], ve[a[j].forws] + a[j].val);
}
}
for (int i = 0; i < m; i++)
cout << ve[a[i].forws] << endl;
}
5.边最晚发生时间
void LatestEdge(Graph &G) {
struct edge a[maxsize];
//最早发生时间
memset(ve, 0, sizeof(ve));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) { //找前驱
if (a[j].backws == topo[i])
ve[topo[i]] = max(ve[topo[i]], ve[a[j].forws] + a[j].val);
}
}
//for(int i=0;i<m;i++)cout<<ve[i]<<endl;
//找vl
int vl[m + 5];
for (int i = 0; i < m; i++)
vl[i] = ve[i];
for (int i = m; i >= 0; i--) {
int minn = INFINITY, flag = 0;
for (int j = 0; j < n; j++) { //找后继
if (a[j].forws == topo[i]) {
minn = min(minn, vl[a[j].backws] - a[j].val);
flag = 1;
}
}
if (flag)
vl[topo[i]] = minn;
}
for (int i = 0; i < n; i++)
cout << vl[a[i].backws] - a[i].val << endl;
}
6.关键路径
int vl_ar[n+5],ve_ar[n+5];
for(int i=0;i<n;i++){
if(ve[a[i].forws]==vl[a[i].backws]-a[i].val)
printf("%d-->%d:%d\n",a[i].forws,a[i].backws,ve[a[i].forws]);
}
4.最短路径、最小生成树
1.prime算法最小生成树
int main() {
Graph G;
Input(G);
int n = G.vexnumber;
int totalcost = 0, cost[n], adj[n];
cost[0] = -1;
adj[0] = 0;
for (int i = 1; i < n; i++) { //初始化
cost[i] = G.adjmatrix[0][i];
adj[i] = 0;
}
for (int i = 1; i < n; i++) {
int minicost = INFINITY, k = 0;
for (int j = 1; j < n; j++) { //找cost最小值
if (cost[j] > 0 && cost[j] < minicost) {
minicost = cost[j];
k = j;
}
}
totalcost += minicost; //最小值边加入
cost[k] = -1; //-1表示已选
for (int j = 1; j < n; j++) { //更新cost、adj数组
if (cost[j] > 0 && G.adjmatrix[k][j] && G.adjmatrix[k][j] < cost[j]) { ///原数组中有比当前边更大的值,替换
cost[j] = G.adjmatrix[k][j];
adj[j] = k;
} else if (cost[j] == 0 && G.adjmatrix[k][j]) { //原数组中没有则新加
cost[j] = G.adjmatrix[k][j];
adj[j] = k;
}
}
}
cout << totalcost;
return 0;
}
2.迪杰斯特拉最短路径
int main() {
Graph G;
Input(G);
int b, n = G.vexnumber;
cin >> b;
struct node a[n];
for (int i = 0; i < n; i++) { //初始化
a[i].path = b;
a[i].shortest = G.adjmatrix[b][i];
}
a[b].shortest = -1;
int answer[n];
memset(answer, 0, sizeof(answer));
for (int i = 0; i < n - 1 ; i++) {
int minn = INFINITY, indexmin = -1;
for (int j = 0; j < n; j++) { //寻找最小值
if (a[j].shortest > 0 && minn > a[j].shortest) {
minn = a[j].shortest;
indexmin = j;
}
}
answer[indexmin] = minn; //最小值进入answer
a[indexmin].shortest = -1;//-1为已遍历的结点
//更新a
for (int j = 0; j < n; j++) {
if (G.adjmatrix[indexmin][j]) {
if (a[j].shortest == 0 ||
a[j].shortest > 0 && minn + G.adjmatrix[indexmin][j] < a[j].shortest) {
a[j].shortest = minn + G.adjmatrix[indexmin][j];
a[j].path = indexmin;
}
}
}
}
for (int i = 0; i < n; i++) {
if (i != b) {
cout << answer[i] << " ";
}
}
return 0;
}
2.弗洛伊德最短路径
struct node a[n][n];
for(int i=0;i<n;i++){//初始化
for(int j=0;j<n;j++){
a[i][j].hub=i;
a[i][j].val=martrix[i][j];
}
}
for(int k=0;k<n;k++){//弗洛伊德算法求a矩阵,从i到j以k为中转点
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(i!=k&&j!=k&&i!=j&&a[i][k].val&&a[k][j].val){
if(a[i][j].val==0||
a[i][j].val!=0&&a[i][j].val>a[i][k].val+a[k][j].val){
a[i][j].val=a[i][k].val+a[k][j].val;
a[i][j].hub=k;
}
}
}
}
}
7.集合与查找
1.二叉搜索树
计算树高
int high(AVLTree &T){
if(T==NULL)return 0;
return max(high(T->lchild),high(T->rchild))+1;
}
旋转
AVLTree LRotate(AVLTree &A){//RR型,左旋
AVLTree B=A->rchild;
A->rchild=B->lchild;
B->lchild=A;
return B;
}
AVLTree RRotate(AVLTree &A){//LL型,右旋
AVLTree B=A->lchild;
A->lchild=B->rchild;
B->rchild=A;
return B;
}
AVLTree LR(AVTree &A){//LR型,左右旋
A=LRotate(A->lchild);
return RRotate(A);
}
AVLTree RL(AVLTree &A){//RL型,右左旋
A=RRotate(A->rchild);
return LRotate(A);
}
插入节点
AVLTree insert(AVLTree T,int x){
if(T==NULL){
T=new node;
T->lchild=T->rchild=NULL;
T->data=x;
return T;
}else if(x>T->data){
insert(T->rchild,x);
if(high(T->rchild)-high(T->lchild)>=2){
if(x>T->rchild->data)LRotate(T);//RR型左旋
else RL(T);//RL型,右左旋
}
}else{
insert(T->lchild,x);
if(high(T->lchild)-high(T->rchild)>=2){
if(x<T->lchild->data)RRotate(T);//LL型,右旋
else LR(T);//LR型,左右旋
}
}
}
2.写不完了,自己看吧
8.排序
1.简单排序法
1.选择排序
从未排序部分中选择最小元素,添加到已排序部分的末尾
void sort(int n,int *num){//选择排序
for(int i=0;i<n;i++){
int min=num[i],index=i;
for(int j=i+1;j<n;j++){//找未排序序列中的最小值
if(num[j]<min){
min=num[j];
index=j;
}
}
num[index]=num[i];
num[i]=min;
}
}
2.交换排序
反复比较两两相邻元素,若不符合顺序要求,则交换相邻元素,直至有序
void sort(int n,int num*){//冒泡排序(交换排序)
for(int i=0;i<n-1;i++){
for(int j=0;j<n-i-1;j++){
if(num[j]>num[j+1]){//交换值
int temp=num[j];
num[j]=num[j+1];
num[j+1]=temp;
}
}
}
}
3.插入排序
任取未排序序列中的一个元素,插入到已排序序列中
void sort(int n, int num *) { //插入排序
for (int i = 1; i < n; i++) {
int temp = num[i], flag = 0;
for (int j = i - 1; j >= 0; j--) {
if (num[j] > temp) {//若大于temp则后移
num[j + 1] = num[j];
} else {//小于等于则插入
num[j + 1] = temp;
flag = 1;
break;
}
}
if (flag == 0)//若没有插入,说明插入的位置为第一个
num[0] = temp;
}
}
2.先进排序法
1.希尔排序(不会写)
2.快速排序
int Partition(int L[], int s, int t) {
int temp = L[s];
int low = s, high = t;
while (low < high) {
while (low < high && L[high] >= temp)
high--;
L[low] = L[high];
while (low < high && L[low] <= temp)
low++;
L[high] = L[low];
}
L[low] = temp;
return low;
}
int QSort(int L[], int s, int t) {
if (s >= t)
return 0;
int k = Partition(L, s, t);
QSort(L, s, k - 1);
QSort(L, k + 1, t);
return 0;
}
int QuickSort(int L[], int n) {
return QSort(L, 0, n - 1);
}
3.堆排序(不会写)
4.归并排序
int Merge(int C[], int A[], int nA, int B[], int nB) {
int iA = 0, iB = 0, iC = 0;
while (iA < nA && iB < nB) {
if (A[iA] < B[iB]) {
C[iC] = A[iA];
iA++;
} else {
C[iC] = B[iB];
iB++;
}
iC++;
}
while (iA < nA) {
C[iC] = A[iA];
iA++;
iC++;
}
while (iB < nB) {
C[iC] = B[iB];
iB++;
iC++;
}
return 0;
}
如有错误,敬请指出。祝大家都取得满意的成绩🎇