c程序设计语言笔记3

折半查找法:

#include <stdio.h>
#include <stdlib.h>
//折半查找函数

int binsearch();
main()
{
	int x,s[10] = {1,2,3,4,5,6,7,8,9,10};
	printf("Please input the number you want to find.\n");
	x = getchar() - '0';
	printf("x = s[%d]\n",binsearch(x,s,10));
	system("pause");
}

int binsearch(int x,int v[],int n)
{
	int low,high,mid;
	low = 0;high = n - 1;
	while(low <= high){
		mid = (low + high) / 2;
		if(x < v[mid])
			high = mid - 1;
		else if(x > v[mid])
			low = mid + 1;
		else 
			return mid;
	}
	return -1;
}

希尔排序(Shell Sort)是插入排序的一种。是针对直接插入排序算法的改进。该方法又称缩小增量排序,

希尔排序基本思想:

  先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

#include <stdio.h>
#include <stdlib.h>

//shell排序法

void shellsort();

main()
{
	int i, v[10] = {10,5,2,4,6,8,9,1,3,7};
	for(i = 0;i < 10;i++)
		printf("%d ",v[i]);
	printf("\n");
	shellsort(v,10);
	for(i = 0;i < 10;i++)
		printf("%d ",v[i]);
	system("pause");

}

//shellsort函数:按递增顺序对v[0]--v[n-1]排序
void shellsort(int v[],int n)
{
	int gap,i,j,temp;

	for(gap = n / 2;gap > 0;gap /= 2)
		for(i = gap;i < n;i++)
			for(j = i - gap;j >= 0 && v[j] > v[j + gap];j -= gap){
				temp = v[j];
				v[j] = v[j + gap];
				v[j + gap] = temp;
			}

}

 插入排序算法思路:

      假定这个数组的序是排好的,然后从头往后,如果有数比当前外层元素的值大,则将这个数的位置往后挪,直到当前外层元素的值大于或等于它前面的位置为止.这具算法在排完前k个数之后,可以保证a[1…k]是局部有序的,保证了插入过程的正确性.

算法描述:

一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:

  1. 从第一个元素开始,该元素可以认为已经被排序

  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描

  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置

  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置

  5. 将新元素插入到该位置中

  6. 重复步骤2

  (如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找排序。)

C代码   收藏代码
  1. void insertSort(char array[], int n)  
  2. {  
  3.     int i,j;  
  4.     int temp;  
  5.     for(i=0;i<n;i++)  
  6.     {  
  7.         temp=array[i];  
  8.         for(j=i; j>0 && temp<array[j-1];j--)  
  9.             array[j]=array[j-1];  
  10.         array[j]=temp;  
  11.     }  
  12. }  


练习3-3 编写函数expand(s1,s2),将字符串s1中类似于a-z一类的速记符号在字符串s2中还原。

#include <stdio.h>
#include <stdlib.h>
//wϰ3-3
void expand();

main()
{
	char s1[10] = "a-gddx-z";
	char s2[100];
	expand(s1,s2);
	printf("%s\n%s",s1,s2);
	system("pause");

}

//expand :expand shorthand notation in s1 into string s2
void expand(char s1[],char s2[])
{
	char c;
	int i,j;

	i = j =0;
	while((c = s1[i++]) != '\0')
		if(s1[i] == '-' && s1[i + 1] >= c){
			i++;
			while(c < s1[i])
				s2[j++] = c++;
		}else 
			s2[j++] = c;
	s2[j] = '\0';
}   

练习3-4,(这是一个纠结的问题)在数的对二的补码表示中,我们编写的itoa函数不能处理最大的负数,即n等于-2^(字长-1)的情况。请解释其原因。修改函数,使它能在任何机器上运行时都能打印出正确的值。

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

//itoa 处理最大的负数

#define abs(x)   ((x) < 0 ? -(x) : (x))
#define MAXCHAR  100

void reverse (char s[]);
void itoa (int n,char s[]);

main()
{
	int i = -2147483648,j;
	char s[MAXCHAR];
    for (j = 0;j < MAXCHAR;j++)
    {
        s[j]=0;
    }
	itoa(i,s);
	printf("%s\n",s);
	getch();
}

void reverse(char s[])
{
	int i,j,c;
	
	for(i = 0,j = strlen(s) - 1;i < j;i++,j--){
		c = s[i];
		s[i] = s[j];
		s[j] = c;
	}

}

void itoa(int n,char s[])
{
	int sign,i;
	sign = n;
	i = 0;
	do{
		s[i++] = abs(n) % 10 + '0';
	}while((n /= 10) != 0);

	if(sign < 0)
		s[i++] = '-';
	s[i] = '\0';
	reverse(s);
}   

另一种版本:

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

//itoa 处理最大的负数

#define abs(x)   ((x) < 0 ? -(x) : (x))
#define MAXCHAR  100

void reverse (char s[]);
void itoa (int n,char s[]);

