《程序设计实践》第05练——指针Part(2/2)

**

《程序设计实践》第05练——指针Part(2/2)

  1. 指针——字符串1
    1.1. 学生模拟题:SC6_4B.cpp(本题15分)

【题目描述】 将字符串中的正、负整数取出求和。如字符串“w&sk234 K3wzm3455kdf43dkf-56slk%9” 中正、负整数取出的和=234+3+3455+43-56+9=3688,程序运行后输出3688。

**注意:
(1)需要考虑字符串中出现的正负号(+, -),即所有转换结果为正或负整数。
(2)空格为字符串的有效字符、不能忽略。例如,字符串"-□345.123"(□表示空格)应转换为-0,345,123三个整数,而不是-345和123两个整数!
(3)需要考虑’0’开始的数字字符串情况,比如"00035",应转换为整数35;"000"应转换为整数0;"00.0035"应转换为整数0和35(忽略小数点:mmm.nnn当成两个数mmm和nnn来识别)。
(4)不考虑转换后整数超出范围情况,即测试用例中可能出现的最大整数不会超过unsigned int可处理的范围;
(5)输入字符串不会超过100 Bytes,请不用考虑超长字符串的情况。
打开SC6_4B.cpp文件,完成程序的编写。
【输入】
输入文件SC6_4B.in有1行,一个字符串。
【输出】
输出文件SC6_4B.out有1个整数,是字符串中所有正、负整数的和。
【输入输出样例1】
SC6_4B.in SC6_4B.out
w&sk234 K3wzm3455kdf43dkf-56slk%9 3688
【输入输出样例2】
SC6_4B.in SC6_4B.out
w&- 123sk0400dkf-12.3slk%-876 -362
【数据限制】
0≤字符串长度≤1000;-1010≤输出结果≤1010。

在这里插入代码片
#include "stdio.h"
#include "string.h"
int  sumInt( char *s ){
	int sum=0, t=0, sign;	//sum-正负整数之和; t-字符串中的整数; sign-字符串中的正负号
	char *p=s;				//p-指向字符串的指针(遍历字符串)
	bool inNumber=false;	// 用于表示当前*p是否为数字, 默认情况下:不是
	//******************************************
	while(*p){
		if(!inNumber && *p>='0' && *p<='9'){          //(1)由非数字状态转入数字状态
			/*(1.1)*/
			inNumber = true;
			t = 0;

			/*(1.2)正负整数 符号控制*/
			if(p>s && *(p-1)=='-'){//判断前一个字符是否为'-'
				sign = -1;
			}else{
				sign = 1;
			}
		}

		if(inNumber && (*p < '0' ||  *p > '9')){     //(2)由数字状态转入非数字状态
			inNumber = false;
			sum += t * sign;
		}
		
		if(inNumber){							     //(3)累加当前数字状态的那个整数
			t = t*10 + (*p-'0');
		}
		
		p++;										//(4)字符串序列的下一个'字符'
	}
    
	//字符串序列->串尾字符为数字字符(整数)
	if(inNumber){
		sum += t * sign;
	}
	//==========================================
	return sum;
}

int main(){
	char s[1000+1];                    //a字符串数组
	
	FILE *fp;
	if((fp=fopen("SC6_4B.in", "r")) != NULL ){
		fclose(fp);  //存在的话,要先把之前打开的文件关掉
		
		freopen("SC6_4B.in", "r", stdin);
		freopen("SC6_4B.out", "w", stdout);
	}
	
	gets(s);                        //输入字符串
	printf("%d\n", sumInt(s));		//调用函数sumInt(s),并输出字符串中的正、负整数的和
	return 0;
}

1.2. 拓展题:SC6_4C.cpp(本题15分)

【题目描述】 求2个大正整数之和。打开SC6_4C.cpp文件,完成程序的编写。

