C语言经典例题整理

1 加法器与累乘器

代码

累加器

#include<stdio.h>
int main (void)
{
int i;
int sum=0;
for(i=1;i<=100;i++)
{
sum=sum+i;
}
printf("%d.\n",sum);
return 0;
}

累乘器:

#include<stdio.h>
int main (void)
{
int i;
int p=1;
for(i=2;i<=100;i++)
{
p=p*i;
}
printf("%d.\n",p);
return 0;
}

2 求最大数与最小数

题目描述

  输入5个数

样例输入

21 12 5 78 485

样例输出

max:485 min:5

代码

#include <stdio.h>
int main(){
	int a[5],max,min,i;
	for(i=0;i<5;i++){
		scanf("%d",&a[i]);
	}
	max=a[0];
	min=a[0];
	for(i=1;i<5;i++){
		if(a[i]>max){
			max=a[i];
		}
		if(a[i]<min){
			min=a[i];
		}
	}
	printf("max:%d min:%d\n",max,min);
	return 0;
}

3 排序算法

冒泡排序

算法原理

  它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。

题目描述

  输入10个数,从小到大排序

样例输入

15 23 2 6 9 46 75 6 8 10

样例输出

2 6 6 8 9 10 15 23 46 75

代码

#include <stdio.h>
void bubleSort(int a[]);
int main(){
	int a[10],i;
	for(i=0;i<10;i++){
		scanf("%d",&a[i]);
	}
	bubleSort(a);
	for(i=0;i<10;i++){
		printf("%d ",a[i]);
	}
}
void bubleSort(int a[]){
	int i,j,temp;
	for(i=0;i<10-1;i++){    //外循环为排序趟数,len个数进行len-1趟
		for(j=0;j<10-i-1;j++){  //内循环为每趟比较的次数,第i趟比较len-i次
			if(a[j]>a[j+1]){
				temp=a[j+1];
				a[j+1]=a[j];
				a[j]=temp;
			}
		}
	}
}

选择排序

算法原理

  第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。

代码

#include <stdio.h>
void select_Sort(int a[], int len);
int main(){
	int a[10],i;
	for(i=0;i<10;i++){
		scanf("%d",&a[i]);
	}
	select_Sort(a, 10);
	for(i=0;i<10;i++){
		printf("%d ",a[i]);
	}
}
void select_Sort(int a[], int len){
	int i,j,min,temp;
	for(i=0;i<len-1;i++){
		min=i;  //每一趟找出最小值的下标
		for(j=i+1;j<len;j++){
			if(a[j]<a[min]){
				min=j;
			}
		}
		if(min!=i){
			temp=a[min];
			a[min]=a[i];
			a[i]=temp;
		}
	}
}

插入排序

算法原理

  主要的实现思想是将数据按照一定的顺序一个一个的插入到有序的表中,最终得到的序列就是已经排序好的数据。

代码

#include <stdio.h>
void Insert_Sort(int a[], int len);
int main(){
	int a[10],i;
	for(i=0;i<10;i++){
		scanf("%d",&a[i]);
	}
	Insert_Sort(a, 10);
	for(i=0;i<10;i++){
		printf("%d ",a[i]);
	}
}
void Insert_Sort(int a[], int len){
	int i,j;
	int temp;
	//开始时只有第一项,有序;从第二项开始即可 
	for(i=1;i<len;i++){
		temp=*(a+i);
		//若前一项比插入的项大,则前一项后移 
		for(j=i;j>0&&*(a+j-1)>temp;j--){
			*(a+j)=*(a+j-1);
		}
		*(a+j)=temp;
	}
}

希尔排序

算法原理

image-20200316124012165

代码

#include <stdio.h>
void Shell_Sort(int a[], int len);
int main(){
	int a[10],i;
	for(i=0;i<10;i++){
		scanf("%d",&a[i]);
	}
	Shell_Sort(a, 10);
	for(i=0;i<10;i++){
		printf("%d ",a[i]);
	}
}
void Shell_Sort(int a[], int len){
	int gap,i,j,k,temp;
	// 步长初始化为数组长度的一半,每次遍历后步长减半
	for(gap=len/2;gap>=1;gap/=2){
		//分组插入排序  
		for(i=0;i<gap;i++){
			for(j=i+gap;j<len;j+=gap){
				temp=a[j];
				for(k=j;k>j%gap&&a[k-gap]>temp;k-=gap){
					a[k]=a[k-gap];
				}
				a[k]=temp;
			}
		}
	}
}

归并排序

算法原理

  归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题(divide)成一些小的问题然后递归求解,而**治(conquer)**的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

img

  • https://www.cnblogs.com/chengxiao/p/6194356.html

代码

#include <stdio.h>
//合 
void Merge(int sourceArr[],int tempArr[], int startIndex, int midIndex, int endIndex)
{
    int i = startIndex, j=midIndex+1, k = startIndex;
    while(i!=midIndex+1 && j!=endIndex+1)
    {
        if(sourceArr[i] > sourceArr[j])
            tempArr[k++] = sourceArr[j++];
        else
            tempArr[k++] = sourceArr[i++];
    }
    while(i != midIndex+1)
        tempArr[k++] = sourceArr[i++];
    while(j != endIndex+1)
        tempArr[k++] = sourceArr[j++];
    for(i=startIndex; i<=endIndex; i++)
        sourceArr[i] = tempArr[i];
}
//内部使用递归
void Merge_Sort(int sourceArr[], int tempArr[], int startIndex, int endIndex)
{
    int midIndex;
    if(startIndex < endIndex)
    {
        midIndex = startIndex + (endIndex-startIndex) / 2;//避免溢出int
        Merge_Sort(sourceArr, tempArr, startIndex, midIndex);
        Merge_Sort(sourceArr, tempArr, midIndex+1, endIndex);
        Merge(sourceArr, tempArr, startIndex, midIndex, endIndex);
    }
}
int main(){
	int a[10],b[10],i;
	for(i=0;i<10;i++){
		scanf("%d",&a[i]);
	}
	Merge_Sort(a, b, 0, 9);
	for(i=0;i<10;i++){
		printf("%d ",a[i]);
	}
}

快速排序

算法原理

image-20200317133844661

  • https://blog.51cto.com/13733462/2113397

代码

#include <stdio.h>
void QuickSort(int a[],int left,int right);
int main(){
	int a[10],i;
	for(i=0;i<10;i++){
		scanf("%d",&a[i]);
	}
	QuickSort(a,0,9);
	for(i=0;i<10;i++){
		printf("%d ",a[i]);
	}
}
void QuickSort(int a[],int left,int right){
	if(left>=right){
		return;
	}
	int i=left,j=right;
	int key=a[left];
	while(i<j){
		while(i<j&&key<=a[j]){
			j--;
		}
		a[i]=a[j];
		while(i<j&&key>=a[i]){
			i++;
		}
		a[j]=a[i];
	}
	a[i]=key;
	QuickSort(a,left,i-1);
	QuickSort(a,i+1,right);
}

4 大小写字母转换

样例输入

aBujZx

样例输出

ABUJZX

代码

#include <stdio.h>
void toupper(char a[]);
int main(){
	char a[50];
	scanf("%s", a);
	toupper(a);
	printf("%s", a);
}
void toupper(char a[]){
	int i=0;
	while(a[i]!='\0'){
		if('a'<=a[i]&&a[i]<='z'){
			a[i]=a[i]-32;
		}
		i++;
	}
}

5 统计字符串中的字母,数字,空格,其他个数

样例输入

aBcd48_@ 653

样例输出

字母有: 4 个
数字有: 5 个
空格有: 1 个
其他有: 2 个

代码

#include <stdio.h>
 
