数据结构PutList的c语言程序,数据结构(C语言版)第二章:数组与结构

2.1 ADT数组

先从一个最简单的程序开始:

#include

#define MAX_SIZE 100

float sum( float [], int );

float input[ MAX_SIZE ], answer;

int i;

int main( void )

{

for ( i = 0; i < MAX_SIZE; i++ ){

input[ i ] = (float)i;

}

answer = sum( input, MAX_SIZE );

printf("the sum is: %f\n", answer );

return 0;

}

float sum( float list[], int n )

{

int i;

float tempSum = 0;

for ( i = 0; i < n; i++ ){

tempSum += list[ i ];

}

return tempSum;

}

程序输出:

68afe829d726375c09b046715a71438b.png

1. 当数组作为参数传递进去的时候,只是将其地址传进去,所以我们无法获知数组的长度,需要将长度当作一个参数传递进去.

2. 良好的程序风格应该具有良好的编码,对齐等风格.

第二个程序:数组的地址:

#include

#include

int main( void )

{

int arr[ 5 ];

int i = 0;

memset( arr, 0, sizeof( int ) * 5 );

for ( i = 0; i < 5; i++ ){

printf("0x%u:%d\n", arr + i, *( arr + i ) );

}

return 0;

}

程序输出:

443726fd73ca54e65515d32a3cf73699.png

2.2 结构与共用体

#include

typedef struct PERSON{

charname[ 10 ];

intage;

floatsalary;

}Person;

int main( void )

{

Person person1 = { "voler", 24, 3500 };

Person person2 = person1;

printf("name:%s age:%d salary:%.2f\n", person2.name, person2.age, person2.salary );

return 0;

}

程序输出:

a889677e57b7e258f5cd2376dca5a74a.png

关于自引用结构的两种写法:

1.

#include

typedef struct LIST{

chardata;

struct LIST*link;

}List;

int main( void )

{

List item1, item2, item3;

List *list = &item1;

item1.data = 'a';

item2.data = 'b';

item3.data = 'c';

item1.link = &item2;

item2.link = &item3;

item3.link = NULL;

while ( NULL != list ){

printf("%c-->", list->data );

list = list->link;

}

printf("NULL\n");

return 0;

}

程序输出:

f920c48f416b5f4fe39b404806100109.png

2.

#include

typedef struct LIST{

chardata;

struct LIST*link;

}List;

int main( void )

{

List *item1 = ( List * )malloc( sizeof( List ) );

List *item2 = ( List * )malloc( sizeof( List ) );

List *item3 = ( List * )malloc( sizeof( List ) );

List *list = item1;

item1->data = 'a';

item1->link = item2;

item2->data = 'b';

item2->link = item3;

item3->data = 'c';

item3->link = NULL;

while ( NULL != list ){

printf("%c-->", list->data );

list = list->link;

}

printf("NULL\n");

free( item1 );

free( item2 );

free( item3 );

return 0;

}

程序输出:

840b2f754aee4eb736da8c95b4630915.png

不确定哪种写法更好.

2.3 ADT多项式

多项式的存储和计算,用一个程序来说明:

#include

#include

typedef struct POLYNOMIAL{

floatcoef;

intexpon;

}Polynomial;

#define MAX_TERMS 100

void padd( Polynomial [], Polynomial [], Polynomial [] );

int main( void )

{

Polynomial p1[ MAX_TERMS ], p2[ MAX_TERMS ], p[ MAX_TERMS ];

int i = 0;

memset( p1, 0, sizeof( Polynomial ) * MAX_TERMS );

memset( p2, 0, sizeof( Polynomial ) * MAX_TERMS );

memset( p, 0, sizeof( Polynomial ) * MAX_TERMS );

p1[ 0 ].coef = 2;

p1[ 0 ].expon = 1000;

p1[ 1 ].coef = 5;

p1[ 1 ].expon = 2;

p1[ 2 ].coef = 1;

p1[ 2 ].expon = 0;//2x^1000 + 5x^2 + 1

p2[ 0 ].coef = 1;

p2[ 0 ].expon = 4;

p2[ 1 ].coef = 10;

p2[ 1 ].expon = 3;

p2[ 2 ].coef = 3;

p2[ 2 ].expon = 2;

p2[ 3 ].coef = 1;

p2[ 3 ].expon = 0;//x^4 + 10x^3+3x^2+1

padd( p1, p2, p );

for ( i = 0; i < MAX_TERMS; i++ ){

if ( 0 == p[ i ].coef && 0 == p[ i ].expon ){

break;

}

printf("%.2fx^%d + ", p[ i ].coef, p[ i ].expon );

}

return 0;

}