【输入】
输入文件SC6_4C.in有2行,每行是1个大正整数。
【输出】
输出文件SC6_4C.out有1个整数,是上面2个大整数的和。
【输入输出样例1】
SC6_4C.in SC6_4C.out
45656834234234095782376907905623
93890352982340549798035 45656834328124448764717457703658
【输入输出样例2】
SC6_4C.in SC6_4C.out
457830640354181320210024
15499999951351567434165464541155 15500000409182207788346784751179
【数据限制】
0≤数字长度≤500。
【思考与扩展】
(1)两个相加的正整数有符号(正号’+’、负号’-’);
(2)两个大(正负)整数的加、减、乘、除四则运算的实现;
(3)任意两个数字(整数、浮点数)的加、减、乘、除四则运算的实现;

在这里插入代码片
#include "stdio.h"
#include "string.h"
const int N0=500;

int longIntegerSum( char a[], char b[], int c[] ){
	char *pa, *pb;	//pa,pb-指向两个大正整数字符串序列的指针;
	int *pc, len;	//pb-指向 两大正整数字之和数组int c[]的指针; len-相加结果的位数
	pa=a+strlen(a)-1; 	// pa指向第一个正整数的最低位 
	pb=b+strlen(b)-1; 	// pb指向第二个正整数的最低位 
	//******************************************
	pc = c;	//指针pc指向和数组c
	int carry = 0;	//是否有进位? 1-yes;0-no

	while(pa>=a || pb>=b){		//只要还有数位没处理,则一直循环下去.....
		if(pa >= a && pb >= b){	//【1】两个加数相应位置上都还有值....
			if(carry){	//if(carry==1){ //低位->有进位
				if(((*pa-'0') + (*pb-'0') +1 ) > 9 ){	//当前位相加后-->产生进位
					*pc = ((*pa-'0') + (*pb-'0') + 1) % 10;
					carry = 1;
				}else{
					*pc = (*pa-'0') + (*pb-'0') + 1;	//当前位相加后-->'不'产生进位
					carry = 0;
				}
			}else{	//低位->没有进位
				if(((*pa-'0') + (*pb-'0')) > 9 ){	//当前位相加后-->产生进位
					*pc = ((*pa-'0') + (*pb-'0')) % 10;
					carry = 1;
				}else{
					*pc = (*pa-'0') + (*pb-'0');	//当前位相加后-->'不'产生进位
					carry = 0;
				}
			}

			pa--;	//第1个加数往高位移1位
			pb--;	//第2个加数往高位移1位
			pc++;	//和指针往后移动1位
		}else if(pa < a){	//【2】第1个加数pa较短,已经没值了,只需要累加第2个加数后面的高位....
			while(pb >= b){
				if(carry == 1){//此位的低1位-->有进位
					if( ((*pb - '0')+1) > 9){
						*pc = ((*pb - '0')+1) % 10;
						carry = 1;
					}else{
						*pc = *pb - '0' +1;
						carry = 0;
					}
				}else{//没有进位
					*pc = *pb - '0';
					//carry = 0;
				}

				pc++;	//和指针往后移动1位
				pb--;	//第2个加数往高位移1位
			}
		}else if(pb < b){	//【3】第2个加数pa较短,已经没值了,只需要累加第1个加数后面的高位....
			while(pa >= a){
				if(carry == 1){//此位的低1位-->有进位
					if( ((*pa - '0')+1) > 9){
						*pc = ( (*pa - '0')+1 ) % 10;
						carry = 1;
					}else{
						*pc = (*pa - '0')+1;
						carry = 0;
					}
				}else{//没有进位
					*pc = *pa - '0';
					//carry = 0;
				}
				
				pc++;	//和指针往后移动1位		
				pa--;	//第1个加数往高位移1位
			}
		}
	}
	
	/*(2)求两大整数相加结果的位数*/
	len = pc - c;

	//==========================================
	return len;
}

int main(){
	char a[N0+1], b[N0+1];  // 用两个字符数组存放两个加数(大正整数)
    int c[N0+5]={ 0 }, *pc, len; // 变量len表示相加结果的位数 
	// 用一个整型数组存放两数相加的和,c[0]存放最低位,c[len-1]存放最高位 
	
	FILE *fp;
	if((fp=fopen("SC6_4C.in", "r")) != NULL ){
		fclose(fp);  //存在的话,要先把之前打开的文件关掉
		
		freopen("SC6_4C.in", "r", stdin);
		freopen("SC6_4C.out", "w", stdout);
	}
	
    gets(a);	//输入第一个加数(大正整数1)
    gets(b);	//输入第二个加数(大正整数2)

    len=longIntegerSum( a, b, c);	//调用函数计算a+b的和c, 结果以低位到高位'倒序(反序)'的方式存储在c中

    for(pc=c+len-1; pc>=c; pc--){	//输出结果-两个加数(大正整数)之和==>低位到高位'倒序(反序)'存储
		printf("%d", *pc);
	}
    printf("\n");

    return 0;	
}
  1. 指针——字符串2
    2.1. 学生模拟题:SC6_5B.cpp(本题15分)
    **