main()
{
	int i = -2147483648,j;
	char s[MAXCHAR];
    for (j = 0;j < MAXCHAR;j++)
    {
        s[j]=0;
    }
	itoa(i,s);
	printf("%s\n",s);
	getch();
}

void reverse(char s[])
{
	int i,j,c;
	
	for(i = 0,j = strlen(s) - 1;i < j;i++,j--){
		c = s[i];
		s[i] = s[j];
		s[j] = c;
	}

}

void itoa(int n,char s[])
{
	int sign,i;
	sign = n;
	i = 0;
	do{
		s[i++] = abs(n) % 10 + '0';
	}while((n /= 10) != 0);

	if(sign < 0)
		s[i++] = '-';
	s[i] = '\0';
	reverse(s);
}   

Exercise 3-4 explanation: There are a number of ways of representing signed integers in binary, for example, signed-magnitude, excess-M, one's complement and two's complement. We shall restrict our discussion to the latter two. In a one's complement number representation, the binary represenation of a negative number is simply the binary representation of its positive counterpart, with the sign of all the bits switched. For instance, with 8 bit variables: 

                SIGNED  BINARY  UNSIGNED
                
                  25   00011001     25
                 -25   11100110    230

                 127   01111111    127
                -127   10000000    128

The implications of this are (amongst others) that there are two ways of representing zero (all zero bits, and all one bits), that the maximum range for a signed 8-bit number is -127 to 127, and that negative numbers are biased by (2^n - 1) (i.e. -I is represented by (2^n - 1) - (+I). In our example, so: 
                Bias = 2^8 - 1 = 255 = 11111111
                Subtract 25          = 00011001
                Equals               = 11100110

In a two's complement representation, negative numbers are biased by 2^n, e.g.: 
         Bias = 2^8  = 100000000
         Subtract 25 =  00011001
         Equals      =  11100111

In other words, to find the two's complement representation of a negative number, find the one's complement of it, and add one. The important thing to notice is that the range of an 8 bit variable using a two's complement representation is -128 to 127, as opposed to -127 to 127 using one's complement. Thus, the absolute value of the largest negative number cannot be represented (i.e. we cannot represent +128). Since the itoa() function in Chapter 3 handles negative numbers by reversing the sign of the number before processing, then adding a '-' to the string, passing the largest negative number will result it in being translated to itself: 
                 -128            : 10000000
                 One's complement: 01111111
                 Subtract 1      : 10000000

Therefore, because (n /= 10) will be negative, the do-while loop will run once only, and will place in the string a '-', followed by a single character, (INT_MIN % 10 + '0'). We can remedy these two bugs in the following way: 1 - change 'while ((n /= 10) > 0)' to 'while (n /= 10)'. Since any fractional part is truncated with integer division, n will eventually equal zero after successive divides by 10, and 'n /= 10' will evaluate to false sooner or later. 2 - change 'n % 10 + '0'' to 'abs(n % 10) + '0'', to get the correct character. EX3_4.C shows the revised function, which will run correctly regardless of the number representation. 

/*

  EX3_4.C
  =======
  
  Suggested solution to Exercise 3-4
  
*/
    
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>

void itoa(int n, char s[]);
void reverse(char s[]);

int main(void) {
    char buffer[20];
    
    printf("INT_MIN: %d\n", INT_MIN);
    itoa(INT_MIN, buffer);
    printf("Buffer : %s\n", buffer);
    
    return 0;
}

void itoa(int n, char s[]) {
    int i, sign;
    sign = n;
    
    i = 0;
    do {
        s[i++] = abs(n % 10) + '0';
    } while ( n /= 10 );
    if (sign < 0)
        s[i++] = '-';
    
    s[i] = '\0';
    reverse(s);
}

void reverse(char s[]) {
    int c, i, j;
    for ( i = 0, j = strlen(s)-1; i < j; i++, j--) {
        c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}

      

练习3-5 编写函数itob(n,s,b),将整数n转换为以b为底的数,并将转换的结果以字符形式保存到字符串s中。

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

//ex3.5

void reverse(char s[]);
void itob(int n,char s[],int b);

main()
{
	int n,b;
	char s[100];
	printf("Please input your number:\n");
	scanf("%d", &n);
	printf("Please input your base number:\n");
	scanf("%d,%d,%d", &b);
	itob(n,s,b);
	printf("\nThe string is %s",s);
	getch();

}

void itob(int n,char s[],int b)
{
	int i,j,sign;

	if((sign = n) < 0)
		n = -n;
	i = 0;
	do{
		j = n % b;
		s[i++] = (j <= 9) ? j + '0':j + 'a' - 10;
	}while((n /= b) > 0);
	if (sign < 0)
		s[i++] = '-';
	s[i] = '\0';
	reverse(s);

}

void reverse(char s[])
{
	int i,j,c;
	for(i = 0,j = strlen(s) - 1;i < j;i++,j--){
		c = s[i];
		s[i] = s[j];
		s[j] = c;
	}

}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值