void padd( Polynomial p1[], Polynomial p2[], Polynomial p[] )

{

while ( ( 0 != ( *p1 ).expon || 0 != ( *p1 ).coef ) && ( 0 != ( *p2 ).expon || 0 != ( *p2 ).coef ) ){

if ( ( *p1 ).expon > ( *p2 ).expon ){

*p = *p1;

p1++;

p++;

}else if ( ( *p1 ).expon < ( *p2 ).expon ){

*p = *p2;

p2++;

p++;

}else{

( *p ).coef = ( *p1 ).coef + ( *p2 ).coef;

( *p ).expon = ( *p1 ).expon;

p1++;

p2++;

p++;

}

}

while ( 0 != ( *p1 ).expon || 0 != ( *p1 ).coef ){

*p++ = *p1++;

}

while ( 0 != ( *p2 ).expon || 0 != ( *p2 ).coef ){

*p++ = *p2++;

}

}

指针是双刃剑,只有懂她的人才会明白她的美,虽然现在我还不太理解她.程序输出:

e8c44e995854c784b3af1fb76fbd94d4.png

2.4 ADT稀疏矩阵

#include

#include

#define MAX_TERMS 101

typedef struct TERM{

intcol;

introw;

intvalue;

}Term;

void transpose( Term [], Term [] );

void sortpose( Term [] );

int main( void )

{

Term a[ MAX_TERMS ], b[ MAX_TERMS ];

int i = 0;

memset( a, 0, sizeof( Term ) * MAX_TERMS );

memset( b, 0, sizeof( Term ) * MAX_TERMS );

a[ 0 ].col = 6;

a[ 0 ].row = 6;

a[ 0 ].value = 8;

a[ 1 ].col = 0;

a[ 1 ].row = 0;

a[ 1 ].value = 15;

a[ 2 ].col = 0;

a[ 2 ].row = 3;

a[ 2 ].value = 22;

a[ 3 ].col = 0;

a[ 3 ].row = 5;

a[ 3 ].value = -15;

a[ 4 ].col = 1;

a[ 4 ].row = 1;

a[ 4 ].value = 11;

a[ 5 ].col = 1;

a[ 5 ].row = 2;

a[ 5 ].value = 3;

a[ 6 ].col = 2;

a[ 6 ].row = 3;

a[ 6 ].value = -6;

a[ 7 ].col = 4;

a[ 7 ].row = 0;

a[ 7 ].value = 91;

a[ 8 ].col = 5;

a[ 8 ].row = 2;

a[ 8 ].value = 28;

transpose( a, b );

sortpose( b );

for ( i = 1; i <= b[ 0 ].value; i++ ){

printf("(%d,%d):%d\n", b[ i ].col, b[ i ].row, b[ i ].value );

}

return 0;

}

void transpose( Term a[], Term b[] )

{

int i = 0;

b[ 0 ].col = a[ 0 ].row;

b[ 0 ].row = a[ 0 ].col;

b[ 0 ].value = a[ 0 ].value;

for ( i = 1; i <= a[ 0 ].value; i++ ){

b[ i ].col = a[ i ].row;

b[ i ].row = a[ i ].col;

b[ i ].value = a[ i ].value;

}

}

void swap( Term *a, Term *b )

{

Term temp;

temp = *a;

*a = *b;

*b = temp;

}

void sortpose( Term b[] )