【题目描述】 在主字符串中删除所有子字符串。打开SC6_5B.cpp文件,完成程序的编写

**。
【输入】
输入文件SC6_5B.in有2行,第1行是主字符串,第2行是子字符串。
【输出】
输出文件SC6_5B.out有1行,即删除所有子字符串后的主字符串。
【输入输出样例1】
SC6_5B.in SC6_5B.out
hyuaaaabcad;dsj2390aaabcadldkaaaaabcaaabcade
aaabcad hyua;dsj2390ldkaaaaabce
hyua;dsj2390ldkaaaaabcaaabcade
【输入输出样例2】注意此例运行结果!
SC6_5B.in SC6_5B.out
123aaaaaaaabcaabcbcaabcbcbcbc567
aabc 123bc567
【输入输出样例3】
SC6_5B.in SC6_5B.out
123aaaaaaaabcaabcbdecaabcbrgcjkaabc
aabc 123aaaaaabdecbrgcjk
【数据限制】
0≤字符串长度≤1000。

在这里插入代码片
#include "stdio.h"
#include "string.h"
const int N0=1000;

char *index( char *s, char *sub ){ //在s中查找sub,找到则返回首字符地址,找不到则返回空(0)
	//int i=0, j=0;	  //i,j-循环控制(游标)变量
	char *p=sub;	  //子字符串
	if( *sub=='\0' )  //字符串为空? 若空则非法,退出程序.
		return NULL;
	//******************************************
	while( *s){ //while( *s && ( strlen(s) >= strlen(p) ) ){	//主串非空, 且主串比子串'长',才有搜索的必要
		if(*p == '\0'){	//若已达到子串的末尾, 则匹配成功, 在主串中找到子串
			//s = s - (p-sub) + 1;	//主串指针回退(子串指针移位步长-1)=(p-sub)-1, 进行下一轮搜索
			//p = sub;				//子串指针p重新回到子串的首部sub
			return s - (p-sub);		//
		}

		if( *s == *p ){	//当前字符匹配成功,则子串&主串指针后移一位
			s++;
			p++;
		}else{ //当前字符匹配'不'成功, 子串&主串 回退相应位数
			s = s - (p-sub) + 1;	//主串指针回退(子串指针移位步长-1)=(p-sub)-1, 进行下一轮搜索
			p = sub;				//子串指针p重新回到子串的首部sub
		}
	}
	
	if(*p == '\0'){//子串的
		return s - (p-sub);
	}else{
		return NULL;
	}
	//==========================================
}

int main(){
	char s[N0+1], sub[N0+1], *p, *q;		//s[]-主字符串; sub[]-子字符串; p,q-子串在主串中第一次出现的首地址&(尾地址+1)
	int sublen;	//sublen-子字符串长度
	
	FILE *fp;
	if((fp=fopen("SC6_5B.in", "r")) != NULL ){
		fclose(fp);  //存在的话,要先把之前打开的文件关掉
		
		freopen("SC6_5B.in", "r", stdin);
		freopen("SC6_5B.out", "w", stdout);
	}
	
	gets(s);		//输入主字符串s
	gets(sub);		//输入子字符串sub

	sublen=strlen( sub );	//子字符串长度
	while( p=index(s, sub) )	{ //若在主串中找到子串, 即p不为空(0)
		q = p + sublen;		//子字符串(在主字符串中)的结束地址-的下一个位置!
		while( *p++=*q++ ); //在s中删除p指向的子串sub--[位置p~(q-1)], 即把q及其之和的字符整体往前挪到p位置.
	}

	puts(s);		//输出 删除所有子字符串后的主字符串。
	return 0;
}

