1966年Bohm和Jacpini用數學方法證明了隻用三類控制結構和任意數量的布爾型标志變量就能表示任何算法(或函數),這三類控制結構是:
1 順序結構
2 選擇結構(例如,if-else,switch)
3 循環結構(例如,whuile,for,do)
這三種控制結構的一個特點就是隻有一個入口和出口,是對goto語句随意跳轉的一種約束或限制。
不管是選擇還是循環,本質上都是一種跳轉,在計算機的底層,分支選擇與循環是通過比較與跳轉命令來實現的。
在彙編語言中,比較命令是cmp,跳轉命令是jmp\jg\jge等。
指令序列順序存儲在内存的代碼區,用地址表示每一條指令,指令跳轉就是直接跳到代碼區某一地址對應的指令去執行。
而比較命令cmp在計算機内部是通過一個減法操作來實現,減法的結果可以是一個正數、負數或0,存儲到标志寄存器中,根據标志寄存器中的值(狀态)來進行跳轉。
這三種控制結構的順序和選擇結構相對容易理解,理解循環結構要複雜一些。
可以通過goto如何實現重複操作去理解while循環,通過while循環去理解for循環:
#include <stdio.h>
int accumuByGoto(int n)
{
int sum=0,i=0; // 叠代變量i初始化
label:
i ; // 叠代變量i更新
sum =i;
if(i<n) // 包含不的條件判斷
goto label;
return sum;
}
int accumuByWhile(int n)
{
int i=1,sum=0; // 循環變量初始化
while(i<=100) // 包含循環變量的條件判斷
{
sum =i;
i ; // 循環變量更新
}
return sum;
}
int accumuByFor(int n)
{
int sum = 0;
for(int i=1;i<=100;i ) // 包含循環變量的三個表達式集中到了一起
sum = i;
return sum;
}
int main()
{
printf("%d ",accumuByGoto(100));
printf("%d ",accumuByWhile(100));
printf("%d ",accumuByFor(100));
getchar();
return 0;
}
循環應用場合最多的就是遍曆數組,鍊表去做排序或查找操作等。
1 單循環及應用場合
#include <stdio.h>
int func(char s[],int c) // 在字符串在删除某一指定字符
{
char *q=s;
for(; *q; q )
if(*q != c)
*(s )=*q;
*s='\0';
}
void main()
{
static char str[]="Turbo c and borland c ";
char ch;
printf(" The string before delete is %s.\n",str);
printf(" Please input the char to delete : ");
scanf("%c",&ch);
func(str,ch);
printf(" The string after delete is %s.\n",str);
printf(" Press any key to quit...");
getchar();
return;
}
數組名是數組全部元素的基點,索引的改變相當于就是這個指針的移動。
一趟循環找出兩個最值:
#include <stdio.h>
#include <stdlib.h>
const int minm = -32767;
const int maxm = 32767;
int maxmin[2]={0};
int* findMax(int data[],int count,int *arr) // 一趟循環找出兩個最值
{
int i;
int maxn = data[0];
int maxn2 = minm;
for (i=1;i<count;i )
{
if(data[i] > maxn)
{
maxn2 = maxn; // maxn2是maxn的接替者
maxn = data[i]; // maxn更新為最新近的最大值
}
else
{
if(data[i]>maxn2)
maxn2 = data[i]; // maxn2如果比最新比較的值要小,也要更新
}
}
arr = maxmin; // 隻是指針指向
arr[0] = maxn;
arr[1] = maxn2;
printf("%d,%d\n",arr[0],arr[1]);
return arr;
}
int* findMin(int data[],int count,int *arr)
{
int i;
int minn = data[0];
int minn2 = maxm;
for (i=1;i<count;i )
{
if(data[i] < minn)
{
minn2 = minn;
minn = data[i];
}
else
{
if(data[i]<minn2)
minn2 = data[i];
}
}
arr = maxmin;
arr[0] = minn;
arr[1] = minn2;
printf("%d,%d\n",arr[0],arr[1]);
return arr;
}
int main()
{
int arr[] = {12,5,6,7,7,8,98,3,458,53,1};
int len = sizeof(arr)/sizeof(arr[0]);
findMax(arr,len,maxmin);
findMin(arr,len,maxmin);
system("pause");
return 0;
}
遍曆鍊表:
struct Node
{
int data;
struct Node* next;
};
void printList(struct Node* headNode)
{
struct Node* pMove = headNode->next;
while (pMove) // 節點是否為空
{
printf("%d->", pMove->data);
pMove = pMove->next; // 鍊表指針移動
}
printf("\n");
}
不同于數組索引的移動,鍊表是以頭節點為基準,每個節點通過節點的指針域去找到下一個節點的。
2 雙循環相對于單循環,雙循環的理解要困難一些。假設有一個n*m的雙循環(外循環執行n次,内循環執行m次),簡單的理解就是外循環的叠代變量叠代一次,内循環的叠代變量叠代m次(跑一圈後回到外循環),當外循環變量叠代n次(外循環跑一圈 )後,雙循環退出(當然也可以通過break提前退出)。
雙循環用得最多的場合就是一維數組排序了。
我們知道,對于冒泡排序來說,一次從一個線性結構中冒出一個最值需要一個循環,自然,數組全部元素的處理就需要再在外面套一個循環了。
#include<stdio.h>
#include<stdlib.h>
int main(){
int i,j;
char a[10] = {'e','b','a','d','f','i','c','g','j','h'};
char t;
printf("原數組中的字符是:\n");
for(i=0; i<10; i )
{
printf("%c ",a[i]);
}
for(i=0; i< 9; i )
{
for(j=0;j<9-i; j )
{
if(a[j]>a[j 1])
{
t=a[j];
a[j]=a[j 1];
a[j 1] = t;
}
}
}
printf("\n按升序排序後的字符是:\n");
for(i=0; i<10; i )
{
printf("%c ",a[i]);
}
printf("\n");
system("pause");
return 0;
}
/*
原數組中的字符是:
e b a d f i c g j h
按升序排序後的字符是:
a b c d e f g h i j
*/
鍊表的排序是同樣的思想:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node* next;
};
struct Node* createList()
{
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
headNode->next = NULL;
return headNode;
}
struct Node* createNode(int data)
{
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
headNode->data = data;
headNode->next = NULL;
return headNode;
}
void insertNodeByHead(struct Node* headNode, int data)
{
struct Node* newNode = createNode(data); // 1 新建節點
newNode->next = headNode->next; // 連(新節點的指針域連上頭節點的下一個節點)
headNode->next = newNode; // 斷(頭節點的指針域連上新節點)
}
void printList(struct Node* headNode)
{
struct Node* pMove = headNode->next;
while (pMove)
{
printf("%d->", pMove->data);
pMove = pMove->next;
}
printf("\n");
}
void BubbleSort(struct Node* headNode)
{
struct Node* firstNode = headNode->next;
struct Node* secondNode = headNode;
while (firstNode != NULL)
{
while (firstNode->next != NULL)
{
if (firstNode->data > firstNode->next->data)
{
int temp = firstNode->data;
firstNode->data = firstNode->next->data;
firstNode->next->data = temp;
}
firstNode = firstNode->next;
}
//減少排序次數
firstNode = secondNode->next;
secondNode = firstNode;
}
}
int main()
{
struct Node* list = createList();
insertNodeByHead(list, 3);
insertNodeByHead(list, 1);
insertNodeByHead(list, 2);
insertNodeByHead(list, 5);
printList(list);
BubbleSort(list);
printList(list);
system("pause");
return 0;
}
一維數組找一個最值需要單循環,一維數組排序需要雙循環,二維數組排序則需要再在外套一個循環,需要三重循環。
#include <stdio.h>
jsValue(int arr[][9],int rows)
{
int size = 9;
int i,j,r;
for(r=0;r<rows;r )
{
for(i=0;i<size;i )
for(j=0;j<size-i-1;j )
if(arr[r][j]>arr[r][j 1])
{
int t=arr[r][j];
arr[r][j]=arr[r][j 1];
arr[r][j 1]=t;
}
}
}
main()
{
int a[10][9]={
{6,8,9,1,2,5,4,7,3},
{3,5,8,9,1,2,6,4,7},
{8,2,1,9,3,5,4,6,7},
{3,5,1,2,9,8,6,7,4},
{4,7,8,9,1,2,5,3,6},
{4,7,3,5,1,2,6,8,9},
{9,1,3,5,8,6,2,4,7},
{2,6,1,9,8,3,5,7,4},
{5,3,7,9,1,8,2,6,4},
{7,1,3,2,5,8,9,4,6},
};
int i,j;
jsValue(a,10);
for(i=0;i<10;i ){
for(j=0;j<9;j ) {
printf("%d",a[i][j]);
if(j<=7)printf(",");
}
printf("\n");
}
getchar();
}
在枚舉算法中,都極有可能使用4重及更多重循環了。
現有蘋果、桔子、香蕉、菠蘿、梨5種水果用來做水果拼盤,每個水果拼盤一定有3個水果,且這3個水果的種類不同,問可以制作出多少種水果拼盤?
使用枚舉類型定義變量x、y、z,其中,x、y、z 是5 種水果中的任一種,設定由水果x、y、z 制作一種水果拼盤,并滿足x≠y≠z。使用三重循環語句來組合它們,使用窮舉法來計算總共有多少種水果拼盤可以制作。
#include <stdio.h> // 排列問題,非組合問題
void main()
{
enum fruit {apple, orange, banana, pineapple, pear};/* 定義枚舉結構*/
enum fruit x,y,z,pri; /* 定義枚舉變量*/
int n=0,loop;
for(x=apple;x<=pear;x )
for(y=apple;y<=pear;y )
if(x!=y)
{
for(z=apple;z<=pear;z ) // 三個東西的組合需要三重循環
if((z!=x)&&(z!=y))
{
n=n 1;
printf("\n %-4d",n);
for(loop=1;loop<=3;loop ) // 組合順序不同,也是不同的排列
{
switch(loop)
{
case 1:pri=x;break;
case 2:pri=y;break;
case 3:pri=z;break;
default: break;
}
switch(pri)
{
case apple: printf(" %-9s","apple"); break;
case orange: printf(" %-9s","orange");break;
case banana: printf(" %-9s","banana");break;
case pineapple: printf(" %-9s","pineapple");break;
case pear: printf(" %-9s","pear"); break;
default: break;
}
}
}
}
printf("\n\n There are %d kinds of fruit plates.\n",n);
puts(" Press any key to quit...");
getch();
return;
}
-End-
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!