int main(void)
{
	char ch;
	int zimu, shuzi, kongge, other;
	zimu = shuzi = kongge = other = 0;
 
	 while( ( ch = getchar() ) != '\n')
	 {
		if ( (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') )
		{
			zimu++;
		
		}
		else if( ch >= '1' && ch <= '9')
		{
			shuzi++;
		
		}
		else if( ch == ' ')
		{
			kongge++;
		
		}
		else
		{
			other++;
		}
	 }
 
	printf("字母有: %d 个\n", zimu);
	printf("数字有: %d 个\n", shuzi);
	printf("空格有: %d 个\n", kongge);
	printf("其他有: %d 个\n", other);
	printf("\n");
	return 0;
}

6 判断闰年

样例输入

1900
2004

样例输出

1900 year is not leap year
2004 year not leap year

代码

#include <stdio.h>
int main(){
	int year;
	scanf("%d",&year);
	if((year%4==0 && year%100!=0) || year%400==0){  //判断闰年的条件
		printf("%d year is leap year\n", year);
	}
	else{
		printf("%d year is not leap year\n", year);
	}
	return 0;
}

7 百分制成绩和等级制成绩转换

题目描述

代码

#include <stdio.h>
int main(){
	int score;
	char result;
	do{
		scanf("%d",&score);
	}while(score<0 || score>100);
	switch((int)(score/10)){
		case 10:                    //注意switch case语句使用,case仅能常量
		case 9:result='A';break;
		case 8:result='B';break;
		case 7:result='C';break;
		case 6:result='D';break;
		default:result='E';
	}
	printf("%c",result);
	return 0;
}

8 求两数最大公因数和最小公倍数(辗转相除法/欧几里得算法)

算法原理

样例输入

3139 2117

样例输出

最大公约数 73,最小公倍数 91031

代码

#include <stdio.h>
int main(){
	int a,b,m,n,o;
	scanf("%d%d",&a,&b);
	m=a;
	n=b;
	if(a<b){    //a<b则交换顺序
		m=b;
		n=a;
	}
	while(n!=0){    //辗转相除法
		o=m%n;
		m=n;
		n=o;
	}
	printf("最大公约数 %d,最小公倍数 %d\n",m,a*b/m);    //最小公约数最小公倍数关系
	return 0;
}

9 求斐波拉契数列有限项(递归应用)

样例输入

9

样例输出

34

代码

#include <stdio.h>
int Fibonacci(int n);
int main(){
	int n;
	scanf("%d",&n);
	printf("%d",Fibonacci(n));
}
int Fibonacci(int n){
	if(n==1 || n==2){
		return 1;
	}
	else{
		return Fibonacci(n-1)+Fibonacci(n-2);
	}
}

10 验证哥德巴赫猜想(素数验证应用)

题目描述

  数学领域著名的“哥德巴赫猜想”的大致意思是:任何一个大于2的偶数总能表示为两个素数之和。比如:24=5+19,其中5和19都是素数。本实验的任务是设计一个程序,验证20亿以内的偶数都可以分解成两个素数之和。

样例输入

42

样例输出

42 = 5 + 37

代码

#include <stdio.h>
#include <math.h>
bool is_prime(int num);
int main(){
	int n,i;
	scanf("%d",&n);
	for(i=2;i<n;i++){
		if(is_prime(i) && is_prime(n-i)){
			printf("%d = %d + %d\n",n,i,n-i);
			break;
		}
	}
	return 0;
}
bool is_prime(int num){
	int i,k;
	k=sqrt(num);
	for(i=2;i<=k;i++){  //素数验证可简化为仅需判断是否能够被 2~√n 之间整数整除即可
		if(num%i==0)break;
	}
	if(i<=k){
		return false;
	}
	else
		return true;
}

11 水仙花数

题目描述

样例输出

153 370 371 407

代码

#include <stdio.h>
#include <math.h>
int main(){
	int i,ge,shi,bai;
	for(i=100;i<=999;i++){
		ge=i%10;
		shi=(i%100)/10;
		bai=i/100;
		if(i==pow(ge,3)+pow(shi,3)+pow(bai,3)){
			printf("%d ",i);
		}
	}
	return 0;
}

12 完全平方数

题目描述

  一个整数,它加上100 后是一个完全平方数,再加上168 又是一个完全平方数,请问该数是多少?

  完全平方数:开方之后是整数
样例输出

21 261 1581

代码

#include <stdio.h>
#include <math.h>
int main(){
	int i,num1,num2;
	for(i=0;i<100000;i++){
		num1=i+100;
		num2=num1+168;
		if(sqrt(num1)==(int)sqrt(num1) && sqrt(num2)==(int)sqrt(num2)){
			printf("%d ",i);
		}
	}
	return 0;
}

13 完数

题目描述

  它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身,1 不是完数
样例输出

6 is factors are 1 2 3
28 is factors are 1 2 4 7 14
496 is factors are 1 2 4 8 16 31 62 124 248

代码

#include <stdio.h>
#include <math.h>
int main(){
	int i,j,s;
	for(i=2;i<=1000;i++){
		s=0;
		for(j=1;j<i;j++){
			if(i%j==0){
				s+=j;
			}
		}
		if(s==i){
			printf("%d is factors are ",i);
			for(j=1;j<i;j++){
				if(i%j==0){
					printf("%d ",j);
				}
			}
			printf("\n");
		}
	}
	return 0;
}

14 梯形法求定积分近似值

题目描述

  求函数X^2的定积分近似值

样例输入

0 1

样例输出

0.353804

代码

#include <stdio.h>
#include <math.h>
float seekSimilar(float a,float b,int n);
float func(float x);
int main(){
	float a,b;
	scanf("%f%f",&a,&b);
	printf("%f", seekSimilar(a,b,50));
}
float seekSimilar(float a,float b,int n){
	float h,i,s=0;
	h=(b-a)/n;	//将区间划为n份 
	for(i=a;i<b;i+=h){
		s+=(func(i)+func(i+h))*h/2;
	}
	return s;
}
float func(float x){
	return pow(x,2);
}

15 牛顿迭代法求多元方程根

题目描述


样例输出

2.000000

代码

#include <stdio.h>
#include <math.h>
int main(){
	double x0,x1,f,f1;
	x1=1.5;
	do{
		x0=x1;
		f=2*pow(x0,3)-4*pow(x0,2)+3*x0-6;
		f1=6*pow(x0,2)-8*x0+3;
		x1=x0-f/f1;
	}while(fabs(x1-x0)>=1e-5);  //注意判断条件
	printf("%f\n",x1);
	return 0;
}

16 二分法求多次方根

题目描述


样例输入

enter x1,x2:-10,10

样例输出

x=  2.00

代码

#include <stdio.h>
#include <math.h>
int main(){
	float x1,x2,x0,f1,f2,f0;
	do{
		printf("enter x1,x2:"); 
		scanf("%f,%f",&x1,&x2);
		f1=2*pow(x1,3)-4*pow(x1,2)+3*x1-6;
		f2=2*pow(x2,3)-4*pow(x2,2)+3*x2-6;
	}while(f1*f2>0);
	do{
		x0=(x1+x2)/2;
		f0=2*pow(x0,3)-4*pow(x0,2)+3*x0-6;
		if(f0*f1<0){
			x2=x0;
			f2=f0;
		}
		else{
			x1=x0;
			f1=f0;
		}
	}while(fabs(x1-x2)>=1e-5);
	printf("x=%6.2f", x0);
	return 0;
}

17 求两个矩阵相乘

样例输入

输入第一个矩阵:
1 2
3 4
5 6
输入第二个矩阵:
7 8 9
10 11 12

样例输出

   27   30   33
   61   68   75
   95  106  117

代码

#include <stdio.h>
#define X 3
#define Y 2
#define Z 3
int main(){
	int a[X][Y],b[Y][Z],c[X][Z];
	int i,j,k;
	printf("输入第一个矩阵:\n");
	for(i=0;i<X;i++){
		for(j=0;j<Y;j++){
			scanf("%d", &a[i][j]);
		}
	}
	printf("输入第二个矩阵:\n");
	for(i=0;i<Y;i++){
		for(j=0;j<Z;j++){
			scanf("%d", &b[i][j]);
		}
	}
	printf("矩阵相乘结果:\n");
	for(i=0;i<X;i++){
		for(j=0;j<Z;j++){
			c[i][j]=0;
			for(k=0;k<Y;k++){
				c[i][j] += a[i][k]*b[k][j]; //相乘的时候注意下标
			}
		}
	}
	for(i=0;i<X;i++){
		for(j=0;j<Z;j++){
			printf("%5d", c[i][j]);
		}
		printf("\n");
	}
	return 0;
}

18 利润利息计算


代码

//利息计算
#include <stdio.h>
#include <math.h>

int main(){
	double P1, P2, P3, P4, P5;
	
	P1 = 1000*(1+5*0.0585);
	P2 = (1000*(1+2*0.0468))*(1+3*0.054);
	P3 = (1000*(1+3*0.054))*(1+2*0.0468);
	P4 = 1000*pow(1+0.0414, 5);
	P5 = 1000*pow(1+0.0072/4, 5*4);
	
	printf("%f\n%f\n%f\n%f\n%f\n", P1, P2, P3, P4, P5);
	return 0;
}

19 年月日判断是年份的第几天

样例输入

Please input year/mouth/day:2000/4/2

样例输出

its 93 day

代码

#include <stdio.h>
int main(){
	int mon[12]={31,28,31,30,31,30,31,31,30,31,30,31};
	int year,mouth,day,num,i;
	printf("Please input year/mouth/day:");
	scanf("%d/%d/%d",&year,&mouth,&day);
	if((year%4==0 && year%100!=0) || (year%400==0)){
		mon[1]=29;
	}
	num=day;
	for(i=0;i<mouth-1;i++){
		num += mon[i];
	}
	printf("its %d day\n",num);
	return 0;
}

20 图形输出

//图形输出问题
//分成两部分来看,找每一行空格,*和行号的规律
//注意输出一行后记得输出\n
#include <stdio.h>
int main(){
  int i,j,k;
  for(k=1;k<=4;k++){
  	for(i=1;i<=4-k;i++){
  		printf(" ");
	  }
	for(j=1;j<=2*k-1;j++){
		printf("*");
	}
	printf("\n");
  }
  for(k=1;k<=3;k++){
  	for(i=1;i<=k;i++){
  		printf(" ");
	}
	for(j=1;j<=2*(3-k)+1;j++){
		printf("*");
	}
	printf("\n");
  }
  return 0;
 }

21 输出乘法表

样例输出

1×1=1
2×1=2    2×2=4
3×1=3    3×2=6    3×3=9
4×1=4    4×2=8    4×3=12   4×4=16
5×1=5    5×2=10   5×3=15   5×4=20   5×5=25
6×1=6    6×2=12   6×3=18   6×4=24   6×5=30   6×6=36
7×1=7    7×2=14   7×3=21   7×4=28   7×5=35   7×6=42   7×7=49
8×1=8    8×2=16   8×3=24   8×4=32   8×5=40   8×6=48   8×7=56   8×8=64
9×1=9    9×2=18   9×3=27   9×4=36   9×5=45   9×6=54   9×7=63   9×8=72   9×9=81

代码

#include "stdio.h"
main(){
	int i,j;
	for(i=1;i<10;i++){
		for(j=1;j<=i;j++){
			printf("%d×%d=%-5d",i,j,i*j);
		}
		printf("\n");
	}
	return 0;
}

22 兔子问题(斐波那契数列应用)

题目描述

  有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?

代码

#include <stdio.h>
int Fibonacci(int n);
int main(){
	int n;
	scanf("%d",&n);
	printf("%d",Fibonacci(n));
}
int Fibonacci(int n){
	if(n==1 || n==2){
		return 1;
	}
	else{
		return Fibonacci(n-1)+Fibonacci(n-2);
	}
}

23 分解质因数

代码

#include <stdio.h>
#include <stdlib.h>
//将一个正整数分解质因数
int main()
{
    int i,n;
    printf("Please input an integer!\n");
    scanf("%d",&n);
    for(i=2;i<=n;i++)
    {
        while(n!=i)     //若i=n,则质因数就是n本身
        {
            if(n%i==0)  //若i是质因数,则打印出i的值,并用商给n赋新值
            {
                printf("%d\n",i);
                n=n/i;
            }
            else break;//若不能被i整除,则算下一个i
        }
    }
    printf("%d\n",n);   //这里是打印最后一个质因数,也就是等于i时的那个
    return 0;
}

24 求sn=a+aa+aaa+aaaa+aa…a


代码

//注意an的求法
#include <stdio.h>
int main(){
	int a,n,i=1,result=0,an=0;
	printf("a,n:");
	scanf("%d,%d",&a,&n);
	while(i<=n){
		an=an+a;
		printf("%d\n",an);
		result=result+an;
		a=a*10;
		i++;
	}
	printf("a+aa+aaa+ …=%d\n",result);
	return 0;
}

25 小球下落问题

题目描述

  一球从100 米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在第10次落地时,共经过多少米?第10 次反弹多高?

样例输出

Total 299.609375
h10 is 0.097656

代码

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    int i;
    double sn=100;
    double hn=sn/2;
    for(i=2;i<=10;i++)
    {
        sn+=2*hn;
        hn/=2;
    }
    printf("Total %lf\n",sn);
    printf("h10 is %lf\n",hn);
    return 0;
}

26 比赛排序


//比赛排序问题
//先逻辑图,判断出正确结果
//编程使用假设的方法,三层循环,判断符合条件的情况
#include <stdio.h>
int main(){
  char i,j,k;
  for(i='X';i<='Z';i++){
  	for(j='X';j<='Z';j++){
  		if(i!=j){
  			for(k='X';k<='Z';k++){
  				if(k!=i&&k!=j){
  					if(i!='X'&&k!='X'&&k!='Z'){
  						printf("A-%c,B-%c,C-%c\n",i,j,k);
					  }
				  } 
			  }
		  }
	  }
  }
  return 0;
 }

27 阶乘的和

代码

#include <stdio.h>
#include <stdlib.h>
//求1到20的阶乘的和
int main()
{
    int i,j;
    long int sum,n;
    sum=0;
    for(i=1;i<=20;i++)
    {
        n=1;
        for(j=1;j<=i;j++)
           n*=j;
        //循环后的n为i!
        sum+=n;
    }
    printf("Sum is %ld!\n",sum);
    return 0;
}

28 递归逆序输出字符

代码

//注意,一定要在putchar()之前调用递归函数,另外注意:getchar()是从输入流中获取一个字符,所以输入的时候格式就是abcde,并非像scanf那样输入一个字符后,按回车或者Tab后再输入下一个字符。
#include <stdio.h>

void print(int);
int main()
{
    printf("Input chars:\n");
    print(5);
    printf("\n");
    return 0;
}
void print(int n)
{
    char c;
    if(n==1){
    	c=getchar();
    	printf("Output:\n");
    	putchar(c);
	}
	else{
		c=getchar();
		print(n-1);
		putchar(c);
	}
}

29 求一个整数的位数且逆序打印

样例输入

Please input an integer!
789456

样例输出

654987
It contains 6 digits!

代码

#include <stdio.h>
#include <stdlib.h>
int digits(int n);
int main()
{
    int i;
    printf("Please input an integer!\n");
    scanf("%d",&i);
    printf("It contains %d digits!\n",digits(i));
    return 0;
}
int digits(int n){
	int d=0;
	while(n>0){
		printf("%d", n%10);
		n /= 10;
		d++;
	}
	printf("\n");
	return d;
}

30 判断回文数

样例输入

12121

样例输出

12121 是回文数

代码

//思路:反着排一遍,如果和原数相同则为回文数
#include <stdio.h>

bool huiwenshu(int num);
int main(){
    int num;
    scanf("input a interger:");
    scanf("%d",&num);
    if(huiwenshu(num)){
    	printf("%d 是回文数", num);
	}
	else{
		printf("%d 不是回文数", num);
	}
	return 0; 
}
bool huiwenshu(int num){
	int s,y=0;
	s=num;
	while(s>0){
		y=y*10+s%10;
		s /= 10;
	}
	if(y==num)
		return true;
	else
		return false;
}

31 判断字符串是否为回文

样例输入

abcdcba

样例输出

是回文

代码

#include <stdio.h>
#include <string.h>

bool  huiwen(char *str, int len);
int main(){
    char str[20];
    scanf("input a string:");
//    scanf("%s",&str);
	gets(str);
	if(huiwen(str, strlen(str))){
		printf("是回文"); 
	}
	else{
		printf("不是回文");
	}
	return 0;
}
bool  huiwen(char *str, int len){
	int i;
	for(i=0;i<len;i++){
		if(str[i]!=str[len-i-1]){
			return false;
		}
	}
	return true;
}

32 顺序队列中插入新元素

代码

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    int a[11]={1,2,4,7,9,13,18,24,32,45};
    int i,num,pos=0;
    scanf("%d",&num);
    if(num>=a[9])
        a[10]=num;
    while(a[i]<num)     //找到第一个不比num小的元素的位置
    {
        i++;
        pos++;
    }
    for(i=10;i>pos;i--) //将该元素及之后所有元素右移一位
        a[i]=a[i-1];
    a[pos]=num;         //给新元素安排位置
    for(i=0;i<11;i++)
        printf("%4d",a[i]);
    return 0;
}

