数据结构复习

目录

1.线性表

1.结构体定义

2.基本操作

3.一般操作

 ⭐有序单链表的有序合并(2023年数据结构补题-L)

有序单链表删除重复结点(2023年数据结构补题-U)

⭐单链表反转(2023年数据结构补题-X)

两个有序链表序列的交集(2023年数据结构补题-AB)

2.栈和队列

1.栈

⭐括号匹配问题(2023年数据结构补题-AI):

八进制数(2023年数据结构补题-AG):

行编辑程序(2023年数据结构补题-AH) 

2.递归

n阶汉诺塔问题(2023年数据结构补题-AO):

3.队列

约瑟夫问题(2023年数据结构补题-AD):

3.字符串模式匹配

1.朴素算法

字符串匹配(朴素算法)-附加代码模式(2023年数据结构补题-AX)

2.KMP算法 

KMP算法中的模式串移动数组(2023年数据结构补题-AU)

改进的nextVal向量(2023年数据结构补题-AT)

 ⭐字符串匹配KMP算法(没有题,可以试着交到朴素算法验证)

4.数组和广义表

1.稀疏矩阵

1.三元组、稀疏矩阵定义

2.基本操作

⭐计算行向量 (每行第一个非零元素下标):

⭐稀疏矩阵乘法(2023年数据结构补题二-D):

⭐稀疏矩阵转置:

2.数组(多维数组下标换算)

5.二叉树 

1.性质

2.结构体定义

3.基本操作

⭐前序遍历

⭐中序遍历

⭐后序遍历

⭐层次遍历

4.哈夫曼树 

6.图

1.结构体定义

2.遍历

1.DFS

2.BFS

3.强连通分量

3.关键路径

4.最短路径、最小生成树

7.集合与查找

1.二叉搜索树

8.排序

1.简单排序法

1.选择排序

2.交换排序

3.插入排序

2.先进排序法

1.希尔排序(不会写)

2.快速排序

3.堆排序(不会写)

4.归并排序


后面写得有点潦草了,大家随便看看吧🥹🥹🥹


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.数组(多维数组下标换算)

⭐公式:A[i_{1}][i_{2}][i_{3}][i_{4}]=a[i_{1}*(n_{2}*n_{3}*n_{4})+i_{2}*(n_{3}*n_{4})+i_{3}*(n_{4})+i_{4}] 

定义数组:

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.性质

⭐设n_{0}n_{1}n_{2}分别为度为0,1,2的结点,则n_{2}=n_{0}-1

  • i层最多有2^{i}个结点
  • 深度为h的树,最少有h个结点,最多有2^{h}-1个结点
  • 结点数为n,深度最大为n,最小为log_{2}(n+1)

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;
}

如有错误,敬请指出。祝大家都取得满意的成绩🎇

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Solen.&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值