2.2. 拓展题:SC6_5C.cpp(本题15分)

【题目描述】 输入3行字符串,分别是s字符串,t字符串和r字符串。如果s字符串中有包含t字符串,则用r字符串替换之。例如:s=“12aaabc3aaaaaabc# %aaabc”,t=“aaabc”,r=“abc”,将s中的“aaabc”替换成“abc”之后,s=“12abc3aabc# %abc”。输出替换之后的s字符串。打开SC6_5C.cpp文件,完成程序的编写。

【输入】
输入文件SC6_5C.in包含有3行字符串,分别是s字符串,t字符串和r字符串。
【输出】
输出文件SC6_5C.out将s字符串中包含的t字符串,用r字符串替换之,输出替换之后的s字符串。
【输入输出样例1】
SC6_5C.in SC6_5C.out
ALKJFOE23DLS67AFAOE
OE
XYZ ALKJFXYZ23DLS67AFAXYZ
【输入输出样例2】
SC6_5C.in SC6_5C.out
12aaabc3aaaaaabc#KaTeX parse error: Expected 'EOF', got '#' at position 28: … abc 12abc3aabc#̲%abc
【数据限制】
0≤字符串长度≤1000。

在这里插入代码片
#include "stdio.h"
#include "string.h"
const int N0=1000;

char *index( char *s, char *sub ){ //在s中查找sub,找到返回首字符地址,找不到返回空
	//int i=0, j=0;	  //i,j-循环控制(游标)变量
	char *p=sub;	  //子字符串
	if( *sub=='\0' )  //字符串为空? 若空则非法,退出程序.
		return NULL;
	//******************************************
	while( *s){ //while( *s && ( strlen(s) >= strlen(p) ) ){	//主串非空, 且主串比子串'长',才有搜索的必要
		if(*p == '\0'){	//若已达到子串的末尾, 则匹配成功, 在主串中找到子串
			//s = s - (p-sub) + 1;	//主串指针回退(子串指针移位步长-1)=(p-sub)-1, 进行下一轮搜索
			//p = sub;				//子串指针p重新回到子串的首部sub
			return s - (p-sub);		//
		}
		
		if( *s == *p ){	//当前字符匹配成功,则子串&主串指针后移一位
			s++;
			p++;
		}else{ //当前字符匹配'不'成功, 子串&主串 回退相应位数
			s = s - (p-sub) + 1;	//主串指针回退(子串指针移位步长-1)=(p-sub)-1, 进行下一轮搜索
			p = sub;				//子串指针p重新回到子串的首部sub
		}
	}
	
	if(*p == '\0'){//子串的
		return s - (p-sub);
	}else{
		return NULL;
	}
	
	//==========================================
}

void insStr( char *s, char *r, char *p ){ //往主串s的位置p插入子串r (s中p之后的字符往后挪动)
	char *pi, *pj;
	//******************************************

	/*(0)待插入的字符串非空, 即有发生实际的插入操作! 否则直接跳出,不做插入!*/
	if(strlen(r) < 1){ 
		return;
	}

	/*(1)插入位置p起始 及其之后的所有字符向后移(挪)动---> '插入串r长度strlen(r)' */
	pi = s + strlen( s );		//指针pi指向主串s的末尾
	//*(pi+strlen(r)) = '\0';	//手动指定新主串s的末尾的字符串结束符
	while(pi >= p){ //从主串的末尾到指针p的所有元素,往后挪动strlen(r)个位置
		*(pi+strlen(r)) = *pi;
		//*pi = ' ';  //抹除掉移(挪)位掉的字符信息, 跟踪(显示)输出操作过程时更清楚!
		pi--;
	}

	/*(2)插入串r插入到主串s的指定位置 p*/
	pi = p;	//pi指向主串s中字符串插入的位置
	pj = r; //pj指向插入串r的起始位置
	while(*pj != '\0'){ //当插入串非空, 则循环插入...
		*pi++ = *pj++;
	}

	//==========================================
}