33 杨辉三角形

代码

#include <stdio.h>
# define N 10
int main(){
  int i,j,a[N][N];
  for(i=0;i<N;i++){
  	a[i][i]=1;
  	a[i][0]=1;
  }
  for(i=2;i<N;i++){
  	for(j=1;j<=i-1;j++){
  		a[i][j]=a[i-1][j]+a[i-1][j-1];
	  }
  }
  for(i=0;i<N;i++){
  	for(j=0;j<=i;j++)
  		printf("%6d", a[i][j]);
  	printf("\n");
  }
  return 0;
 }

34 约瑟夫环问题

题目描述

  一堆猴子都有编号,编号是1,2,3 …m,这群猴子(m个)按照1-m的顺序围坐一圈,从第1开始数,每数到第N个,该猴子就要离开此圈,这样依次下来,直到圈中只剩下最后一只猴子,则该猴子为大王。

样例输入

请输入猴子的总数:6
请输入循环单位:5

样例输出

它出列了:5
它出列了:4
它出列了:6
它出列了:2
它出列了:3
最终大王是他:1

代码

#include <stdio.h>
#define MAX_SIZE 50

int main(){
	int Monkey[MAX_SIZE];
	int total_num,num,n,i,count,pos;
	printf("请输入猴子的总数:");
	scanf("%d", &total_num);
	printf("请输入循环单位:");
	scanf("%d", &n);
	for(i=0;i<total_num;i++){
		Monkey[i]=i+1;
	}
	count=0;
	pos=0;
	num=total_num;
	while(num!=1){
		if(Monkey[pos]!=0){
			count++;
		}
		if(count==n){
			Monkey[pos]=0;
			num--;
			printf("它出列了: %d\n",pos+1);
			count=0;
		}
		pos++;
		if(pos==total_num){
			pos=0;
		}
	}
	pos=0;
	while(Monkey[pos]==0){
		pos++;
	}
	printf("最终大王是他:%d", pos+1);
	return 0;
} 

35 八进制转十进制

代码

#include <stdio.h>

int main()
{ char *p,s[6];int n;
p=s;
gets(p);
n=0;
while(*(p)!='\0')
{n=n*8+*p-'0';
p++;}
printf("%d",n);
return 0;
}

36 鸡兔同笼

题目描述

  已知鸡和兔的总数量为n,总腿数为m,输入nm,依次输出鸡的数目和兔的数目。如果无解则输出No answer

样例输入

14 32

样例输出

12 2

代码

///巧解,先算出鸡的数量再算兔子的数量,根据均>=0判断是否有解
#include "stdio.h"
int main() {
  int a,b,n, m;
  // a鸡的数量
  // b兔的数量
  // n鸡兔总数
  // m总脚数
  scanf("%d %d", &n,&m);
  a = (4 * n - m) / 2;//算出鸡的数量
  b = n - a;//算出兔的数量

  if (a <= 0 || b <= 0) {
  //结果小于等于0,答案不成立,无解
    printf("No answer");
  } else {
  //结果大于0
    printf("%d %d", a, b);
  }
  return 0;
}

37 三天打鱼两天晒网

题目描述

  中国有句俗语叫“三天打鱼两天晒网”。某人从2010年1月1日起开始“三天打鱼两天晒网”,问这个人在以后的以后的某一天中是打鱼还是晒网。

代码

/*中国有句俗语“三天打鱼两天晒网”,
有个人从2010年1月1日起开始“三天打鱼,两天晒网”
问这个人在以后的某一天是“打鱼”还是“晒网”。*/ 

#include<stdio.h>
int main()
{
	int year,month,day;
	int y=2010;
	int sum=0;
	int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};//建立一个有平年各月份天数的数组
	printf("请按照年月日的顺序输入日期,中间用空格隔开\n");
	scanf("%d""%d""%d",&year,&month,&day);//输入日期
	while((year<2010)||(month<1||month>12)||(month==2&&(year%4!=0||year%400!=0)&&day>=29)||(day>a[month]))
	{
		printf("输入日期错误,请重新输入\n");
		printf("请按照年月日的顺序重新输入日期,中间用空格隔开\n");
		scanf("%d""%d""%d",&year,&month,&day);
	}
	//判断输入日期是否正确
	for(y;y<year;y++)//用此循环加上相差年份所隔的天数。 
	{
		if((year%400==0)||(year%4==0&&year%100!=0))//判断此年份是否是闰年 
		{
			sum+=366;
		}//是闰年,则总天数加上366. 
		else
		{
			sum+=365;
		}//是平年,总天数加上365 
	}
	for(int m=1;m<month;m++)//用此循环加上所隔月份的总天数 
	{
		sum+=a[m];
		if(month==2&&((year%400==0)||(year%4==0&&year%100!=0))) 
		{
			sum+=1;
		}//判断月份是否为闰年2月,若是2月,则总天数加一。
	}
	sum+=day;//总天数加上日 
	if((sum%5==1)||(sum%5==2)||(sum%5==3))//用相隔总天数除以周期5,若余数为1,2,3,则此人打鱼。 
	{
	printf("这个人今天打鱼\n");
	}
	else//否则,这个人晒网
	{
	printf("这个人今天晒网\n"); 
	}
	return 0;
}

38 汉诺塔问题

问题描述

image-20200320150341382

  需要移动的次数是2n-1

image-20200320151003876image-20200320151036509

样例输入

input the number of disks:3

样例输出

the step:
A->C
A->B
C->B
A->C
B->A
B->C
A->C

代码

image-20200320151153771

#include <stdio.h>

void hannuo(int num,char one,char two,char three);
void move(char a,char b);
int main(){
	int num;
	printf("input the number of disks:");
	scanf("%d", &num);
	printf("the step:\n");
	hannuo(num,'A','B','C');
}

void hannuo(int num,char one,char two,char three){
	if(num==1){
		move(one,three);
	}
	else{
		hannuo(num-1,one,three,two);
		move(one,three);
		hannuo(num-1,two,one,three);
	}
}

void move(char a,char b){
	printf("%c->%c\n",a,b);
}

39 数组循环移位

题目描述

image-20200325101713838

样例输入

6 2
1 2 3 4 5 6

样例输出

5 6 1 2 3 4

代码

方法一:递归的方法

image-20200325103028994

方法二:直接移位,大问题化小问题

#include <stdio.h>
#define MAX 10

void ArrayRight(int a[],int n,int m);
int main(){
	int a[MAX],n,m;
	int i;
	scanf("%d%d",&n,&m);
	for(i=0;i<n;i++){
		scanf("%d",&a[i]);
	}
	ArrayRight(a,n,m);
	for(i=0;i<n;i++){
		printf("%d ",a[i]);
	}
}
void ArrayRight(int a[],int n,int m){
	int temp,k,i;
	//总共移动m位 
	for(k=0;k<m;k++){
		temp=*(a+n-1);
		for(i=n-1;i>=0;i--){
			*(a+i)=*(a+i-1);
		}
		*a=temp;
	}
}

40 线性表

翔哥代码:

/*
    适用于标准C
	SeqList.c
	V1.1
	2016.9.12 wangx
*/
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define OVERFLOW 0
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10

#define Elemtype char

//公共错误码,项目组成员之间的共同约定
#define MALLOC_ERROR  -1  
#define NOTFIND  -2
#define PARAM_ERROR -3
#define REALLOC_ERROR  -4  
//顺序表的结构定义
typedef struct 
{
	Elemtype *pElem;    //动态模式,只定义了一个指针,未分配数据的存储空间。本例假设每个元素都是char型,此处是实际应用中每个元素可能会是结构体变量或者结构体指针
	int iCount;         //当前长度
	int iTotalLength;   //线性表的总长度
}SeqList;               //定义一个新类型,顺序表的类型名称


//你这个菜鸟的任务,就是写这个InitList()函数。本函数假设实参指针已经指向了一个SeqList类型的结构体变量
 int InitList(SeqList *pList)
 {
	 pList->iCount=0; //初始时,一个元素都没有
	 pList->iTotalLength= LIST_INIT_SIZE;  //初始时理论总长就是100个元素(假定值)
	 pList->pElem= (Elemtype *)malloc( LIST_INIT_SIZE * sizeof(Elemtype));  //因为SeqList的定义中,elem只是一个指针,需要分配空间并让该指针指向这段空间。因为malloc可能迸发异常,所以实际中往往会放在try {} catch() {}结构中
	 if (pList->pElem==NULL)
	 {
	 	 return MALLOC_ERROR;   //  返回一个非0值(通常是一个负数),表示本子函数非正常结束,以供主调函数识别和采取对应措施
	 }
	 return 0;                           //一般情况下,在实际工程开发中,基本上都默认函数返回值为0表示该函数运行期间没有异常情况
 }

//根据元素的值x,在顺序表pList中,查找其第一次出现的位置下标,并返回(注意,下标可以为0)。如果没找到,则返回NOTFIND,即-2
int SearchByValue(SeqList *pList, Elemtype Value)
{
	int pos=0;
	//重要的步骤,参数校验!一定别忘了!如果Value有一定的现实含义,则还需要对其做参数有效性校验
	if (pList==NULL)
	{
		return PARAM_ERROR;
	}

	while ( pos<=pList->iCount-1 && pList->pElem[pos]!= Value) //一边比较,一边往后移pos的值,直到找到或者到达有效数据的末尾
		pos++;

	if ( pos <= pList->iCount-1 ) //如果是以“找到”的姿态跳出while循环
		return pos;
	else  
		return NOTFIND;    //如果是以“到末尾”的姿态跳出while循环

}

//功能:根据给定的逻辑位置值pos(假设从1开始),在pList指向的顺序表中提取其元素值,存放到pValue指针指向的空间中并返回给主调函数使用
//备注:pValue的写法,展示了C语言如何通过参数传递,将子函数内的数据传出来,给主调函数使用,注意形参写法和调用时的实参写法!
//      pValue指针,假定其已经指向某个存储空间,本函数不再校验它。问题是:这个空间,应该在主调函数中申请,还是在子函数中申请?一般做法是在主调函数中申请!
int GetValue(SeqList *pList, int pos, Elemtype *pValue)
{
	//重要的步骤,参数校验!一定别忘了!如果Value有一定的现实含义,则还需要对其做参数有效性校验
	if (pList==NULL || pList->pElem==NULL || pos<1 || pos >pList->iCount || pValue==NULL)
	{
		return PARAM_ERROR;
	}
	
	*pValue= pList->pElem[pos];                    //获得元素值
	return 0;
}