{

int i = 0;

int j = 0;

for ( i = 1; i < b[ 0 ].value; i++ ){

for ( j = i + 1; j <= b[ 0 ].value; j++ ){

if ( b[ i ].col > b[ j ].col ){

swap( &b[ i ], &b[ j ] );

}

}

}

}

程序输出:

e70f8e2871b1c2b3a3b1f332fbda1fa4.png

我之所以没按书上的方法来做矩阵的倒置,有以下原因:

1. 程序块的功能越简单越好.我封装的两个函数,一个用来倒置,一个用来排序.

2. 这样更容易扩展,如果程序要求以value的顺序排序,我只要修改一行代码即可(if那条判断比较语句)

当然,时间复杂度貌似是n的平方.书上有个例子,说明可以控制时间复杂度在常数时间内,代码如下:

书上的例子用到了一个编码小技巧,关于数组索引的技巧,很好用,但书上是以列作为排序的:

#include

#include

#define MAX_TERMS 101

typedef struct TERM{

intcol;

introw;

intvalue;

}Term;

void fast_transpose( Term [], Term [] );

int main( void )

{

Term a[ MAX_TERMS ], b[ MAX_TERMS ];

int i = 0;

memset( a, 0, sizeof( Term ) * MAX_TERMS );

memset( b, 0, sizeof( Term ) * MAX_TERMS );

a[ 0 ].col = 6;

a[ 0 ].row = 6;

a[ 0 ].value = 8;

a[ 1 ].col = 0;

a[ 1 ].row = 0;

a[ 1 ].value = 15;

a[ 2 ].col = 0;

a[ 2 ].row = 3;

a[ 2 ].value = 22;

a[ 3 ].col = 0;

a[ 3 ].row = 5;

a[ 3 ].value = -15;

a[ 4 ].col = 1;

a[ 4 ].row = 1;

a[ 4 ].value = 11;

a[ 5 ].col = 1;

a[ 5 ].row = 2;

a[ 5 ].value = 3;

a[ 6 ].col = 2;

a[ 6 ].row = 3;

a[ 6 ].value = -6;

a[ 7 ].col = 4;

a[ 7 ].row = 0;

a[ 7 ].value = 91;

a[ 8 ].col = 5;

a[ 8 ].row = 2;

a[ 8 ].value = 28;

fast_transpose( a, b );

for ( i = 1; i <= b[ 0 ].value; i++ ){

printf("(%d,%d):%d\n", b[ i ].col, b[ i ].row, b[ i ].value );

}

return 0;

}

void fast_transpose( Term a[], Term b[] )

{

introw_terms[ MAX_TERMS ], starting_post[ MAX_TERMS ];

inti, j, num_cols = a[ 0 ].col, num_terms = a[ 0 ].value;

b[ 0 ].row = num_cols;

b[ 0 ].col = a[ 0 ].row;

b[ 0 ].value = num_terms;

if ( num_terms > 0 ){

for ( i = 0; i < num_cols; i++ ){

row_terms[ i ] = 0;

}

for ( i = 1; i <= num_terms; i++ ){

row_terms[ a[ i ].col ]++;

}

starting_post[ 0 ] = 1;

for ( i = 1; i < num_cols; i++ ){

starting_post[ i ] = starting_post[ i - 1 ] + row_terms[ i - 1 ];

}

for ( i = 1; i <= num_terms; i++ ){

j = starting_post[ a[ i ].col ]++;

b[ j ].row = a[ i ].col;

b[ j ].col = a[ i ].row;

b[ j ].value = a[ i ].value;

}

}

}

程序输出:

dcd4be16c00e36ea6b285284916ed62d.png

矩阵的乘法:

书上代码有误,此题先放着.

2.5 多维数组

数组下标为负数的小程序:

#include

int main( void )

{

int a[ 20 ];

int *b = NULL;

int i = 0;

for ( i = 0; i < 20; i++ ){

a[ i ] = i;

}

b = a + 10;

for ( i = -10; i < 10; i++ ){

printf("%d ", *( b + i ) );

if ( 0 == ( ( i + 11 ) % 5 ) ){

printf("\n");

}

}

return 0;

}