int main(){
	char s[N0+1], t[N0+1], r[N0+1], *p, *p1, *q; //s,t,r-执行三个字符串的指针; p,p1-子串t在主串s中首次出现的首地址&q为(尾地址+1)
	int tlen;	//字符串t的长度
	
	FILE *fp;
	if((fp=fopen("SC6_5C.in", "r")) != NULL ){
		fclose(fp);  //存在的话,要先把之前打开的文件关掉
		
		freopen("SC6_5C.in", "r", stdin);
		freopen("SC6_5C.out", "w", stdout);
	}
	
	gets(s);	//输入字符串s
	gets(t);	//输入字符串t
	gets(r);	//输入字符串r

	tlen=strlen( t );	//字符串t的长度
	while( p=p1=index( s, t ) ){ //查找子串t在主串s中的位置p1, 若存在,则
		q = p + tlen; //子串t在主串s中的结束位置的-->下一个位置
		
		while( *p++ = *q++ ); //从主串s中删除找到的子串t (s中p~q之间的字符, q之后的字符往前挪)
		
		insStr( s, r, p1 ); //往主串s的位置p1插入子串r (s中p1之后的字符往后挪动)
	}

	puts(s);	//输出字符串s
	return 0;
}
  1. 指针——链表
    3.1. 学生模拟题:SC6_6B.cpp(本题20分)

【题目描述】 有2个从小到大已经排序好的(有序)表,每个结点的数据是1个整数,已知两个表的数据存放在带头结点的单向链表中,将2个有序表合并成1个新的有序表,要求新的有序表中去掉重复相同的数据。打开SC6_6B.cpp文件,完成程序的编写


【输入】
输入文件SC6_6B.in有4行,第1行有1个整数n,即第1个表的结点数,第2行有n个整数;第3行有1个整数m,即第2个表的结点数,第4行有m个整数。整数之间用空格隔开。
【输出】
输出文件SC6_6B.out有1行,将上述2个表的数据从小到大排序输出,数据中没有相同项,每个整数之后输出1个空格。
【输入输出样例1】
SC6_6B.in SC6_6B.out
6
3 6 11 25 67 84
10
-5 3 8 25 25 43 67 92 96 99 -5 3 6 8 11 25 43 67 84 92 96 99
【输入输出样例2】
SC6_6B.in SC6_6B.out
11
-5 3 8 13 16 25 43 67 92 96 99
8
3 6 11 13 25 67 84 123 -5 3 6 8 11 13 16 25 43 67 84 92 96 99 123
【数据限制】
0≤m, n;1≤m+n;所有数据均为整数。

在这里插入代码片
#include "stdio.h"
const int INF=0x7fffffff; //无穷大整数

struct ND{	//链表节点结构
	int data; //链表节点数据: 一个整数
	struct ND *next; //指向下一个链表节点的指针
};

ND *createLink( ) {	//创建链表, 并返回链表头指针
	ND *head, *p; //head-链表头指针; p-遍历链表的链表游标
	int n;	//链表长度(节点数目)
    head = p = new ND; //链表头指针head, 链表游标p指向链表头
	scanf("%d", &n);	//链表长度(节点数目)
	while( n-- ) {
		p->next = new ND; //创建1个新的链表节点 
		p = p->next;	  //链表游标 -> 后移一个节点
		scanf("%d", &p->data); //输入链表节点数据
	}
	p->next = NULL; //链表最后一个节点指向下一个节点的指针 --> 指向空NULL
	return head; //返回链表头指针
}

void printLink( ND *head ) { //打印链表
	ND *p = head->next;  
	if( p==NULL ){ //若链表为空, 直接返回
		return ;
	}
	while( p ) { //逐个打印链表节点上的数据
		printf( "%d ", p->data );
		p=p->next;
	}
	printf("\n");
}

void deleteLink( ND *head) { //删除整个链表
	ND *p=head;
	while( p ) { //若链表节点存在,...
		head = p->next; //链表头指针往后移动
		delete p; //删除链表节点('新'头指针之前的一个节点)
		p = head; //更新当前链表节点指针
	}
}

