小白自学,漏洞百出实属身不由己,有任何改进建议或错误,欢迎列位批评与斧正
一:分治与递归
1.汉诺塔:
#include <stdio.h>
void h(int n, char A, char B, char C) {
if (n == 1) {
printf("%c->%c\n", A, C);
return;
}
h(n - 1, A, C, B);
printf("%c->%c\n", A, C);
h(n - 1, B, A, C);
}
int main() {
char A = 'A';
char B = 'B';
char C = 'C';
h(3, A, B, C);
return 0;
}
2.n个数的全排列:
#include <stdio.h>
void swap(int *a,int *b){
int temp = *a;
*a = *b;
*b = temp;
}
void perm(int s[],int start,int end){
if (start == end){
for(int i = 0;i <= end;i++){
printf("%d",s[i]);
}
printf("\n");
}
else{
for(int i = start;i <= end;i++){
swap(&s[start],&s[i]);
perm(s,start + 1,end);
swap(&s[start],&s[i]);
}
}
}
int main(){
int n;
scanf("%d",&n);
int s[n];
for(int i = 0;i < n;i++){
s[i] = i + 1;
}
perm(s,0,n-1);
return 0;
}
3.二分搜索法:
#include <stdio.h>
void search(int s[],int start,int end,int n){
if(start > end){
printf("找不到该数字!");
return;
}
int middle = (start + end) / 2;
if(n == s[middle]){
printf("该数在数组中的位置为%d",middle);
}
else if(n > s[middle]){
search(s,middle + 1,end,n);
}
else{
search(s,start,middle - 1,n);
}
}
int main(){
int x,n;
printf("请输入数组大小:");
scanf("%d",&x);
int s[x];
for(int i = 0;i<x;i++){
scanf("%d",&s[i]);
}
printf("请输入想寻找的数:");
scanf("%d",&n);
search(s,0,x - 1,n);
}
4.合并排序:
(算法关键:将待排序的数组分成两个子数组,分别排序,然后将排好序的子数组合并起来:
1.分解:将待排序的数组分解成两个子数组,直到子数组的长度为1,即无法再分解为止。
2.排序:递归地对每个子数组进行排序。
3.合并:将排好序的子数组合并成一个大的有序数组。
合并排序的关键在于合并过程,它要求合并的两个子数组已经有序,然后通过比较两个子数组的第一个元素,选择较小的元素放入新的数组中,然后将指针向后移动,直到其中一个子数组的所有元素都已经合并完毕)
#include <stdio.h>
void M(int s1[],int s2[],int left,int right){
int middle = (left + right) / 2;
int a = left;
int b = middle + 1;
int k = 0;
while(a <= middle && b <= right){
if(s1[a] < s1[b]){
s2[k] = s1[a];
a++;
}
else if(s1[a] > s1[b]){
s2[k] = s1[b];
b++;
}
else{
s2[k] = s1[a];
a++;
b++;
}
k++;
}
while(a <= middle){
s2[k] = s1[a];
k++;
a++;
}
while(b <= right){
s2[k] = s1[b];
k++;
b++;
}
for(int i = 0;i <= right;i++){
s1[left + i] = s2[i];
}
}
void MS(int s1[],int s2[],int left,int right){
if(left < right){
int middle = (left + right) / 2;
MS(s1,s2,left,middle); //通过递归不断将数组分解
MS(s1,s2,middle + 1,right);
M(s1,s2,left,right);
}
}
int main(){
int n;
printf("请输入数组个数:");
scanf("%d",&n);
int s1[n],s2[n];
for(int i = 0;i < n;i++){
scanf("%d",&s1[i]);
}
MS(s1,s2,0,n-1);
for(int i = 0;i < n;i++){
printf("%d",s1[i]);
}
return 0;
}
5.快速排序:
#include <stdio.h>
void QS(int s[], int start, int end) {
if (start >= end){
return;
} // 当子数组大小为1时,无需排序
int i = start + 1, j = end;
int t = s[start];
int c;
while (1) {
while (i <= end && s[i] < t) i++; // 找到左侧大于基准值的元素
while (j > start && s[j] >= t) j--; // 找到右侧小于基准值的元素
if (i > j) {
break;
} else {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
c = s[start];
s[start] = s[j];
s[j] = c;
QS(s, start, j - 1); // 对基准值左侧的子数组进行递归排序
QS(s, j + 1, end); // 对基准值右侧的子数组进行递归排序
}
int main() {
int n;
printf("输入数组个数:");
scanf("%d",&n);
int arr[n];
for(int i = 0;i < n;i++){
scanf("%d",&arr[i]);
}
QS(arr,0,n-1);
for(int i = 0;i < n;i++){
printf("%d ",arr[i]);
}
return 0;
}
二:动态规划
1.数塔求最大值并输出路径问题:
(算法关键:s[i][j] = a[i][j] + max{s[i+1][j],s[i+1][j+1]})
#include <stdio.h>
int main(){
int n;
printf("请输入数塔的层数:");
scanf("%d",&n);
int a[n][n],s[n][n],p[n][n];
for(int i = 0;i < n;i++){
for(int j = 0;j <=i;j++){
scanf("%d",&a[i][j]);
}
}
for(int j = 0;j < n;j++){
s[n-1][j] = a[n-1][j];
}
for(int i = n -2;i >= 0;i--){
for(int j = 0;j <= i;j++){
if(s[i+1][j] > s[i+1][j+1]){
s[i][j] = a[i][j] + s[i+1][j];
p[i][j] = j;
}
else{
s[i][j] = a[i][j] + s[i+1][j+1];
p[i][j] = j+1;
}
}
}
printf("%d",s[0][0]);
printf("[%d",a[0][0]);
int j = p[0][0];
for(int i = 1;i < n;i++){
printf("->%d",a[i][j]);
j = p[i][j];
}
printf("]");
return 0;
}
2.0-1背包问题
(1).当没有任何物品,背包为j,即:m(i,j) = 0 i = 0
(2).当