算法是对特定问题求解步骤的一种描述方式,是若干指令的有穷序列。(有限的时间或者空间内算出确定的结果)
n逐渐增大的时候,时间复杂度是怎么增加的?
#include "stdio.h"
int f(int n) {
if (n == 0)
return 1;
else
return n * f(n - 1);
}
int main() {
int n;
printf("请输入n的值:");
scanf_s("%d", &n);
int r = f(n);
printf("%d的阶乘是:%d",n,r);
return 0;
}
二叉树遍历的时候,内存使用了栈,要了解进栈出栈的过程。
#include "stdio.h"
#include "stdlib.h"
// 二叉树的存储结构
typedef struct BiTNode {
char data;
struct BiTNode* lchild, * rchild;
}BiTNode, *BiTree;
// 构建一棵二叉树
void CreateBiTree(BiTree* T) {
char ch;
scanf_s("%c", &ch);
if (ch == '#')
*T = NULL;
else {
*T = (BiTree)malloc(sizeof(BiTNode)); // 动态分配内存空间
(*T)->data = ch; // 生成结点
CreateBiTree(&(*T)->lchild); // 构造左子树
CreateBiTree(&(*T)->rchild); // 构造右子树
}
}
void visit(BiTree T) {
printf("%c ", T->data);
}
// 先序遍历
void PreOrder(BiTree T) {
if (T != NULL) {
visit(T);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
// 中序遍历
void InOrder(BiTree T) {
if (T != NULL) {
InOrder(T->lchild);
visit(T);
InOrder(T->rchild);
}
}
// 后序遍历
void PostOrder(BiTree T) {
if (T != NULL) {
PostOrder(T->lchild);
PostOrder(T->rchild);
visit(T);
}
}
int Count(BiTree T){
if (T != NULL)
return Count(T->lchild) + Count(T->rchild) + 1;
else
return 0; //空二叉树为0结点
}
int main() {
BiTree T = NULL; // 构建一棵树 12#46###3#5##
printf("请以先序遍历方式输入:");
CreateBiTree(&T);
printf("递归前序遍历结果:");
PreOrder(T);
printf("递归中序遍历结果:");
InOrder(T);
printf("递归后序遍历结果:");
PostOrder(T);
printf("二叉树结点总数为:%d", Count(T));
}
每次从剩下未安排会议中选出最早结束且与已安排会议不冲突的会议【选最早结束时间】
#include "stdio.h"
#define n 10
struct TypeElem {
//定义开始结束时间
int Begin, End;
};
TypeElem A[n] = {
{3,6},{1,4},{5,7},{2,5},{5,9},{3,8},{8,11},{6,10},{8,12},{12,14}
};
/*
冒泡排序:
从前往后依次比较两个元素的大小,左比右大则交换,否则不动
第一趟排出最小的在第一位,然后再冒泡排序
如果值相同则不用换位置
*/
void Sort(TypeElem A[], int k) {
for (int i = 0; i < k; i++) {
for (int j = 0; j < k-i-1; j++) {
if (A[j].End > A[j+1].End) {
TypeElem typeelem;
typeelem = A[j];
A[j] = A[j+1];
A[j+1] = typeelem;
}
}
}
};
int main() {
//冒泡排序-会议最早结束时间的升序
Sort(A,n);
//排序后的结果展示
for (int i = 0; i < n; i++) {
printf("%d,%d",A[i].Begin,A[i].End);
printf("\n");
}
printf("----------\n");
//定义开始的时间
int T = 0;
//存储最终的会议
TypeElem Meet[n];
int m = 0;
for (int j = 0; j < n; j++) {
if (A[j].Begin >= T) {
//安排此会议
Meet[m] = A[j];
T = A[j].End;
m++;
}
}
//安排会议后的结果展示
for (int k = 0; k < m; k++) {
printf("%d,%d", Meet[k].Begin, Meet[k].End);
printf("\n");
}
return 0;
}
8棵结点树:5,29,7,8,14,23,3,11
#include "stdio.h"
#define Maxnode 8
// 哈夫曼树的结点结构
struct HtNode{
int weight; // 权值
int parent, lchild, rchild; // parent:该结点的双亲结点在数组中的下标;lchild:左孩子在数组中的下标;rchild:右孩子在数组中的下标
};
// 哈夫曼树的存储结构
struct HtNode ht[2 * Maxnode - 1];
void Huffman(int n, int w[Maxnode]) {
int i, j, p1, p2; //p1,p2用来记录权值最小的两棵树在数组中的位置
int min1, min2; //min1,min2用来记录两个最小的权值
if (n <= 1)
return;
// 初始化ht数组:前n个赋的值是叶子结点的值,从n+1开始到2n-1个是还未使用的结点赋值-1
for (i = 0; i < 2 * n - 1; i++) {
ht[i].parent = 0;
if (i < n)
ht[i].weight = w[i];
else
ht[i].weight = -1;
}
// 执行n-1次合并操作,即构造哈夫曼树的n-1个内部结点
for (i = 0; i < n - 1; i++) {
p1 = p2 = 0;
min1 = min2 = 10000;
// 从ht中选择权值最小的两个结点
for (int j = 0; j < n + i; j++) {
// 当此结点的父节点为0时表示未被选过
if (ht[j].parent == 0) {
// 查找权值最小的结点,用p1记录下标
if (ht[j].weight < min1) {
min2 = min1; // 把min1赋值给min2
min1 = ht[j].weight; // 用min1记录这个权值
p2 = p1;
p1 = j; // p1为最小权值结点的下标
} else if(ht[j].weight < min2){
min2 = ht[j].weight;
p2 = j; // p2为次小权值结点的下标
}
}
}
// 将ht[p1]和ht[p2]进行合并,其双亲是i
ht[p1].parent = n + i;
ht[p2].parent = n + i;
ht[n + i].weight = min1 + min2;
ht[n + i].lchild = p1;
ht[n + i].rchild = p2;
}
}
int main() {
int w[Maxnode] = { 5,29,7,8,14,23,3,11 };
Huffman(Maxnode, w);
for (int i = 0; i < (2 * Maxnode - 1); i++) {
printf("权值为:%d,左孩子为:%d,右孩子为:%d,父节点为:%d",ht[i].weight,ht[i].lchild,ht[i].rchild,ht[i].parent);
printf("\n");
}
return 0;
}
依据约定:左分支为0,右分支为1,获得哈夫曼编码即可。【左右子树为0或1根据题目而定,不唯一】
struct edge{ double weight; int u,v; bool K; }; // 边。weight:权重; K为真:在生成树上
void Prim( edge Topology[ ], int m, int n){
// Topology:原图的m条边,已按权重升序排好序;顶点编号从0开始,n个;
int Point[n], num=0, i, j;
for( Point[0]=0, num=1, m1=0; num<n; num++ ){
for( i=0; i<m; i++ ){
if( !Topology[i].K ){
bool U,V; U=V= false;
for( int j=0; j<num; j++ ){
if(Topology[i].u==Point[j]) U=true;
if(Topology[i].v==Point[j]) V=true;
}
if( U && !V ) Point[num] = Topology[i].v;
if( !U && V ) Point[num] = Topology[i].u;
if( (U&&!V) || (!U&&V) ){
Topology[i].K=true;
break;
}
}
}
}
}
struct edge{ double weight; int u,v; bool K; }; // 边。weight:权重; K为真:在生成树上
struct TypeTree { int *A; int len; };
void Merg(TypeTree &P, TypeTree &Q ){// 合并P,Q两棵树到P
int *M; M = new int[ P.len+Q.len ];
for( int i=0; i<P.len; i++) M[i] = P.A[i];
for( int i=0; i<Q.len; i++) M[i+P.len] = Q.A[i];
delete [ ]Q.A; Q.A=NULL; Q.len=0;
delete [ ]P.A; P.A=M; P.len+=Q.len
}
void Kruskal( edge Topology[ ], int m, int n){
// Topology:原图的m条边,已按权重升序排好序;顶点编号从0开始,n个;
TypeTree Tree[n]; int t, e, q;
for( int i=0; i<n; i++ ){ Tree[i].A = new int[1]; Tree.len=1; Tree.A[0]=i; }
for( int nTree = n; nTree>1; nTree-- ){
for( e=0; e<m; e++ ){
if( Topology[ e ].K ) continue;
int T1= -1, T2= -1;
for( t=0; t<n; t++ ){
for( q=0; q<Tree[t].len; q++){
if(Topology[ e ].u==Tree[ t ].A[ q ] ) T1 = t;
if(Topology[ e ].v==Tree[ t ].A[ q ] ) T2 = t;
}
}
if( T1 != T2 ){
Topology[ e ].K = true;
Merg(Tree[T1], Tree[T2]);
break;
}
}
}
}
#include "stdio.h"
#define length 8
int QuickPass(int A[], int L, int R) {
int T = A[L]; // 基准元素为第一个元素
while (L < R) {
// 从最后一个元素开始比较
while (L < R && A[R] >= T) R--; // 循环比较,比基准元素大,则保持不动,指针左移
A[L] = A[R];
while (L < R && A[L] <= T) L++;
A[R] = A[L];
}
// 最后两个指针重合,则将基准元素给这个空位
A[L] = T;
return L;
}
void QuickSort(int A[], int L, int R) {
if (L >= R) return;
int M = QuickPass(A, L, R);
QuickSort(A, L, M-1);
QuickSort(A, M+1, R);
}
int main() {
int A[length] = {49,38,65,97,76,13,27,49};
QuickSort(A, 0, length-1);
//遍历输出结果
for (int i = 0; i < length; i++) {
printf("%d ", A[i]);
}
return 0;
}
#include "stdio.h"
#include "string"
using namespace std;
struct TypeData {
string Name;
int Age;
// 构造函数
TypeData(string Name, int Age) :Name(Name), Age(Age) {}
TypeData():Age(0){}
};
const int Size = 10;
// 定义线性表
struct TypeList {
// 数组
TypeData Array[Size];
// 有效元素个数
int n;
};
int Binary_Search(TypeList List, string Key) {
// low是首位置,high是末位置,middle是中间位置
int low = 0, high = List.n - 1, middle;
while (low < high) {
middle = (low + high) / 2;
/*
* if语句的条件里,
1. if(Key <= List.Array[middle].Name) high = middle;
else low = middle+1;
2. if(Key < List.Array[middle].Name) high = middle;
else low = middle
3. if(Key >= List.Array[middle].Name) low = middle;
else high = middle;
4. if(Key > List.Array[middle].Name) low = middle+1;
else high = middle;
*/
if (Key >= List.Array[middle].Name) {
low = middle;
} else {
high = middle;
}
if (Key == List.Array[low].Name) {
return low;
}
}
return -1;
}
int main() {
TypeList List;
List.Array[0] = TypeData("A1",111);
List.Array[1] = TypeData("B1",123);
List.Array[2] = TypeData("C1",456);
List.Array[3] = TypeData("D1",789);
List.Array[4] = TypeData("E1",110);
List.n = 5;
string K = "B1";
int result = Binary_Search(List, K);
if (result == -1)
printf("未找到!");
else
printf("找到!");
return 0;
}
#include "stdio.h"
#include "stdlib.h"
#define MAX_VERTEX_NUM 30
// 一维数组:记录顶点是否被访问
bool visited[MAX_VERTEX_NUM];
typedef struct AMGraph {
int vexs[MAX_VERTEX_NUM]; // 顶点表
int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 邻接矩阵
int vexnum, arcnum; // 当前的顶点数和边数
}AmGraph;
// 找到顶点v的对应下标
int LocationVex(AMGraph& G, int v) {
for (int i = 0; i < G.vexnum; i++)
if (G.vexs[i] == v)
return i;
}
// 用邻接矩阵表示法,创建无向图G
int CreateG(AMGraph& G) {
int i, j, k;
G.vexnum = 8; // 总顶点数为8
G.arcnum = 10; // 总边数为10
for (i = 0; i < G.vexnum; i++)
G.vexs[i] = i + 1; // 顶点的信息
for (i = 0; i < G.vexnum; i++) {
for (j = 0; j < G.vexnum; j++)
G.arcs[i][j] = 0; // 初始化邻接矩阵的边,0表示顶点i和j之间无边
}
int A[10][2] = { {1,2},{1,5},{2,6},{3,6},{3,7},{3,4},{4,7},{4,8},{6,7},{7,8} };
for (k = 0; k < G.arcnum; k++) {
i = LocationVex(G, A[k][0]);
j = LocationVex(G, A[k][1]);
G.arcs[i][j] = G.arcs[j][i] = 1; // 1表示顶点i和j之间有边,无向图不区分方向,对称矩阵
}
return 1;
}
void DFSV0(AMGraph& G, int v) {
printf("%d ", G.vexs[v]);
visited[v] = true; // 访问过之后置true
for (int i = 0; i < G.vexnum; i++)
if (G.arcs[v][i] && !visited[i]) //递归调用
DFSV0(G, i);
}
void DFS(AMGraph G) {
for (int i = 0; i < MAX_VERTEX_NUM; i++)
visited[i] = false; // 初始化顶点数组,false表示未访问
for (int i = 1; i <= G.vexnum; i++) { // 从0号顶点开始遍历
if (!visited[i])
DFSV0(G, i);
}
}
int main() {
AMGraph G;
int c = CreateG(G); // 创建无向图
if (c)
DFS(G);
else
printf("创建无向图失败!");
return 0;
}
【注】
- 进过队列的不能再进队列,当一个顶点进队列的时候打标记;
- 循环开始的条件:把第一个顶点打好标记然后加到队列里;
- 循环结束的条件:队列空的时候结束,一幅图的一个连通子图搜索完毕。
#include "stdio.h"
#include "queue"
#define MAX_VERTEX_NUM 8 // 最大顶点数
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
queue<int> q; // 定义一个队列,使用库函数queue
bool visited[MAX_VERTEX_NUM]; // 定义一个数组,记录已被访问的顶点
typedef struct AMGraph {
int vexs[MAX_VERTEX_NUM]; // 顶点表
int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 邻接矩阵
int vexnum, arcnum; // 当前的顶点数和边数
}AmGraph;
// 找到顶点v的对应下标
int LocationVex(AMGraph& G, int v){
int i;
for (i = 0; i < G.vexnum; i++)
if (G.vexs[i] == v)
return i;
}
// 用邻接矩阵表示法,创建无向图G
int CreatG(AMGraph& G) {
int i, j, k;
G.vexnum = 8; // 总顶点数为8
G.arcnum = 10; // 总边数为10
for (i = 0; i < G.vexnum; i++)
G.vexs[i] = i + 1; // 顶点的信息
for (i = 0; i < G.vexnum; i++) {
for (j = 0; j < G.vexnum; j++)
G.arcs[i][j] = 0; // 初始化邻接矩阵的边,0表示顶点i和j之间无边
}
int A[10][2] = { {1,2},{1,5},{2,6},{3,6},{3,7},{3,4},{4,7},{4,8},{6,7},{7,8} };
for (k = 0; k < G.arcnum; k++) {
i = LocationVex(G, A[k][0]);
j = LocationVex(G, A[k][1]);
G.arcs[i][j] = G.arcs[j][i] = 1; // 1表示顶点i和j之间有边,无向图不区分方向,对称矩阵
}
return 1;
}
// 宽度优先遍历(从v0开始遍历)
void BFSV0(AMGraph& G, int v0){
int i, v, head, w;
v = LocationVex(G, v0);
visited[v] = true; // true表示顶点v已被访问
q.push(v0); //顶点v0入队列
printf("%d",v0);
while (!q.empty()) {
head = q.front(); // 取队头元素head
v = LocationVex(G, head); // 得到顶点head的下标
q.pop(); // 顶点head出队
for (i = 0; i < G.vexnum; i++) {
w = G.vexs[i]; // 遍历记录每个顶点,看和w之间有没有边
if (G.arcs[v][i] && !visited[i]) { // 如果顶点head和w之间有边,并且顶点未访问
visited[i] = true; // 将w的位置标记为true
q.push(w); // 将w入队
printf("%d", w);
}
}
}
}
void BFS(AMGraph G) {
for (int i = 0; i < MAX_VERTEX_NUM; i++)
visited[i] = false; // 初始化顶点数组,false表示未访问
for (int i = 1; i <= G.vexnum; i++) { // 从0号顶点开始遍历
if (!visited[i])
BFSV0(G, i);
}
}
int main() {
AMGraph G;
int c = CreatG(G); // 创建无向图
if (c)
BFS(G);
else
printf("创建无向图失败!");
return 0;
}
将n个物品【分别价值为v0,v1…】装入容量为W的背包中,问怎样才能实现装入的价值最大。
#include "stdio.h"
#define n 5
struct TypeE {
int W; // 物品重量
int V; // 物品价值
};
TypeE A[n] = { {2,3}, {3,4}, {4,5}, {5,6}, {1,1} };
int BagW = 8;
TypeE R = { 0, 0 };
int V0 = 0;
// 返回方案S的总重量,引用V里是总价值
int WV(unsigned long S, int& V) {
int W = 0;
V = 0;
unsigned long K = 0x01; // K为逻辑尺
for (int i = 0; i < n; i++) {
if (K & S) {
W += A[i].W;
V += A[i].V;
}
K = K << 1;
}
return W;
}
int main() {
int Result;
for (int i = 0; i < 31; i++) {
int V = 0; // 初始化每次循环物品的价值为0
if (i != 0) {
int res_w = WV(i, V);
if (res_w <= BagW && R.V >= V0) {
R.W = res_w;
R.V = V;
V0 = R.V;
Result = i;
}
}
}
for (int i = 0; i < n; i++) {
if (Result & (1 << i))
printf("挑选第%d个物品,即[%d,%d] \n", i+1, A[i].W, A[i].V);
}
printf("总重量是:%d, 总价格为%d", R.W, R.V);
return 0;
}
#include "stdio.h"
#include "queue"
using namespace std;
struct Position {
int row, col;
};
int grid[11][9]; // 表盘数组
void showPath(){
printf("----------------------输出列阵开始----------------------\n");
for (int i = 0; i < 11; i++){
for (int j = 0; j < 9; j++)
printf("%d\t",grid[i][j]);
printf("\n");
}
printf("----------------------输出列阵结束----------------------\n");
}
void initGrid() {
// 1. 上下左右边框均设置为-2
for (int i = 0; i < 9; i++)
grid[0][i] = grid[10][i] = -2;
for (int i = 1; i < 10; i++)
grid[i][0] = grid[i][8] = -2;
// 2. 除边框外其他部分赋值为-1
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 7; j++) {
grid[i][j] = -1;
}
}
// 3. 障碍点设置为-2
grid[1][5] = grid[9][3] = grid[9][5] = -2;
for (int i = 2; i <= 4; i++) grid[i][3] = -2;
for (int i = 5; i <= 6; i++) grid[3][i] = -2;
for (int i = 5; i <= 7; i++) grid[i][6] = -2;
for (int i = 4; i <= 5; i++) grid[6][i] = -2;
}
bool findPath(Position start, Position finish, int &PathLen, Position* &path) {
// 判断起点和终点是否重合
if (start.col == finish.col && start.row == finish.row) {
PathLen = 0;
return true;
}
Position offset[4]; // 定义四个方向
offset[0].row = 0; offset[0].col = 1; //右
offset[1].row = 1; offset[1].col = 0; //下
offset[2].row = 0; offset[2].col = -1; //左
offset[3].row = -1; offset[3].col = 0; //上
Position here, nbr; // 当前结点、相邻结点
here.row = start.row; // 起初的当前结点为起点
here.col = start.col;
grid[here.row][here.col] = 0; // 当前结点值为0
queue<Position> Q; // 定义一个队列
do {
for (int i = 0; i < 4; i++) {
nbr.row = here.row + offset[i].row;
nbr.col = here.col + offset[i].col;
if (grid[nbr.row][nbr.col] == -1) // 该方格未标记
grid[nbr.row][nbr.col] = grid[here.row][here.col] + 1;
if (nbr.row == finish.row && nbr.col == finish.col) // 找到
break;
if (grid[nbr.row][nbr.col] == -2)
continue;
Q.push(nbr);
}
if (nbr.row == finish.row && nbr.col == finish.col)
break; // 布线成功,跳出外层循环
if (Q.empty())
return false; // 无解
here = Q.front();
Q.pop(); // 取下一个扩展结点
} while (true);
// 逆向构造最短路线
PathLen = grid[finish.row][finish.col];
path = new Position[PathLen];
here = finish;
for (int j = PathLen - 1; j >= 0; j--) {
path[j] = here;
// 寻找前驱
for (int k = 0; k < 4; k++) {
nbr.row = here.row + offset[k].row;
nbr.col = here.col + offset[k].col;
if (grid[nbr.row][nbr.col] == j)
break;
}
here = nbr; // 向前移动
}
return true;
}
int main() {
Position start; // 定义起点
start.col = 2;
start.row = 3;
Position finish; // 定义终点
finish.col = 7;
finish.row = 6;
initGrid(); // 初始化表盘
showPath();
int PathLen = 0;
Position* path;
bool flag = findPath(start, finish, PathLen, path); // 开始寻找最短布线路径,找到返回true,未找到返回false
if(flag){
showPath();
printf("最短路径经过:\n");
for (int i = 0; i <= PathLen; i++)
printf("第%2d个单元格的坐标为:第%d行, 第%d列\n", i + 1, path[i].row, path[i].col);
}else
printf("布线失败");
return 0;
}
#include "stdio.h"
#include "time.h"
#include
#define m 65536L
#define b 1194211693L
#define c 12345L
using namespace std;
class RandomNumber{
public:
RandomNumber(unsigned long s = 0); // 默认值0表示由系统自动产生种子
unsigned short random(unsigned long n); // 产生0:n-1之间的随机整数
double fRandom(void); // 产生[0,1)之间的随机实数
private:
unsigned long d; // d为当前种子
};
// RandomNumber用来生产种子
RandomNumber::RandomNumber(unsigned long s){
if (s == 0)
d = time(0); // 由系统时间产生种子
else
d = s;
}
// random用来产生0:n-1之间的随机整数
unsigned short RandomNumber::random(unsigned long n) {
d = b * d + c; //用线性同余式计算新的种子d
return (unsigned short)((d >> 16 % n)); // 把d的高16位映射到0~(n-1)的范围内
}
// fRandom用来产生[0,1)之间的随机实数
double RandomNumber::fRandom(void) {
return random(m) / double(m);
}
// 用随机投点法计算 PI
double Darts(int n){
static RandomNumber darts;
int k = 0;
for (int i = 1; i <= n; i++) {
double x = darts.fRandom(); // 产生一个[0,1)之间的实数
double y = darts.fRandom();
if ((x * x + y * y) <= 1) {
k++;
}
}
return (4 * k) / (double)n;
};
int main(){
cout << Darts(200000000) << endl;
return 0;
};
#include "stdio.h"
#include "time.h"
#include
#define m 65536L
#define b 1194211693L
#define c 12345L
using namespace std;
class RandomNumber {
public:
RandomNumber(unsigned long s = 0); // 默认值0表示由系统自动产生种子
unsigned short random(unsigned long n); // 产生0:n-1之间的随机整数
double fRandom(void); // 产生[0,1)之间的随机实数
private:
unsigned long d; // d为当前种子
};
// RandomNumber用来生产种子
RandomNumber::RandomNumber(unsigned long s) {
if (s == 0)
d = time(0); // 由系统时间产生种子
else
d = s;
}
// random用来产生0:n-1之间的随机整数
unsigned short RandomNumber::random(unsigned long n) {
d = b * d + c; //用线性同余式计算新的种子d
return (unsigned short)((d >> 16 % n)); // 把d的高16位映射到0~(n-1)的范围内
}
// fRandom用来产生[0,1)之间的随机实数
double RandomNumber::fRandom(void) {
return random(m) / double(m);
}
// 用随机投点法计算 PI
double Darts(int n) {
static RandomNumber darts;
int k = 0;
for (int i = 1; i <= n; i++) {
double x = darts.fRandom(); // 产生一个[0,1)之间的实数
double y = darts.fRandom();
if ((x * x + y * y) <= 1) {
k++;
}
}
return k / (double)n;
};
int main() {
cout << Darts(200000000) << endl;
return 0;
};
近似解:用广度优先算法,用分支界限法
注意:本博客仅提供算法参考,有问题的地方欢迎指正。