ND * megerLink( ND *ha, ND *hb ){ //合并2有序表,返回合并后链表头结点的地址
	ND *pa=ha->next, *pb=hb->next, *hc, *pc; //三个链表的头指针p*(a,b,c)及其链表游标h*(a,b,c)
	int data, lastData=INF; //lastData为上一个结点的数据项,用于判定是否有相同数据
	hc=pc=new ND; //hc-合并完后的链表的头指针; pc-游标指针,初始时刻指向链表头
	//************************************************
	while(pa!=NULL || pb!=NULL){	//只要待合并的两个链表其中之一不为空, 则继续进行合并操作
		if(pa == NULL){ //若链表1为空, 则合并链表2剩下的所有数据
			while(pb){
				if(pb->data != lastData){
					pc->next = new ND; //创建1个新的链表节点
					pc = pc->next;	  //链表游标 -> 后移一个节点
					pc->data = pb->data;
					pc->next = NULL;
					
					lastData = pc->data;
				}
				pb = pb->next;
			}
		}else if(pb == NULL){//若链表2为空, 则合并链表1剩下的所有数据
			while(pa){
				if(pa->data != lastData){
					pc->next = new ND; //创建1个新的链表节点
					pc = pc->next;	  //链表游标 -> 后移一个节点
					pc->data = pa->data;
					pc->next = NULL;
					
					lastData = pc->data;
				}
				pa = pa->next;
			}
		}else{//(pa != NULL) && (pb != NULL) //两个链表都非空
			if(pa->data > pb->data){//pa节点数据>pb节点数据,则先合并pb
				if(pb->data != lastData){
					pc->next = new ND; //创建1个新的链表节点
					pc = pc->next;	  //链表游标 -> 后移一个节点
					pc->data = pb->data;
					pc->next = NULL;
					
					lastData = pc->data;
				}
				pb = pb->next;
			}else{//即(pa->data < pb->data) //pa节点数据<pb节点数据,则先合并pa
				if(pa->data != lastData){
					pc->next = new ND; //创建1个新的链表节点
					pc = pc->next;	  //链表游标 -> 后移一个节点
					pc->data = pa->data;
					pc->next = NULL;
					
					lastData = pc->data;
				}
				pa = pa->next;
			}
		}
	}
	
	//=================================================
	return hc;
}
int main(){
	ND *ha, *hb, *hc; //ha,hb-指向两个给定的有序链表头; hc-指向合并后的有序链表
	
	FILE *fp;
	if((fp=fopen("SC6_6B.in", "r")) != NULL ){
		fclose(fp);  //存在的话,要先把之前打开的文件关掉
		
		freopen("SC6_6B.in", "r", stdin);
		freopen("SC6_6B.out", "w", stdout);
	}
	
	ha = createLink();	//创建有序链表ha
	hb = createLink();	//创建有序链表hb
	
	hc = megerLink( ha, hb );	//调用函数megerLink(...)合并两个有序链表ha & hb, 并去除其中重复元素
	
	printLink( hc );	//打印输出合并后的有序链表hc
	
	deleteLink( ha );	//删除有序链表ha
	deleteLink( hb );	//删除有序链表hb
	deleteLink( hc );	//删除有序链表hc
	return 0;
}

3.2. 拓展题:SC6_6C.cpp(本题20分)

有2个从小到大已经排序好的(有序)表,每个结点的数据是1个整数,已知两个表的数据存放在带头结点的单向链表中,将2个有序表合并成1个新的有序表,并要求新表中仅包含2个原表的交集。打开SC6_6C.cpp文件,完成程序的编写。

【输入】
输入文件SC6_6C.in有4行,第1行有1个整数n,即第1个表的结点数,第2行有n个整数;第3行有1个整数m,即第2个表的结点数,第4行有m个整数。整数之间用空格隔开。
【输出】
输出文件SC6_6C.out有1行,将上述2个表数据的交集从小到大排序输出,每个整数之后输出1个空格。
【输入输出样例1】
SC6_6C.in SC6_6C.out
7
3 6 11 25 67 84 92
10
-5 3 8 25 25 43 67 92 96 99 3 25 67 92
【输入输出样例2】
SC6_6C.in SC6_6C.out
8
3 6 11 25 25 67 84 92
10
-5 3 8 25 25 43 67 92 96 99 3 25 25 67 92
【数据限制】
0≤m, n;1≤m+n;所有数据均为整数。