程序输出:

2c9ff139ed2d050ed1331a2270239450.png

2.6 ADT字符串

说明字符串和字符数组不同的小例子:

#include

int main( void )

{

char *s1 = "hello world";

char s2[] = { "hello world" };

s2[ 1 ] = 'a';

s1[ 1 ] = 'a';

printf("%s\n", s1 );

printf("%s\n", s2 );

return 0;

}

实际上运行出错.对于C语言熟悉的人会知道字符串是不能改变的,所以你不能对s1进行任何的修改.

例2-2:字符串的插入

自己写的小程序:

#include

#include

#include

#define MAX_SIZE 100

void strnins( char *s, char *t, int i );

int main( void )

{

char str1[MAX_SIZE] = "amobile";

char str2[MAX_SIZE] = "uto";

strnins( str2, str1, 1 );

printf("%s\n", str1 );

return 0;

}

void strnins( char *s, char *t, int i )

{

char *begint = ( char * )malloc( sizeof( char ) * MAX_SIZE );

char *result = t;

strcpy( begint, t );

while ( i-- ){

result++;

begint++;

}

while ( *s ){

*result++ = *s++;

}

while ( *begint ){

*result++ = *begint++;

}

*result = '\0';

}

程序输出:

3d3577a57c8be64c29b8992fa3a33444.png

不过貌似不好,看看书上怎么写:

结果书上的效率一样,思想一样就是了,只是用到了一堆的strncpy,strcat等.不过书上的某种写法让我学习到了不用动态分配的手法(我一直不太想用malloc):

char str[ MAX_SIZE ], *temp = str;

2.6.2 模式匹配

简单的模式匹配用到strstr函数:

#include

#include

int main( void )

{

char *str1 = "hello world";

char *str2 = "wor";

char *str3 = "worr";

if ( strstr( str1, str2 ) ){

printf("str2 in str1\n");

}

else{

printf("str2 not in str1\n");

}

if ( strstr( str1, str3 ) ){

printf("str3 in str1\n");

}

else{

printf("str3 not in str1\n");

}

return 0;

}

程序输出:

a37e64f13fbe5eb1ecfb5d6a7bf04c0e.png

但是效率到很低,如果非常重视性能的话,可以考虑自己写(之前自己也写过,如下):

#include

#include

int nfind( char *string, char *pat );

int main( void )

{

char *str1 = "hello world";

char *str2 = "wor";

char *str3 = "worr";

if ( nfind( str1, str2 ) ){

printf("str2 in str1\n");

}

else{

printf("str2 not in str1\n");

}

if ( nfind( str1, str3 ) ){

printf("str3 in str1\n");

}

else{

printf("str3 not in str1\n");

}

return 0;

}

int nfind( char *string, char *pat )

{

char *tempString = string;

char *tempPat = pat;

int lenPat = strlen( pat );

while ( *( string + lenPat ) ){

while ( *string == *pat && *pat ){

string++;

pat++;

}

if ( !*pat ){

return string - tempString;

}

else{

pat = tempPat;

}

string++;

}

return 0;

}

程序输出:

89558f6e838955d1acc30585f863d109.png

书上也用到了这类思想,但是是用数组实现的,也方便实际上.但现在是学习指针的情形,所以能用指针尽量用指针.而且我发现自己的这种算法也是在常数运行时间内啊.

但实际上这是错误的一段程序,如果str1是"aaabb",而pat是"aabb",则根本无法正确查找,这段程序差的就是KMP算法中的失配函数:

著名的KMP算法:

失配函数:

void fail( char *pat )

{

int i = 0;

int j = 0;

int n = strlen( pat );

failure[ 0 ] = -1;

for ( j = 1; j < n; j++ ){

i = failure[ j - 1 ];

while ( ( pat[ j ] != pat[ i + 1 ] ) && ( i >= 0 ) )

i = failure[ i ];

if ( pat[ j ] == pat[ i + 1 ] )

failure[ j ] = i + 1;

else

failure[ j ] = -1;

}

}