//功能:根据指定的逻辑位置pos值(假设从0开始),在pList指向的顺序表中,第pos个元素后面插入值为Value的元素
//备注:pos的值应>=0,当pos=0时,全体所有数据都需要后移一格;当pos>=iCount时,全体数据都不需要后移
int SeqListInsert(SeqList *pList, int pos, Elemtype Value)
{
	Elemtype *pNewBase, *p, *q;
	
	if (pList==NULL || pList->pElem==NULL || pos <0 )
	{
		return PARAM_ERROR;
	}
	if ( pos > pList->iCount )
		pos = pList->iCount ;

	//如果当前已经装满,则需要扩展存储空间
	if (pList->iCount == pList->iTotalLength)
	{
		pNewBase= (Elemtype *)realloc(pList->pElem, (pList->iTotalLength + LISTINCREMENT)*sizeof(Elemtype));  //请同学们进一步了解realloc的工作原理,当空间字节数较多时,该函数开销较大!
		if (pNewBase== NULL)
		{
			return REALLOC_ERROR;
		}

		pList->pElem= pNewBase;
		pList->iTotalLength= pList->iTotalLength + LISTINCREMENT;
	}

	q= &(pList->pElem[pos]); //q 指向的这个元素及其后面所有元素都需要后移一格
	for(p= &(pList->pElem[pList->iCount-1]) ; p>=q; p--)  //从后面往前,循环,每个元素后移一格,直到腾出要插入的内存空间。当pos=0时,全体所有数据都需要后移一格;当pos>=iCount时,全体数据都不需要后移
		*(p+1)= *p;

	*q= Value;  //实现插入操作
	pList->iCount++;  //元素增加,别忘了让有效长度值iCount加1――随时维护iCount值的准确性,以方便程序员即时读取,而不是在需要的时候才去数个数
	return 0;
}

//合并无序的顺序表  MergeOption:0 不允许重复  1允许重复
int DisorderSeqListMerge(SeqList *pListA, SeqList *pListB, int MergeOption, SeqList **pListC)
{
	int i, ret;

	if (pListA==NULL || pListA->pElem==NULL || pListB==NULL || pListB->pElem==NULL || MergeOption < 0 || MergeOption > 1 )
	{
		return PARAM_ERROR;
	}

	*pListC= (SeqList *)malloc( sizeof(SeqList));
	if (*pListC==NULL)
	{
		return MALLOC_ERROR;
	}

	(*pListC)->iTotalLength= pListA->iTotalLength + pListB->iTotalLength;
	(*pListC)->pElem= (Elemtype *)malloc( (*pListC)->iTotalLength * sizeof(Elemtype));  
	if ((*pListC)->pElem==NULL)
	{
		if ((*pListC) != NULL)
			free(*pListC);
		*pListC= NULL;
		return MALLOC_ERROR;
	}
	
	//将A表的数据依次复制到C表数据区
	for(i= 0; i<pListA->iCount; i++)
		(*pListC)->pElem[i]= pListA->pElem[i];
	(*pListC)->iCount= pListA->iCount;

	for (i=0; i<pListB->iCount; i++)
	{
		ret = SearchByValue(pListA, pListB->pElem[i]);
		if ( ret >= 0 && MergeOption==0) //现有重复的元素,且不允许重复
		{
			//什么都不做,不执行插入操作
		}
		else  //没找到,没有重复的元素
		{
			SeqListInsert(*pListC, (*pListC)->iCount, pListB->pElem[i]);  //将LB[i]插入到新表LC的末尾
		}
	}

	return 0;
}
 //测试代码,或者主程序代码,在测试InitList函数时,由你自己随意编写;在提交老板后,由项目经理或高级程序员负责编写
void main(void)
{
	int ret, i;
	SeqList List1, List2;              //内存中为List1这个结构体变量分配4+4+4=12个字节
	Elemtype myValue;
	Elemtype *pmyValue= &myValue;
	SeqList *pList1= &List1;    //内存中为pList1这个结构体指针变量分配4个字节         
	SeqList *pList3= NULL;
	//创建演示
	ret= InitList( &List1 );  //注意,InitList需要的是一个结构体变量的地址,故传&pList1
	if (ret==0)
		printf("创建空的顺序表成功!表的理论总长为%d,每次如果不够,自动增长值为%d", LIST_INIT_SIZE, LISTINCREMENT);
	else
	{
		printf("未能成功分配顺序表的数据存储空间,创建顺序表失败!");
		return;
	}

	ret= InitList( &List2 );  //注意,InitList需要的是一个结构体变量的地址,故传&pList2
	if (ret==0)
		printf("创建空的顺序表成功!表的理论总长为%d,每次如果不够,自动增长值为%d", LIST_INIT_SIZE, LISTINCREMENT);
	else
	{
		printf("未能成功分配顺序表的数据存储空间,创建顺序表失败!");
		return;
	}

	for (i= 0; i<5; i++)
	{
		SeqListInsert(pList1, i, (Elemtype)('H'-i));
	}
	for (i= 0; i<5; i++)
	{
		SeqListInsert(&List2, i, (Elemtype)('A'+i));
	}

	//访问演示
	ret= GetValue(&List1, 2, pmyValue);  //注意在Debug状态下看看*pmyValue的变化,理解数据传递的方向(从子函数给主调函数)
	if (ret==0)
		printf("你要读取表中第%d个元素,其值是%c", 2, *pmyValue); //主调函数使用子函数传出来的数据
	else
		printf("你要读取表中第%d个元素,本表不存在这个元素!", 2);

	//无序表的合并
	DisorderSeqListMerge(&List1, &List2, 1, &pList3);
	return;
}

java版本:

class person{
	public int ID;
	public String name;
	public person(int ID,String name) {
		this.ID = ID;
		this.name = name;
	}
}

public class Seqlist{

	static final int MAXSIZE = 20;
	static person []Element;
	static int Count;//线性表当前长度 
	
	//构造函数,线性表的初始化
	public Seqlist(int maxsize) {
		Count = 0;
		Element = new person[maxsize];
	}
	
	//取元素值
	static person Getvalue(int pos) throws Exception{
		if(Count == 0)
		{
			throw new Exception("为空表,查找失败");
		}
		else if(pos <= 0 || pos > Count)
		{
			throw new Exception("第"+pos+"个元素不存在");
		}
			return Element[pos - 1];
	}
	
	 //插入元素
	int Insert(int pos,person value) throws Exception{
		if(Count == MAXSIZE)
		{
			throw new Exception("表溢出!");
		}
		else if(pos <= 0 )
		{
			throw new Exception("插入位置错误");
		}
		for(int i = Count-1;i >= pos-1;i--)
		{
			Element[i+1] = Element[i];
		}
		Element[pos-1] = value;
		Count++;
		return 1;
	}
	
	//删除元素
	int Del(int pos) throws Exception{
		if(pos <= 0 || pos > Count)
		{
			throw new Exception("该元素不存在");
		}
		for(int i = pos;i <= Count;i++)
		{
			Element[i-1] = Element[i];
		}
		Count--;
		return 1;
	}
	
	//获取长度
	int ListLength() {
		return Count;
	}
	
	//清空表
	int ListClear() {
		Count = 0;
		return 1;
	}
	
	 //获得前驱
	static person GetPre(int pos) throws Exception{
		if(pos < 2 || pos > Count)
		{
			throw new Exception("前驱不存在");
		}
		return Element[pos - 2];
	}
	
	 //获得后驱
	static person GetNext(int pos) throws Exception{
		if(pos < 1 || pos > Count - 1)
		{
			throw new Exception("后驱不存在");
		}
		return Element[pos];
	}
	