在这里插入代码片
#include "stdio.h"
const int INF=0x7fffffff; //无穷大整数

/*链表节点结构*/
struct ND{
	int data; //链表节点数据: 一个整数
	struct ND *next; //指向下一个链表节点的指针
};

/*创建链表, 并返回链表头指针*/
ND *createLink( ) {	
	ND *head, *p; //head-链表头指针; p-遍历链表的链表游标
	int n;	//链表长度(节点数目)
    head = p = new ND; //链表头指针head, 链表游标p指向链表头
	scanf("%d", &n);	//链表长度(节点数目)
	//printf("-->%d", n);
	
	while( n-- ) {
		p->next = new ND; //创建1个新的链表节点 
		p = p->next;	  //链表游标 -> 后移一个节点

		scanf("%d", &p->data); //输入链表节点数据
	}

	p->next = NULL; //链表最后一个节点指向下一个节点的指针 --> 指向空NULL

	return head; //返回链表头指针
}

/*打印链表*/
void printLink( ND *head ) { 
	ND *p = head->next;  
	if( p == NULL ){ //若链表为空, 直接返回
		return ;
	}

	while( p ) { //逐个打印链表节点上的数据
		printf( "%d ", p->data );
		p=p->next;
	}
	printf("\n");
}

/*删除整个链表*/
void deleteLink( ND *head) { 
	ND *p=head;
	while( p ) { //若链表节点存在,...
		head = p->next; //链表头指针往后移动
		delete p; //删除链表节点('新'头指针之前的一个节点)
		p = head; //更新当前链表节点指针
	}
}

/*合并2有序表, 返回合并后链表头结点的地址*/
ND * megerLink( ND *ha, ND *hb ){ 
	ND *pa=ha->next, *pb=hb->next, *hc, *pc; //三个链表的头指针p*(a,b,c)及其链表游标h*(a,b,c)
	//int data, lastData=INF; //lastData为上一个结点的数据项,用于判定是否有相同数据
	hc=pc=new ND;
	//************************************************
	while(pa!=NULL || pb!=NULL){	//只要待合并的两个链表其中之一不为空, 则继续进行合并操作
		if( (pa != NULL) && (pb != NULL) ){ //两个链表都非空
			if(pa->data > pb->data){ //pb向后遍历
				pb = pb->next;
			}else if(pa->data < pb->data){ //pa向后遍历
				pa = pa->next;
			}else{//pa->data == pb->data //是交集元素,为结果集创建新节点, 并使pa & pb都向后遍历
				pc->next = new ND; //创建1个新的链表节点

				pc = pc->next;	   //链表游标 -> 后移一个节点
				pc->data = pb->data;
				//pc->next = NULL; //最后一个节点指向NULL,在返回结果头指针hc之前处理
				
				//lastData = pc->data;
				pa = pa->next;
				pb = pb->next;
			}
		}else if(pa == NULL){ //若链表1为空, 则合并链表2剩下的所有数据
			break;
		}else if(pb == NULL){//若链表2为空, 则合并链表1剩下的所有数据
			break;
		}
	}

	pc->next = NULL; //合并完的链表的 最后一个节点的下一个节点为NULL

	//=================================================
	return hc;
}

int main(){
	ND *ha, *hb, *hc; //ha,hb-指向两个给定的有序链表头; hc-指向合并后的有序链表
	
	FILE *fp;
	if((fp=fopen("SC6_6C.in", "r")) != NULL ){
		fclose(fp);  //存在的话,要先把之前打开的文件关掉
		
		freopen("SC6_6C.in", "r", stdin);
		freopen("SC6_6C.out", "w", stdout);
	}
	
	ha = createLink();	//创建有序链表ha
	hb = createLink();	//创建有序链表hb

	hc = megerLink( ha, hb );	//调用函数megerLink(...)合并两个有序链表ha & hb, 并去除其中重复元素
	
	printLink( hc );	//打印输出合并后的有序链表hc

	deleteLink( ha );	//删除有序链表ha
	deleteLink( hb );	//删除有序链表hb
	deleteLink( hc );	//删除有序链表hc

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值