假设pat为"abcabcacab",则failure数组为-1,-1,-1,0,1,2,3,-1,0,1.

整个函数罗列如下:

#include

#include

#define MAX_SIZE 100

int failure[ MAX_SIZE ];

void fail( char *pat );

int pmatch( char *string, char *pat );

int main( void )

{

int count = 0;

count = pmatch( "hello world", "wor" );

printf("%d\n", count );

count = pmatch( "hello world", "worr" );

printf("%d\n", count );

count = pmatch( "aaabb", "aabb" );

printf("%d\n", count);

return 0;

}

int pmatch( char *string, char *pat )

{

int i = 0, j = 0;

int lens = strlen( string );

int lenp = strlen( pat );

fail( pat );

while ( i < lens && j < lenp ){

if ( string[ i ] == pat[ j ] ){

i++;

j++;

}

else if ( 0 == j ){

i++;

}

else{

j = failure[ j - 1 ] + 1;

}

}

return ( ( j == lenp ) ? ( i - lenp ) : -1 );

}

void fail( char *pat )

{

int i = 0;

int j = 0;

int n = strlen( pat );

failure[ 0 ] = -1;

for ( j = 1; j < n; j++ ){

i = failure[ j - 1 ];

while ( ( pat[ j ] != pat[ i + 1 ] ) && ( i >= 0 ) )

i = failure[ i ];

if ( pat[ j ] == pat[ i + 1 ] )

failure[ j ] = i + 1;

else

failure[ j ] = -1;

}

}

程序输出:

0d20008096f5e11d35500ba77217104e.png

程序大概能理解,但是要我写,写不出来.

关于字符串的习题,做做.现在附加习题先不碰:

备注:以下程序并不进行错误的判断,比如无理的一堆输入.

习题1:不同字符的出现频率:

#include

#include

#include

/*

小程序,只计算小写字符串

*/

void frequency( char *s, int *arr );

int main( void )

{

int arr[ 26 ];

int i = 0;

int ch = 'a';

memset( arr, 0, sizeof( int ) * 26 );

frequency( "hello world", arr );

for ( i = 0; i < 26; i++ ){

printf("%c-->%d ", ch, arr[ i ] );

ch++;

if ( ( i + 1 ) % 5 == 0 ){

printf("\n");

}

}

}

void frequency( char *s, int *arr )

{

while ( *s ){

arr[ *s - 'a' ]++;

s++;

}

} 记住:char本身就是int.程序输出:

83313ff6555bb1def25912ece41dcac1.png

2. 删除子字符串

#include

#include

void strndel( char *str, int start, int length );

int main( void )

{

char str[] = "hello world";

strndel( str, 2, 3 );

printf("%s\n", str );

return 0;

}

void strndel( char *str, int start, int length )

{

char *tempStr = str;

while ( start-- ){

tempStr++;

str++;

}

while ( length-- && *str ){

str++;

}

while ( *str ){

*tempStr++ = *str++;

}

*tempStr = '\0';

}

程序输出:

406c7a4fc87871f489ef5521662f86a5.png

3. 删除特定字符后面的字符串

#include

#include

char *strdel( char *s, char ch );

int main( void )

{

char *str = "hello world";

printf("%s\n", strdel( str, 'l' ) );

return 0;

}

char *strdel( char *s, char ch )

{

while ( *s != ch && *s ){

s++;

}

return s;

}

程序输出:

03ef184f5d5fb2ee21402191c3a4aeb2.png

4. 字符首次出现位置的索引:

#include

#include

int strpos1( char *str, char ch );

int main( void )

{

char *str = "hello world";

printf("%d\n", strpos1( str, 'l' ) );

printf("%d\n", strpos1( str, 'm' ) );

return 0;

}

int strpos1( char *str, char ch )

{

char *tempStr = str;

while ( *str != ch && *str ){

str++;

}

if ( *str ){

return str - tempStr;

}

return -1;

}

程序输出:

41fd075d13aa84e69e133d9a6fa63e03.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值