	//显示链表
	void display() {
		System.out.println("当前表中一共有"+Count+"个元素,表中元素如下:");
		for(int i = 0;i < Count;i++)
		{
			System.out.println("ID:"+Element[i].ID+"  name:"+Element[i].name);
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		//创建并初始化线性表
		Seqlist list1 = new Seqlist(10);
		
		person[] data1 = new person[5];
		
		person p1 = new person(1,"张三");
		person p2 = new person(2,"李四");
		person p3 = new person(3,"王五");
		person p4 = new person(4,"李雷");
		person p5 = new person(5,"韩梅梅");
		
		data1[0] = p1;
		data1[1] = p2;
		data1[2] = p3;
		data1[3] = p4;
		data1[4] = p5;
		
		for(int i = 0;i <5;i++)
		{
			try {
				list1.Insert(list1.ListLength()+1,data1[i]);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		list1.display();
		System.out.println("顺序表初始化成功");
		System.out.println("表的长度为:"+list1.ListLength());
		System.out.println("表中第三个元素的值:");
		try {
			System.out.println("ID:"+Getvalue(3).ID+"  name:"+Getvalue(3).name);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("添加姓名为'刘备'的数据到位置二");
		person p6 = new person(6,"刘备");
		try {
			list1.Insert(2,p6);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		list1.display();
		System.out.println("删除位置四的数据");
		try {
			list1.Del(4);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		list1.display();
		System.out.println("位置二的前驱为:");
		try {
			System.out.println("ID:"+GetPre(2).ID+"  name:"+GetPre(2).name);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("位置二的后驱为:");
		try {
			System.out.println("ID:"+GetNext(2).ID+"  name:"+GetNext(2).name);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		list1.ListClear();
		System.out.println("清空线性表成功");
		System.out.println(list1.ListLength());
	}

}

41 单链表

翔哥代码:

/*
    适用于标准C
	LinkList.c
	无序单链表的实现代码
	V1.1――2016.9.20 by wangx
    v1.2――2017.9.7  by wangx
	v1.2.1――2017.9.10  by wangx
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //for memcpy

#define OK 1
#define OVERFLOW 0
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10


//公共错误码,项目组成员之间的共同约定
#define MALLOC_ERROR  -1  
#define NOTFIND  -2
#define PARAM_ERROR -3
#define REALLOC_ERROR  -4  
#define END_ID  0  

typedef struct  person
{
	long ID;           //4
	char name[20];     //20
}Elemtype;

//单链表的单个数据结点的类型定义
typedef struct NODE
{
	Elemtype	data;  //24
	struct NODE *next; //4 
}NODE, *pNODE;                 //如果定义数据结点的对象或变量,每个变量有24+4=28个字节

//单链表整体结构的类型定义
typedef struct LIST
{
	int	Count;                 //数据个数,即表长。该信息使用频繁,3种思路可做:1. 定义为pubblic权限的成员变量Count,增删清空等时候维护该变量,获取时直接以list1.Count的形式返回――有安全风险,且容易引发混乱,不提倡!
	                           //                                               2. 定义成成员方法getCount()的形式,调用方法,临时去计算并返回长度值。                           ――计算费时,不适合频繁使用,尤其是数据量很大的时候
	                           //                                               3. 定义为private权限的成员变量Count,增删清空等时候维护该变量,获取时用public权限的成员方法getCount()去读取该变量。――这是实际普遍使用的方式
	struct NODE *pHeadOfData;  //指向单链表表头的指针,即书上所说的head指针。必须是private权限的,不允许其他类的对象来修改这个成员的值,对使用链表的程序员透明(即:不需要知道它的存在)。指向表头结点,一旦创建了链表对象,在销毁之前永不变。
	//下面是不太重要或常用的一些成员,同学们可以自由发挥想一下,例如如下:
	int maxValue;              //一个并不成熟的设计,要求数据必须是可相互比较的类型,且删除后不好维护
	int minValue;
	struct NODE *pTailOfData;   //以方便快速定位到表尾结点(在数据的尾插法中可以用到)
	// ......
}LIST, *LINKLIST;              //如果定义对象,则每个对象有4+4+4+4=16个字节


/*****************************************************************
 *  函数名字:SearchByPos
 *	函数功能:查询指定的单链表中指定位置的元素,获得其数据结点的地址
 *	函数参数:pList ――指向某单链表对象的一级指针,要求非空
 *			  pos   ――所搜数据在表中的逻辑位置(编号从0开始)
 *			  ppNode――向主调函数传出(加一级指针)该表的第pos个结点的地址(一级指针),故此处需要用1+1=2级指针的参数类型
 *						如果没找到第pos个元素,则该参数返回NULL,即0x00000000
 *	函数返回:int型,0表示操作正常结束; -2(NOTFIND)表示没找到; -3(PARAM_ERROR)表示参数校验失败
 *	备    注:同学们可以自己写SearchByValue函数
 *			  该函数如果在类中,可设为public权限,开放
 */
//根据逻辑顺序值pos,在单链表pList中,将第pos个元素结点的地址值以参数形式传出。
int SearchByPos(LIST *pList, int pos, NODE **ppNode)
{
	int i;
	NODE *p;
	//参数校验
	if (pList==NULL)
	{
		return PARAM_ERROR;
	}

	i= 0;
	p= pList->pHeadOfData;
	while ( i<pos && p->next!= NULL) //当没有数到逻辑顺序的第i个结点 并且 还没有到表尾的时候,则
	{
		p= p->next;          //一边将p指针指向下一个结点
		i++;				 //一边计数
	}

	if ( i==pos ) // 如果 i== pos,即p指向第pos个元素了
	{
		*ppNode= p;    //如果是以“找到第pos个元素”的姿态跳出while循环
		return 0;
	}
	else  //如果是p->next== NULL,即以“到表尾”的姿态跳出while循环
	{
		*ppNode= NULL;
		return NOTFIND;
	}
}


/*****************************************************************
 *  函数名字:Insert
 *	函数功能:插入一个元素到指定的单链表中的指定位置后
 *	函数参数:pList――指向某单链表对象的一级指针,要求非空
 *			  value――需要添加或插入的元素的值,假定元素值是有效的; 可稍作改动,支持结构体变量类型
 *			  pos  ――需要插入的逻辑位置(之后),pos大于表长时视为“表尾追加元素”,pos<=0时视为“表头后插入元素”
 *	函数返回:int型,0表示操作正常结束
 *	备    注:本函数不对上层程序员开放。在无序表中,不需要指定插入的位置(因为无序表中元素的先后顺序并不重要。在Java或C++的有些类中,也提供了这种插入操作,主要是在指定位置之前插入。同学们可以自行设计和尝试改写下面代码)
 *			                            在有序表中,其该插入的位置是由其值的大小来决定的,无须指定插入位置pos;而且,有序表,主要都用在顺序表中,很少有用在单链表里的情况。查找很不方便哦!折半查找没法用!(作为练手,同学们可以尝试编写这个插入方法)
 *			  该函数如果在类中,可设为private权限,不开放
 */
int Insert(LIST *pList, Elemtype value, int pos)
{
	long len;
	int ret;
	struct NODE *pNew= NULL;
	struct NODE *pPre= NULL;
	//参数校验
	if (pList==NULL)
	{
		return PARAM_ERROR;
	}
	//参数调整
	len= pList->Count; //将长度信息读出来备用,len变量不定义也是可以的。
	if (pos >= len)
		pos= len;
	if (pos <0)
		pos= 0;

	//插入第一步:申请新结点空间
	pNew= (struct NODE *)malloc(sizeof(struct NODE));
	if (pNew==NULL)
	{
		return MALLOC_ERROR;
	}

	//插入第二步:填值到新结点空间,准备就绪
	memset(pNew, 0, sizeof(struct NODE));
	pNew->data.ID= value.ID; //此处不能直接写成pNew->data= value;
	memcpy(pNew->data.name, value.name, strlen(value.name));
	pNew->next= NULL;

	//插入第三步:找到第pos个结点,以备在其后插入新结点
	ret= SearchByPos(pList, pos, &pPre);
	if (ret== NOTFIND)
	{
		free(pNew);
		return NOTFIND;
	}

	//插入第四步:插入结点
	pNew->next= pPre->next;
	pPre->next= pNew;
	
	//插入第五步:长度值别忘了+1
	pList->Count++;

	return 0;
}

/*****************************************************************
 *  函数名字:AddToTail
 *	函数功能:往“无序”的线性“表尾”后面添加一个元素(即:在表尾追加一个元素结点)
 *	函数参数:pList――指向某单链表对象的一级指针,要求非空
 *			  value――需要添加的元素的值,假定元素值是有效的; 可稍作改动,支持结构体变量类型
 *	函数返回:int型,0表示操作正常结束
 *	备    注:该函数如果在类中,可设为public权限,开放给上层程序员使用
 */
int AddToTail(LIST *pList, Elemtype value)
{
	int len;
	len= pList->Count;
	return Insert(pList, value, len);
}

/*****************************************************************
 *  函数名字:AddToHead
 *	函数功能:往“无序”的线性“表头”后面添加一个元素结点
 *	函数参数:pList――指向某单链表对象的一级指针,要求非空
 *			  value――需要添加的元素的值,假定元素值是有效的; 可稍作改动,支持结构体变量类型
 *	函数返回:int型,0表示操作正常结束
 *	备    注:该函数如果在类中,可设为public权限,开放给上层程序员使用
 */
int AddToHead(LIST *pList, Elemtype value)
{
	return Insert(pList, value, 0); //在第一个元素之前(即:第0个元素之后)插入元素结点
}


/*****************************************************************
 *   函数名字:createList
 *	函数功能:创建一个空的带表头节点的单向链表
 *	函数参数:ppList――是一个2级指针,调用结束后*ppList指向一个单链表结构的对象
 *	函数返回:int型,0表示操作正常结束
 *  备    注:该函数如果在类中,可设为public权限,开放给上层程序员使用
 */
//创建一个带表头结点的链表,完成数据输入和串接
int createList(LIST **ppList)  //一般我们都将指向单链表第一个结点(或表头结点)的指针命名为head,这是习惯约定
{
	struct LIST *pNewList;
	struct NODE *pNewNode;
	if (ppList==NULL)              //参数校验,注意:此处校验的是ppList(不能为空,口袋必须要有!),不是*ppList(可以为NULL,表示有口袋,但是口袋里什么东西都没有)。
		return PARAM_ERROR;

	//创建一个表头结点,并用pNewList指向该空间
	pNewNode = (struct NODE *)malloc(sizeof(struct NODE));  //申请空间,注意:申请的是一个表结点的空间(28个字节)
	if (pNewNode==NULL)
	{
		return MALLOC_ERROR;
	}
	memset(pNewNode, 0, sizeof(struct NODE));
	pNewNode->next = NULL;  //空表,没有后续结点。表头结点的data域不需要处理,清0即可。另,养成良好习惯,当结点的next成员指向何方尚不明朗时,先置为NULL以防患于未然,避免野指针。


	//创建一个表对象的空间,并用pNewList指向该空间
	pNewList = (struct LIST *)malloc(sizeof(struct LIST));  //申请空间,注意:申请的是一个表对象的空间(16个字节),而不是一个表结点的空间(28个字节)
	if (pNewList==NULL)
	{
		free(pNewNode);     //在发生异常,准备退出之前,先把之前成功申请的pNewNode结点空间给释放了!这一点很多程序员容易忽略,造成内存泄露!
		return MALLOC_ERROR;
	}
	memset(pNewList, 0, sizeof(struct LIST));
	pNewList->Count= 0;   //设置该空表头的表长值为0
	pNewList->pHeadOfData = pNewNode;  //表对象的数据头指针指向刚才建好的表头结点。
	pNewList->pTailOfData = pNewNode;  //表对象的数据尾指针指向刚才建好的表头结点。空表,没数据,所以尾指针指向头结点。

	*ppList = pNewList;  //给表头指针赋值为表头结点的地址。
						 //这是套路,先用一个临时变量pNewList去操作数据,然后交付给*ppList

	return 0;            //本函数是如何返回表头指针的?又如何调用本函数呢?思考这2个问题!能画出内存四区图来么?
}

/*****************************************************************
 *   函数名字:createList2
 *	函数功能:创建一个单向链表,并填入数据,以尾插法实现结点挂接。
 *	函数参数:
 *	函数返回:LIST ** (函数运行结束之后,返回指向该表对象空间的一个2级指针)
 *  备    注:以前数据结构的老版本,没学过面向对象思想的人才会这么写
              这个方法不是面向对象的思想!不会成为单链表类的一个成员函数。写在这里,只是为了给同学们展示目前大多数教科书或考题中的一个不成熟的考法。
 */
//创建一个带表头结点的链表,并且完成数据输入和串接
int createList2(LIST **ppList)
{
	struct NODE *pNew;
	Elemtype Data;

	if (ppList==NULL)              //参数校验
		return PARAM_ERROR;

	createList(ppList);          //调用之前定义的函数,产生一个空表

	printf("请输入学生的5位证件号的值和姓名(空格隔开,ID值为0表示输入结束):");
	scanf("%ld", &(Data.ID));
	scanf("%s", Data.name);
	//创建并挂接后续的各个结点
	while (Data.ID != END_ID)  //程序员和用户已约定:当用户输入的数据为0(END_ID)时,表示数据录入的结束(注意,此约定不是唯一方法,仅供学习时适用)
	{
		//创建新的结点并赋值
		pNew = (struct NODE *)malloc(sizeof(struct NODE));  //申请空间
		if (pNew==NULL)
		{
			return MALLOC_ERROR;
		}
		memset(pNew, 0, sizeof(struct NODE));

		pNew->data.ID= Data.ID;    //为新结点的data域填入数据
		memcpy(pNew->data.name, Data.name, strlen(Data.name));
		pNew->next = NULL;           //为新结点的next域填入数据,指向不行时填入NULL;或因为其是新的表尾结点,所以也应该将其next域填入NULL表示链表在结尾。

		//将新结点挂接到原链表中,此步骤很关键!
		(*ppList)->pTailOfData->next = pNew;          //pTail专门指向链表当前的最后一个结点,此行代码实现了将新结点连入链表尾部(还记得王老师曾经讲过的指针赋值的那句口诀不?“指针的赋值如何看?等式左边的指针,指向等式右边指针所指向的东西”)
		(*ppList)->pTailOfData = pNew;                //pTail指向的结点已经不是链表的表尾结点了(挂接之后,pNew指向的结点才是新的表尾结点),故而刷新pTail,让其指向新的表尾结点。
		printf("请输入学生的5位证件号的值和姓名(空格隔开,ID值为0表示输入结束):");
		scanf("%ld", &(Data.ID));
		scanf("%s", Data.name);
	}
	return 0;     //本函数是如何返回一个表的?思考这个问题!
}

/*****************************************************************
 *  函数名字:output
 *	函数功能:输出单链表的所有结点数据,在屏幕上显示打印
 *	函数参数:pList――指向某单链表对象的一级指针,要求非空(有了它,我们就能顺藤摸瓜,找出所有数据)
 *	函数返回:无(这是一个打印或显示类型的函数,不需要返回任何数据)
 *  备    注:教学演示所用,并无实用
 */
void output(struct LIST *pList)
{
	struct NODE *p;
	if (pList==NULL)                 //参数如果不正确,则直接罢工
		return;
	p = pList->pHeadOfData->next;   //"顺藤",从pHeadOfData->next开始,跳过表头节点的Data域不打印
	while (p != NULL)               //到尾。注意,单链表的最后一个结点的next域的值为NULL,本块代码也是读取单链表的标准模板
	{
		printf("%6d  ", p->data.ID);  //"摸瓜"
		printf("%s\n",  p->data.name);
		p = p->next;                //千万别忘记本行代码,否则死循环了
	}
	return ;
}

/*****************************************************************
 *  函数名字:DelByPos
 *	函数功能:删除指定单链表中指定逻辑顺序位置的元素结点,并将删除的元素的值提取出来
 *	函数参数:pList ――指向某单链表对象的一级指针,要求非空
 *			  pos   ――需要删除的结点的逻辑序号(从0开始编号),pos大于表长或者pos<=0时视为“参数不合法”
 *			  pValue――指向被删除元素的值,以方便在有些应用场合中对其做死前最后可能的访问操作。
 *	函数返回:int型,0表示操作正常结束
 *	备    注:该函数如果在类中,可设为public权限,开放。同学们可以自行练习DelByValue函数。
 */
int DelByPos(struct LIST *pList, int pos, Elemtype *pValue)
{
	int ret;
	struct NODE *pDel= NULL;
	struct NODE *pPre= NULL;
	//参数校验
	if (pList==NULL)
	{
		return PARAM_ERROR;
	}
	//删除第一步:找到第pos-1个结点的地址,顺带着也就校验了pos值是否过大
	ret= SearchByPos(pList, pos-1, &pPre); //要删除第pos个元素,在链表这种结构中,需要获取到第pos-1个元素的地址,以方便删除操作
	if (ret== NOTFIND) //如果本来该表压根就没有第pos-1个元素,那无法完成删除,pos值过大!
	{
		return PARAM_ERROR;
	}

	//删除第二步:获取第pos个结点的地址并暂存该地址(函数的任务就是要删这个结点)
	pDel= pPre->next; 
	if (pDel==NULL)  //有第pos-1个结点,但恰好没有第pos个结点的情况,仍然归咎于pos参数传入错误
	{
		return PARAM_ERROR;
	}

	//删除第三步:将第pos个结点从链表中摘下来,使其脱离链表
	pPre->next= pPre->next->next;

	//删除第四步:(非必须的步骤)将该结点的值拷贝出来,以备上层函数可能使用
	pValue->ID= pDel->data.ID;
	memcpy(pValue->name, pDel->data.name, strlen(pDel->data.name));

	//删除第五步:释放pDel指针所指向的结点空间(在堆区),注意,并不是释放pDel指针变量本身这4个字节哦!free之后,pDel变量仍然存在!成为了一个野指针!
	free(pDel);
	pDel=NULL;  //指针复位操作。可以看出,pDel指针仍然存在,有值,但其指向的空间已被回收。为了避免误操作,特意将这4个字节的空间全部清0,即让pDel指针为NULL
	
	//删除第六步:长度值别忘了-1
	pList->Count--;

	return 0;
}

// 思考下面的这些操作应该怎么去设计参数和操作思想?
/*****************************************************************
 *  函数名字:clearList
 *	函数功能:清空一个单向链表的数据
 *	函数参数:pList――是一个指向表对象空间的1级指针。
 *	函数返回:int型,0表示操作正常结束
 *  备    注:只是清空操作,表对象仍然存在,只是没数据而已。所以表对象指针不会发生变化,没必要用二级指针,一级指针就能搞定。
 */
int clearList(LIST *pList)
{
	pNODE p,q;
	// 参数校验
	if(pList==NULL){
		return PARAM_ERROR;
	}
	// 做好循环控制并针对每个数据结点,释放结点空间。建议用while循环,想想循环结束条件是什么?
	p=pList->pHeadOfData->next;
	while(p){
		q=p->next;
		free(p);
		p=q;
	}
	// pHeadOfData指针复位
	pList->pHeadOfData->next=NULL;
	// 调整表长,恢复为0 ,此步骤千万别忘了!
	pList->Count=0;
	return 0;
}


/*****************************************************************
 *  函数名字:destroyList
 *	函数功能:销毁一个单向链表
 *	函数参数:ppList――是一个2级指针,因为要销毁空间,所以需要在函数内改变实参的值(往外传一个NULL),所以要用2级指针
 *	函数返回:int型,0表示操作正常结束
 *  备    注:
 */
int destroyList(LIST **ppList)
{
	pNODE p,q;
	// 参数校验
	if(ppList==NULL){
		return PARAM_ERROR;
	}
	// 清空数据并销毁数据
	p=(*ppList)->pHeadOfData->next;
	while(p){
		q=p->next;
		free(p);
		p=q;
	}
	// 释放表对象所占空间
	free((*ppList)->pHeadOfData);
//	free((*ppList)->pTailOfData);
	// 表对象指针复位
	*ppList=NULL;
	return 0;
}

/*****************************************************************
 *  函数名字:MergeList
 *	函数功能:将2个单链表进行无序合并,合并后不改变原有的2个表的数据。
 *	函数参数:pList1――指向某单链表对象1的一级指针,要求非空
 *			  pList2――指向某单链表对象2的一级指针,要求非空
 *	函数返回:int型,0表示操作正常结束
 *	备    注:
 */
//    int MergeList(LIST *pList1,   LIST *pList2)
//    int MergeList(LIST **ppList1, LIST *pList2)
// LIST * MergeList(LIST *pList1,   LIST *pList2)
//    ......



int main(void)
{
	int ret, pos;
	struct LIST *pList1;
//	struct LIST *pList2;
	Elemtype value;

	//创建链表1,并填入数据
	ret= createList(&pList1);     // 一定要看清楚此处的用法哦!pList1是一级指针,所以&pList1就是二级指针了(一级指针的地址,有些书上称之为二级指针类型了)!
	value.ID= 10;
	memset(value.name, 0, 20);
	memcpy(value.name,"汤唯", 4);
	AddToTail(pList1, value);

	value.ID= 20;
	memset(value.name, 0, 20);
	memcpy(value.name,"林志玲", 6);
	AddToTail(pList1, value);

	value.ID= 30;
	memset(value.name, 0, 20);
	memcpy(value.name,"关之琳", 6);
	AddToTail(pList1, value);

	value.ID= 40;
	memset(value.name, 0, 20);
	memcpy(value.name,"迪丽热巴", 8);
	AddToTail(pList1, value);

	output(pList1);  //输出显示单链表的所有数据
	
	printf("=========下面演示删除=====================\n");
	pos= 8;
	ret= DelByPos(pList1, pos, &value); //删除第8个。但是不存在第8个结点,删除失败,返回-1,放弃删除(你也可以编程实现让它在这种情况下(pos>count时)去删除最后一个结点来作为对用户的回应)
	if (ret== 0)
		printf("我删除了%s这个结点\n", value.name);
	else
		printf("我没法删除第%d个结点\n", pos);
	output(pList1);  //输出显示单链表的所有数据
	clearList(pList1);
	destroyList(&pList1);
	printf("okkk");
//	printf("=========下面用过时的创建函数演示一下========\n");
//	ret= createList2(&pList2); //用老方法来创建,在创建的同时就在插入元素,模块的划分有点混乱
//	output(pHead2);

	//同学们可以在下面针对上面写的所有函数自行添加测试代码去使用一下!
	// ......

	return 0;
}

Java版本:

//Java没有指针,用对象引用的方法
//单链表单个结点类型定义
class node{
	public int data;
	public node next;
	public node(int data) {
		this.data = data;
		this.next = null;
	}
	public node() {
		this.data = 0;
		this.next = null;
	}
}

public class Linklist{
	//错误代码
	static final int PARAM_ERROR = -1;
	static final int NOTFIND = -2;
	static final int OREADY = -3;
	private int count;
	private static node HeadofData;
	
	//创建一个带头结点的链表
	public Linklist() {
		HeadofData=new node(0);
		count = 0;
	}
	
	/**
	 * 获取单链表的长度
	 * @return
	 */
	public int length() {
		return count;
	}
	
	/**
	 * 在表尾插入一个结点
	 * @param pin 插入的结点
	 * @return
	 */
	public int AddtoTail(node pin) {
		return InsertbyPos(pin,count);
	}
	
	/**
	 * InsertbyPos:根据位置插入结点,如果位置大于链表长度,会插在链表尾
	 * @param pin 插入的结点
	 * @param pos 插入的位置
	 * @return
	 */
	public int InsertbyPos(node pin,int pos) {
		//参数校验
		if(HeadofData == null) {
			return PARAM_ERROR;
		}
		//极端情况,调整参数
		if(pos > count) {
			pos = count;
		}
		if(pos < 0) {
			pos = 0;
		}
		int i = 0;
		node p = HeadofData;
		while(i < pos) {
			i++;
			p = p.next;
		}
		pin.next = p.next;
		p.next = pin;
		count++;
		return 0;
	}
	
	/**
	 * 按位置查找结点
	 * @param pos 结点位置
	 * @return 返回结点上的数据
	 */
	public int SearchbyPos(int pos,node elem) {
		int i = 1;
		//参数校验
		if(HeadofData == null) {
			return PARAM_ERROR;
		}
		node p = HeadofData.next;
		while(i < pos && p.next != null) {
			p = p.next;
			i++;
		}
		if(i == pos) {
			elem.data = p.data;
			elem.next = p.next;
			return 0;
		}
		else {
			return NOTFIND;
		}
	}
	
	//表头添加一个结点
	int AddtoHead(node pin) {
		return InsertbyPos(pin,0);
	}
	
	//输出单链表中所有的数据
	void Output() {
		System.out.println("表中结点元素:");
		node p = HeadofData;
		p = HeadofData.next;
		while(p != null){
			System.out.print(p.data+" ");
			p = p.next;
		}
		System.out.println("\n");
	}

	/**
	 * 按位置删除
	 * @param pos 结点位置
	 * @param delelem 删除的结点
	 * @return
	 */
	int DelbyPos(int pos,node delelem) {
		//参数校验
		node previous = HeadofData;
		node current = HeadofData;
		if(HeadofData == null) {
			return PARAM_ERROR;
		}
		int flag = SearchbyPos(pos, delelem);
		if(flag == NOTFIND) {
			return NOTFIND;
		}
		//删除结点
		int i = 0;
		while(i < pos) {
			previous = current;
			current = current.next;
			i++;
		}
		previous.next = current.next;
		count--;
		return 0;
	}
	
	/**
	 * 链表排序
	 * @param moudle 1为从小到大,2为从大到小
	 * @return
	 */
	int order(int moudle) {
		//参数校验
		if(HeadofData == null) {
			return PARAM_ERROR;
		}
		int temp;
		node pNode = HeadofData;
		if(moudle == 1) {
			for(int i = 0;i < count;i++) {
				pNode = HeadofData.next;
				while(pNode.next != null) {
					if(pNode.data > pNode.next.data) {
						temp = pNode.data;
						pNode.data = pNode.next.data;
						pNode.next.data =temp;
					}
					pNode = pNode.next;
				}
			}
		}
		else {
			for(int i = 0;i < count;i++) {
				pNode = HeadofData.next;
				while(pNode.next != null) {
					if(pNode.data > pNode.next.data) {
						temp = pNode.data;
						pNode.data = pNode.next.data;
						pNode.next.data =temp;
					}
					pNode = pNode.next;
				}
			}
		}
		return 0;
	}
	
	/**
	 * 获取前驱结点
	 * @param pos
	 * @return
	 */
	public node GetPre(int pos) {
		node elem = new node();
		SearchbyPos(pos-1, elem);
		return elem;
	}
	
	//清空链表
	int clearlist() {
		if(HeadofData == null) {
			return OREADY;
		}
		HeadofData.next = null;
		return 0;
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Linklist plist1 = new Linklist();
		if(plist1.HeadofData == null) {
			System.out.println("创建单链表失败");
			System.exit(0);
		}
		node p1 = new node(6);
		plist1.AddtoTail(p1);
		node p2 = new node(8);
		plist1.AddtoTail(p2);
		node p3 = new node(10);
		plist1.AddtoTail(p3);
		node p4 = new node(3);
		plist1.AddtoTail(p4);
		node p5 = new node(13);
		plist1.AddtoTail(p5);
		System.out.println("单链表创建成功,表的长度为:"+plist1.length());
		plist1.Output();
		node elem1 = new node(); //存储查找到的结点
		plist1.SearchbyPos(3, elem1);
		System.out.println("第三个结点元素是:"+elem1.data);
		node elem2 = new node();
		plist1.DelbyPos(3, elem2);
		System.out.println("删除第三个结点上,结点元素为:"+elem2.data);
		plist1.Output();
		System.out.println("在三号位置后插入结点,元素为29");
		node p6 = new node(29);
		plist1.InsertbyPos(p6, 3);
		plist1.Output();
		System.out.println("在表头插入结点,元素为3");
		node p7 = new node(3);
		plist1.AddtoHead(p7);
		plist1.Output();
		plist1.order(1);
		System.out.println("将表中元素排序后");
		plist1.Output();
		node elem3 = plist1.GetPre(3);
		System.out.println("位置三的前驱为:"+elem3.data);
		plist1.clearlist();
		plist1.Output();
		System.out.println("链表清空成功");
	}

}

42 链表合并排序

题目描述

  已有a、b两个链表,每个链表中的节点包括学号、成绩,且a、b两个链表中的节点均按照学号升序排列。要求把两个链表合并,按照学号升序排列并输出。

样例输入

Please input n m:[1-100]
3 5
Please input 3 students' numbers and scores:
101 90
104 80
106 85
Please input 5 students' numbers and scores:
103 95
105 88
107 87
108 90
109 95

样例输出

Output:
The result is:
101 90
103 95
104 80
105 88
106 85
107 87
108 90
109 95

代码

///方法一:直接合并
#include <stdio.h>
#include <stdlib.h>

struct node {
    int num;
    int score;
    struct node * next;
};

int main()
{
    int n, m, i;
    struct node *heada, *taila, *headb, *tailb, *head, *tail, *p;
    heada = taila = headb = tailb = NULL;
    
    printf("Please input n m:[1-100]\n");
    scanf("%d%d", &n, &m);
    /* 读入a链表中的n个学生信息 */
    printf("Please input %d students' numbers and scores:\n", n);
    for (i = 0; i < n; i++) 
    {
        p = (struct node *)malloc(sizeof(struct node));
        scanf("%d%d", &p->num, &p->score);
        if (heada == NULL) 
        {
            heada = taila = p;
        } 
        else 
        {
            taila->next = p;
            taila = p;
        }
    }
    taila->next = NULL;
    /* 读入b链表中的m个学生信息 */
    printf("Please input %d students' numbers and scores:\n", m);
    for (i = 0;i < m;i++) 
    {
        p = (struct node *)malloc(sizeof(struct node));
        scanf("%d%d", &p->num, &p->score);
        if (headb == NULL) 
        {
            headb = tailb = p;
        } 
        else 
        {
            tailb->next = p;
            tailb = p;
        }
    }
    tailb->next = NULL;
    
    printf("Output:\nThe result is:\n");
    /* 合并两个链表 */
    /******start******/
    head=tail=NULL; 
	struct node *p1, *p2;
	p1=heada;
	p2=headb;
	while(p1!=NULL && p2!=NULL){
		if(p1->num < p2->num){
			if(head==NULL){
				head=tail=p1;
			}
			else{
				tail->next=p1;
				tail=p1;
			}
			p1=p1->next;
		}
		else{
			if(head==NULL){
				head=tail=p2;
			}
			else{
				tail->next=p2;
				tail=p2;
			}
			p2=p2->next;
		}
	}
	while(p1!=NULL){
		tail->next=p1;
		tail=p1;
		p1=p1->next;
	}
	while(p2!=NULL){
		tail->next=p2;
		tail=p2;
		p2=p2->next;
	}
	tail->next=NULL; 
    /******end******/
    /* 将合并后的链表进行输出 */
    p = head;
    while (p != NULL) 
    {
        printf("%d %d\n", p->num, p->score);
        p = p->next;
    }
    return 0;
}
//方法二:先合并,再使用冒泡排序
#include <stdio.h>
#include <stdlib.h>

struct node {
    int num;
    int score;
    struct node * next;
};

int main()
{
    int n, m, i;
    struct node *heada, *taila, *headb, *tailb, *head, *tail, *p;
    heada = taila = headb = tailb = NULL;
    
    printf("Please input n m:[1-100]\n");
    scanf("%d%d", &n, &m);
    /* 读入a链表中的n个学生信息 */
    printf("Please input %d students' numbers and scores:\n", n);
    for (i = 0; i < n; i++) 
    {
        p = (struct node *)malloc(sizeof(struct node));
        scanf("%d%d", &p->num, &p->score);
        if (heada == NULL) 
        {
            heada = taila = p;
        } 
        else 
        {
            taila->next = p;
            taila = p;
        }
    }
    taila->next = NULL;
    /* 读入b链表中的m个学生信息 */
    printf("Please input %d students' numbers and scores:\n", m);
    for (i = 0;i < m;i++) 
    {
        p = (struct node *)malloc(sizeof(struct node));
        scanf("%d%d", &p->num, &p->score);
        if (headb == NULL) 
        {
            headb = tailb = p;
        } 
        else 
        {
            tailb->next = p;
            tailb = p;
        }
    }
    tailb->next = NULL;
    
    printf("Output:\nThe result is:\n");
    /* 合并两个链表 */
    /******start******/
    //先合并
	head=heada;
	taila->next=headb;
	//然后使用排序算法
	struct node *p1;
	int temp1,temp2;
	for(p=head;p!=NULL;p=p->next){
		for(p1=p;p1->next!=NULL;p1=p1->next){
			if((p1->num) > (p1->next->num)){
				temp1=p1->num;
				temp2=p1->score;
				p1->num=p1->next->num;
				p1->score=p1->next->score;
				p1->next->num=temp1;
				p1->next->score=temp2;
			}
		}
	} 
    /******end******/
    /* 将合并后的链表进行输出 */
    p = head;
    while (p != NULL) 
    {
        printf("%d %d\n", p->num, p->score);
        p = p->next;
    }
    return 0;
}

43 链栈

翔哥代码

/*
 *  文件名:LinkStack.c
 *	链栈的实现
 *	版本:1.0
 *	时间:2016.09.26
 *	作者:wangx
 *	假定条件: 假设元素的基本类型为int,且每个元素只有一个整数信息需要压栈
 *			
*/

#include "malloc.h" 
#include "stdio.h"

#define PARAM_ERROR -1
#define MALLOC_ERROR -2

typedef  int TElemType;
typedef struct SNode
{
	TElemType data;
   struct SNode *next;
}StackNode;

typedef struct 
{
	StackNode *Top; //一重指针,指向栈顶结点
}LinkStack, *PLinkStack; //PLinkStack是二重指针,等效于LinkStack *
//此处定义了一个链栈类型,叫LinkStack,该结构只有一个数据成员,即一个指向栈顶结点的指针Top
//因为链栈中不设置表头结点,也不需要栈底指针,所以只有一个Top指针变量来指向栈顶元素即可。同学们可以自行添加栈的其他辅助信息到这个结构里面,例如栈的当前深度之类的

 //初始化链栈,只需要将Top指针置空即可
 //子函数内改变Top指针的值,故形参为二级指针
int InitStack(LinkStack **ppStack)
{
   if (*ppStack== NULL) //参数校验,该二级指针必须要指向主调函数中的一个LinkStack *类型的指针变量,即该二级指针指向的东西必须存在!
		return PARAM_ERROR;

	*ppStack= (LinkStack*)malloc(sizeof(LinkStack));
	(*ppStack)->Top= NULL;
	return 0;
}

int ClearStack(LinkStack *pStack)
{
	StackNode *pTemp, *pNext;

	if (pStack== NULL)
		return PARAM_ERROR; //栈如果不存在,返回错误码。注意,空栈的状态是允许的,即允许pStack->Top==NULL

	pTemp= pStack->Top;
	while(pTemp!= NULL)
	{
		pNext= pTemp->next; 
		free(pTemp);
		pTemp= pNext;
	}
	return 0;
}

//因为链栈无表头,所以清空和销毁操作是同样的操作
int DestroyStack(LinkStack **ppStack)
{
   if (*ppStack== NULL)
		return PARAM_ERROR; //栈如果不存在,返回错误码。注意,空栈的状态是允许的,即允许pStack->Top==NULL

	ClearStack(*ppStack);
	free(*ppStack);
	*ppStack= NULL;
	return 0;
}

int Push(LinkStack *pStack, TElemType Value)
 {
   StackNode *p;
   if (pStack== NULL)
		return PARAM_ERROR; //栈如果不存在,返回错误码。注意,空栈的状态是允许的,即允许pStack->Top==NULL
   p=(StackNode *)malloc(sizeof(StackNode));
   if(!p)
     return MALLOC_ERROR;
   p->data=Value;
   //头插法入栈  必须用头插法入栈
   p->next=pStack->Top;  
   pStack->Top=p;
   
   return 0;
 }

int Pop(LinkStack *pStack, TElemType *pValue)
{
	StackNode *p;
	if (pStack== NULL || pStack->Top == NULL || pValue==NULL) 
		return PARAM_ERROR; //空栈无数据可返回,返回错误码
	p= pStack->Top;  //临时指针指向栈顶结点
	pStack->Top= pStack->Top->next;  //调整栈顶指针,指向下一个结点(出栈后的新栈顶结点)

	*pValue= p->data;  //将原栈顶结点的数据值取出,返回给主调函数使用
	free(p);  //销毁原栈顶结点
	p=NULL;
	return 0;
}

//判断一个栈是否为空栈
int IsStackEmpty(LinkStack *pStack)
{
	if (pStack==NULL) //参数校验
		return PARAM_ERROR;

	if (pStack->Top == NULL) //如果是空栈
		return 1;  //空栈返回1
	else
		return 0;

}

int main()
{
	TElemType value;
	LinkStack *pStack;
	InitStack(&pStack);
	Push(pStack, 10);
	Push(pStack, 20);
	Push(pStack, 30);
	Push(pStack, 40);
//	DestroyStack(&pStack);

	while (!IsStackEmpty(pStack))
	{
		Pop(pStack, &value);
		printf("%d  ", value);
	}
	DestroyStack(&pStack);
	return 0;
}

44 循环队列

翔哥代码

//1. 循环队列为空:Q.rear=Q.front
//2. 循环队列满:Q.front=(Q.rear+1)   %   maxsize
//3. 求循环队列长度 (Q.rear-Q.front+maxsize)%maxsize
/*
 *  文件名:SeqQueue.c
 *	循环队列的实现
 *	版本:1.0
 *	时间:2016.06.26
 *	作者:wangx
 *	假定条件: 假设元素的基本类型为整数int
 *			
*/
//代码3. ---------顺序结构下的循环队列基本结构定义代码---------//
//文件名:SeqQueue.c
#include "stdio.h"
#include "malloc.h"

#define MAXQSIZE 10        //假定数组长度为10
typedef int QElemType;     //假定队列元素为比较简单的int型
typedef struct
{
    QElemType *base; //注意,连续存储空间需要在函数中动态申请,此处只是定义了指向该空间的指针
    int front; //队头指针,若队列不空,指向队列头元素的下标
    int rear;  //队尾指针,若队列不空,指向队列尾元素的下一个空位下标
}SeqQueue;

//代码3. ---------顺序结构下的“创建并初始化一个队列”操作算法代码---------//
//文件名:SeqQueue.c
//因为涉及到可能更改指向队列的指针值,所以采用二重指针ppQ为参数,以便返回
int InitQueue(SeqQueue **ppQ)
{ 
    //创建循环队列的基本结构,诞生base、front和rear
    *ppQ= (SeqQueue *)malloc(sizeof(SeqQueue));
    if (!*ppQ) return -1;
    //创建循环队列的数组载体结构,诞生base指向的数组空间
    (*ppQ)->base=(QElemType *)malloc(MAXQSIZE*sizeof(QElemType));
    if(!(*ppQ)->base)
    {
        free(*ppQ);
        return -1;
    }
    //front和rear相等,初始化设其都为0(也可以不从0开始)
    (*ppQ)->front=(*ppQ)->rear=0;
    return 0;
}

//代码3. ---------顺序结构下的“队列销毁”操作算法代码---------//
//文件名:SeqQueue.c
//因为涉及到可能更改指向队列的指针值,所以采用二重指针ppQ为参数,以便返回
int DestroyQueue(SeqQueue **ppQ)
{ /* 销毁队列Q,Q不再存在 */
   if((*ppQ)->base)
     free((*ppQ)->base);
   if(*ppQ)
     free(*ppQ);
   *ppQ= NULL;
   return 0;
}

//代码3. ---------顺序结构下的“清空队列”操作算法代码---------//
//文件名:SeqQueue.c
//函数要求队列本身是已存在的
int ClearQueue(SeqQueue *pQ)
{
    if (pQ==NULL) return -1;
    pQ->front=pQ->rear=0;    //注意,并不需要对数组中已存在的元素置为0或空
    return 0;
}

//代码3. ---------顺序结构下的“判断队列是否为空”操作算法代码---------//
//文件名:SeqQueue.c
//函数要求队列本身是已存在的,否则返回-1
//若队列pQ为空队列,则返回1,否则返回0
int QueueIsEmpty(SeqQueue *pQ)
{
    if (pQ== NULL) return -1;
    if(pQ->front==pQ->rear) /* 队列空的标志 */
        return 1;
    else
        return 0;
}

//代码3. ---------顺序结构下的"获取队列元素个数"操作算法代码---------//
//文件名:SeqQueue.c
//函数要求队列本身是已存在的,否则返回-1
int GetQueueLength(SeqQueue *pQ)
{
    int length;
    if (pQ== NULL) return -1;
    //循环队列中,rear的值有可能会小于front,故要加个MAXQSIZE再来取余
    length= (pQ->rear-pQ->front+MAXQSIZE)%MAXQSIZE;
    return length;
}

//代码3. ---------顺序结构下的"获取队头元素的值"操作算法代码---------//
//文件名:SeqQueue.c
//队列为空或者队列不存在,均返回-1,否则将队头元素的值存储到地址为pe的空间中,并返回0
int GetHead(SeqQueue *pQ,QElemType *pe)
{
    if (pQ== NULL) return -1;
    /* 若队列不空,则用e返回Q的队头元素,并返回0,否则返回-1 */
    if(pQ->front==pQ->rear) /* 队列空 */
        return -1;
    *pe=pQ->base[pQ->front];
    return 0;
}

//代码3. ---------顺序结构下的"进队列"操作算法代码---------//
//文件名:SeqQueue.c
//队列不存在,返回-1;队列满,返回-2;正常进队返回0
//注意此时进队元素是普通的值传递方式	
int EnQueue(SeqQueue *pQ, QElemType e)
{
    if (pQ== NULL) return -1;
    if((pQ->rear+1)%MAXQSIZE==pQ->front) //如果队列满,产生真上溢,放弃操作
        return -2;
    pQ->base[pQ->rear]=e;                //先填值,注意,入队列和front无关
    pQ->rear=(pQ->rear+1)%MAXQSIZE;      //再循环加1
    return 0;
}

//代码3. ---------顺序结构下的"出队列"操作算法代码---------//
//文件名:SeqQueue.c
//队列不存在,返回-1;队列空,返回-2;正常出队返回0
//注意此时出队元素pe采用的是参数的地址传递方式	
int DeQueue(SeqQueue *pQ,QElemType *pe)
{
    if (pQ== NULL) return -1;
    if(pQ->front==pQ->rear)              //如果队列为空,直接放弃操作
        return -2;
    *pe=pQ->base[pQ->front];             //先读值,出队列操作与rear无关
    pQ->front=(pQ->front+1)%MAXQSIZE;    //再循环加1
    return 0;
}

int main()
{
    SeqQueue *pQ;
    InitQueue(&pQ);
	DestroyQueue(&pQ);
	return 0;
}

45 链队列

翔哥代码

/*
 *  文件名:LinkQueue.c
 *	链队列的实现
 *	版本:1.0
 *	时间:2016.06.26
 *	作者:wangx
 *	假定条件: 假设元素的基本类型为int类型
 *			
*/

//链队列
#include "stdio.h"
#include "malloc.h"
 
typedef int QElemType;         //假设队列元素类型为int,读者可更换为其他类型

typedef struct QNode          //定义单向链表的结点类型名为QNode,并定义指向
{                             //这种类型的指针的类型名称为QueuePtr
    QElemType data;
    struct QNode *next;
}QNode, *QueuePtr;
/*将队头指针和队尾指针打包封装,定义出新的结构体类型,
  即链队列的数据类型,取名为LinkQueue
*/
typedef struct                
{
    QueuePtr front;           // 队头指针
    QueuePtr rear;            // 队尾指针
}LinkQueue;

//代码3. ---------链队列的创建和初始化操作---------//
//文件名:LinkQueue.c
//以指向LinkQueue结构体的二重指针ppQ为参数,在函数内构建B和C部分,实现关联
int InitQueue(LinkQueue **ppQ)
{ 
    (*ppQ)=(LinkQueue *)malloc(sizeof(LinkQueue));
    if(!(*ppQ))  return -1;
    (*ppQ)->front=(*ppQ)->rear=(QueuePtr)malloc(sizeof(QNode));
    if(!(*ppQ)->front)  return -2;
    (*ppQ)->front->next=NULL;
    return 0;
}

//代码3. ---------链队列的“判断是否为空”操作---------//
//文件名:LinkQueue.c
//以指向LinkQueue结构体的一重指针pQ为参数
// 如果参数有误,返回-1; 若Q为空队列,则返回1,否则返回0 
int QueueIsEmpty(LinkQueue *pQ)
{ 
    if (pQ==NULL) return -1;
    if(pQ->front==pQ->rear)
        return 1;
    else
        return 0;
}

//代码3. ---------链队列的“读取队头元素”操作---------//
//文件名:LinkQueue.c
//以指向LinkQueue结构体的一重指针pQ为参数
// 如果队列存在且非空,获取队头元素的值,以地址传递的方式通过e传出;如果参数有误,返回-1;  
int GetQueueHead(LinkQueue *pQ,QElemType *e)
{
    if(QueueIsEmpty(pQ)!=0)
        return -1;
    *e=pQ->front->next->data;
    return 0;
}

//代码3. ---------链队列的“入队列”操作---------//
//文件名:LinkQueue.c
//以指向LinkQueue结构体的一重指针pQ为参数
// 如果队列不存在或操作异常,返回负数; 反之,成功操作返回0  
int EnQueue(LinkQueue *pQ,QElemType e)
{ 
    QueuePtr R;
    if (pQ==NULL) return -1;
    // 为新进元素e申请结点空间,并让指针R指向。 
    R=(QueuePtr)malloc(sizeof(QNode));
    if(!R) return -2;          //内存申请失败,返回-2
    R->data=e;
    R->next=NULL;
    //进行入队的指针关联
    pQ->rear->next=R;
    pQ->rear=R;
    return 0;
}

//代码3. ---------链队列的“出队列”操作---------//
//文件名:LinkQueue.c
//以指向LinkQueue结构体的一重指针pQ为参数,参数pe为地址传递形式
//将队头元素用指针e返回;若是唯一元素,需调整rear指针
//如果队列不存在或队列为空,返回-1; 反之,成功操作返回0  
int DeQueue(LinkQueue *pQ,QElemType *pe)
{
    QueuePtr R;
    if (pQ==NULL) return -1;            //队列不存在,返回-1
    if(pQ->front==pQ->rear) return -2;  //队列为空,返回-2
        
    R=pQ->front->next;			        //令R指向表头后的第一个结点
    *pe=R->data;
    pQ->front->next=R->next;
    if(pQ->rear==R)                     //如果第一个结点也是最后一个结点
        pQ->rear=pQ->front;
    free(R);
    return 0;
}

//代码3. ---------链队列的“求队列长度”操作---------//
//文件名:LinkQueue.c
//以指向LinkQueue结构体的一重指针pQ为参数
int GetQueueLength(LinkQueue *pQ)
{
    QueuePtr p;
    int count=0;
    p=pQ->front;
    while(p!=pQ->rear)
    {
        count++;
        p=p->next;
    }
    return count;
}

//代码3. ---------链队列的“清空队列”操作---------//
//文件名:LinkQueue.c
//以指向LinkQueue结构体的一重指针pQ为参数
//清空后,front和rear指针均指向表头结点
int ClearQueue(LinkQueue *pQ)
{ /* 将Q清为空队列 */
    QueuePtr p,q;
	if (pQ==NULL) return -1;
    pQ->rear=pQ->front;    //rear指针归位
    p=pQ->front->next;     //p指针指向表中第一个数据结点
    pQ->front->next=NULL;  //表头结点的next域归位
    while(p!=NULL)         //循环释放每个数据结点的空间
    {
        q=p;
        p=p->next;
        free(q);
    }
    return 0;
}


//代码3. ---------链队列的销毁操作---------//
//文件名:LinkQueue.c
//以指向LinkQueue结构体的二重指针ppQ为参数
//在函数内先清空队列数据,然后销毁空队列的B、C部分,并归位队列指针
int DestroyQueue(LinkQueue **ppQ)
{ 
    if (ClearQueue(*ppQ)==-1) return -1;
    free((*ppQ)->front);
    free(*ppQ);
    ppQ= NULL;
    return 0;
}


int main()
{
	int k,flag;
	LinkQueue *pQ= NULL;
	InitQueue(&pQ);
	scanf("%d",&k);
	while(k != 0)
	{
		EnQueue(pQ,k);
		scanf("%d",&k);
	}
	while(QueueIsEmpty(pQ) != 1)
	{
		DeQueue(pQ,&k);
		printf("%d ",k);
	}
}

46 二分查找

样例输入

请输入10个单调递增的数:5 10 13 18 20 24 27 31 33 39
要查找的数:20

样例输出

20在4位置

代码

#include <stdio.h>
int BinarySearch(int *a,int n,int key);
int main(){
	int a[10],i,pos,key;
	printf("请输入10个单调递增的数:");
	for(i=0;i<10;i++){
		scanf("%d", &a[i]);
	}
	printf("要查找的数:");
	scanf("%d",&key);
	pos=BinarySearch(a,10,key);
	if(pos==-1){
		printf("找不要要查找的数\n"); 
	}
	else{
		printf("%d在%d位置\n",key,pos);
	} 
}
int BinarySearch(int *a,int n,int key){
	int low,high,mid;
	low=0;high=n-1;
	while(low<=high){
		mid=low+high/2;
		if(a[mid]<key){
			low=mid+1;
		}
		else if(a[mid]>key){
			high=mid-1;
		}
		else{
			return mid;
		}
	}
	return -1;
}

参考链接

  • https://blog.csdn.net/mrbourne/category_1925119.html
发布了41 篇原创文章 · 获赞 33 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_39293438/article/details/105327033