2021数据结构CH02【线性表】

2.3线性表的链式表示

1.


#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 

//打印单链表
void printList(LinkList L){
    if (L==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L!= NULL) {
            printf("%d ",L->data);
            L = L->next;
        }
        printf("\n");
    }
}

//尾插法 不带头
LinkList List_TailInsertBuDai(LinkList &L){
	printf("输入单链表的元素,以9999表示结束:");
	int x;
	LNode *r;
	LNode *s;
	L=NULL;
	r=L;
	scanf("%d",&x);
	
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		if(L==NULL){
			L=s;
			r=s;
			scanf("%d",&x);
			continue;	
		}
		r->next=s;
		r=s;
		scanf("%d",&x);
	}

	if(r!=NULL)
		r->next=NULL;
	return L;
}


void Del_X_3(LinkList &L, int x) {  
	LNode *p;          
	if(L==NULL)      
	return;       
	if(L->data==x){    
		p=L;        
		L=L->next;   
		free(p); 
		Del_X_3(L, x); 
	}else 
	Del_X_3(L->next, x); 
}   

bool InitListBuDai(LinkList &L){
	L=NULL;
	return true;
}

int main(){
	int x;
	LinkList L;
	InitListBuDai(L);
	List_TailInsertBuDai(L);
	printf("链表元素为:");
	printList(L);
	printf("删除元素:");
	scanf("%d",&x);
	Del_X_3(L,x);
	printf("删除成功,剩下元素:");
	printList(L);
	return 0;
}

2.


#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 


bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}

//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}

//尾插法 带头
LinkList List_TailInsertDai(LinkList &L){
	printf("输入单链表的元素,以9999表示结束:");
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}

//删除带头单链表所有x
void Del_X_2(LinkList &L,int x){
	LNode *p=L->next;//当前访问到的结点
	LNode *q;//用来删除的结点
	LNode *pre=L;//p结点的前驱结点,保证不断链
	while(p!=NULL){//当前访问结点不是空的,继续循环
		if(p->data==x){
			q=p;
			p=p->next;
			pre->next=p;
			free(q);
		}
		else{
			pre=p;
			p=p->next;
		}
	}

}

int main(){
	int x;
	LinkList L;
	InitListDai(L);
	List_TailInsertDai(L);
	printf("链表元素为:");
	printListDai(L);
	printf("删除元素:");
	scanf("%d",&x);
	Del_X_2(L,x);
	printf("删除成功,剩下元素:");
	printListDai(L);
	return 0;
}

3.


#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 


bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}

//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}

//尾插法 带头
LinkList List_TailInsertDai(LinkList &L){
	printf("输入单链表的元素,以9999表示结束:");
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}

//反向打印带头单链表的每个元素
void R_Print(LinkList &L){
	if(L->next!=NULL)
		R_Print(L->next);
	printf("%d ",L->data);//包含头结点,主函数部分需要做处理
}


int main(){
	LinkList L;
	InitListDai(L);
	List_TailInsertDai(L);
	printf("链表元素为:");
	printListDai(L);
	printf("反向打印链表后:");
	R_Print(L->next);
	return 0;
}

4.


#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 


bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}

//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}

//尾插法 带头
LinkList List_TailInsertDai(LinkList &L){
	printf("输入单链表的元素,以9999表示结束:");
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}

//删除最小值的高效算法 带头
LinkList Del_Min(LinkList &L){
	LNode *p=L->next,*pre=L;//定义当前访问的指针和其前驱指针,最初p指针指向头结点后的第一个元素
	LNode *minp=p,*minpre=pre;//记录最小值结点,默认minp在头结点之后的第一个元素
	while(p!=NULL){
		if(p->data<minp->data){
			minp=p;
			minpre=pre;
		}
		pre=p;
		p=p->next;
	}
	minpre->next=minp->next;
	free(minp);
	return L;
}


int main(){
	LinkList L;
	InitListDai(L);
	List_TailInsertDai(L);
	printf("链表元素为:");
	printListDai(L);
	printf("删除最小值后:");
	Del_Min(L);
	printListDai(L);
	return 0;
}

5.


#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 


bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}

//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}

//头插法 带头
LinkList List_HeadInsert(LinkList &L){
	printf("输入单链表的元素,以9999表示结束:");
	LNode *s;
	int x;
	L=(LinkList)malloc(sizeof(LNode));//创建头结点
	L->next=NULL;//初始化
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));//创建新的结点
		s->data=x;
		s->next=L->next;
		L->next=s;//插入新节点,注意顺序
		scanf("%d",&x);
	}
	return L;
}

//就地逆置带头结点的单链表(辅助空间复杂度为O(1))
//法一 头插法思想
LinkList Reverse_1(LinkList L){// 未涉及到增删操作 只是改变结点顺序而已 可以不写引用类型 
	LNode *p,*r;//p为工作指针,r为p的后继
	p=L->next;//p默认状态下指向第一个元素的结点
	L->next=NULL;//把头结点摘下来,头结点之后为NULL
	while(p!=NULL){//p如果不是最后一个结点就继续循环
		r=p->next;//防止断链
		p->next=L->next;//将p结点指向L->next
		L->next=p;//把p结点插入到L头结点之后
		p=r;//p又回到原链表当前的第一个元素,即r结点处
	}
	return L;
}
//法二 指针反向思想
LinkList Reverse_2(LinkList L){
	LNode *pre,*p=L->next,*r=p->next;//三个相邻结点
	p->next=NULL;
	//指针反向的第一步操作是将p->next置空,而不是反向指头结点
	//原因在于p结点将作为新表的尾结点
	while(r!=NULL){//r为空,说明p已经遍历到最后一个结点了
		pre=p;
		//最初pre指针没有指向任何地方  现在指向p指针所指处 
		//是因为p要往后移动了,此处也就变成了p的前驱
		p=r;//p后移
		r=r->next;//r后移
		p->next=pre;//指针反向
	}
	L->next=p;//此时p已经遍历到最后一个结点,头结点指向最后一个结点,链表反向完成
	return L;
}

int main(){
	LinkList L;
	InitListDai(L);
	List_HeadInsert(L);
	printf("链表元素为:");
	printListDai(L);
	printf("就地逆置带头结点的单链表法一效果:");
	Reverse_1(L);
	printListDai(L);
	printf("就地逆置带头结点的单链表法二效果:");
	Reverse_2(L);
	printListDai(L);
	return 0;
}

法一过程分析

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NDEzODUw,size_16,color_FFFFFF,t_70

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NDEzODUw,size_16,color_FFFFFF,t_70

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NDEzODUw,size_16,color_FFFFFF,t_70

6.


#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 


bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}

//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}

//头插法 带头
LinkList List_HeadInsert(LinkList &L){
	printf("输入单链表的元素,以9999表示结束:");
	LNode *s;
	int x;
	L=(LinkList)malloc(sizeof(LNode));//创建头结点
	L->next=NULL;//初始化
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));//创建新的结点
		s->data=x;
		s->next=L->next;
		L->next=s;//插入新节点,注意顺序
		scanf("%d",&x);
	}
	return L;
}

//尾插法 带头
LinkList List_TailInsertDai(LinkList &L){
	printf("输入单链表的元素,以9999表示结束:");
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}

//带头单链表递增排序
/*思想:先取下头结点和第一个元素结点,构成一个新的有序链表
然后依次扫描原表中的每一个结点(记为p),对比新表中的每个结点,
找到新表中第一个比它大的数的前驱结点pre,插入pre之后即可。
*/
void Sort(LinkList &L){
	LNode *p=L->next,*pre;
	LNode *r=p->next;
	p->next=NULL;
	p=r;
	while(p!=NULL){
		r=p->next;//防止断链
		pre=L;//pre作为工作结点,找到插入位置
		while(pre->next!=NULL&&pre->next->data<p->data)
			pre=pre->next;//在新表中找到插入p的结点的前驱结点pre
		p->next=pre->next;//插入
		pre->next=p;
		p=r;//这里不能写成p=p->next;
		//原因在于p->next在上两行代码已经做了转移,无法定位到原链表的第一个元素
	}
}


int main(){
	LinkList L;
	InitListDai(L);
	List_TailInsertDai(L);
	printf("链表元素为:");
	printListDai(L);
	printf("递增排序后:");
	Sort(L);
	printListDai(L);
	return 0;
}

7.


#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 


bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}

//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}

//头插法 带头
LinkList List_HeadInsert(LinkList &L){
	printf("输入单链表的元素,以9999表示结束:");
	LNode *s;
	int x;
	L=(LinkList)malloc(sizeof(LNode));//创建头结点
	L->next=NULL;//初始化
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));//创建新的结点
		s->data=x;
		s->next=L->next;
		L->next=s;//插入新节点,注意顺序
		scanf("%d",&x);
	}
	return L;
}

//尾插法 带头
LinkList List_TailInsertDai(LinkList &L){
	printf("输入单链表的元素,以9999表示结束:");
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}

//删除给定两个值之间的所有元素(若存在)
/*思想:p始终指向L,用q遍历链表,找到符
合条件的q就删,并且重新让p指向当前的p->next
*/
void RangeDel(LinkList &L,int min,int max){
	printf("删除大于%d且小于%d之间的所有元素:",min,max);
	LNode *p=L,*q=p->next;
	while(q!=NULL){
		if(q->data>min&&q->data<max){
			p->next=q->next;
			free(q);
			q=p->next;
		}
		else{
			p=q;
			q=q->next;//这两行代码顺序不能反
		//否则每次循环会漏掉一个元素的比较
		//这两行代码的执行和前面if语句只能二选一
		//否则无论是否需要删除元素都会向前走一步
		//导致某些元素没有被删除,见出错截图示例
		}

	}
}


int main(){
	LinkList L;
	InitListDai(L);
	List_TailInsertDai(L);
	printf("链表元素为:");
	printListDai(L);
	RangeDel(L,2,7);
	printf("删除之后:");
	printListDai(L);
	return 0;
}

出错截图示例:(存在元素未检测到)

20200804110938748.png

8.

开始做本题之前需要明确的是:

①两个链表存在公共结点是指两个链表的结点为同一个结点,而不是说两个链表存在data域的值相同的结点。

②两个链表一旦存在公共结点,由于每个结点只有一个next域,故公共结点之后所有结点必然重合,不会分叉。

在明白以上两点之后,就能理解为何只需要找到第一个公共结点就能找到两个单链表的所有公共结点了。

所以本题的关键点在于如何找到第一个公共结点,在找第一个公共结点之前还要考虑到两个单链表的长度可能不相同。

如果两个链表长度不等,二者同时遍历时,短的链表总是先遍历到公共结点,而这个时候通过对比当前访问到的两个结点,无法判断是否发现了第一个公共结点,所以只有保证二者同时遍历到第一个公共结点时,通过对比发现两个结点相同,才能真正找出第一个公共结点。

为了同时遍历到第一个公共结点,长的链表应当先行遍历完比短链表长的部分,二者再一同开始遍历,这样就能保证同时到达第一个公共结点,也就顺利成章找到公共部分了。


 
#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 
 
 
bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}
//打印单链表 不带头
void printList(LinkList L){
    if (L==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L!= NULL) {
            printf("%d ",L->data);
            L = L->next;
        }
        printf("\n");
    }
}

 
//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}
 
//求表长 带头
int Length(LinkList L){
	LNode *p=L;
	int length=0;
	while(p->next!=NULL){
	p=p->next;
	length++;
	}
	return length;
}
 
//尾插法 带头
LinkList List_TailInsertDai(LinkList &L){
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}
//为两个单链表插入公共结点 插入部分无头结点 
LinkList TailInsert_Common(LinkList &M,LinkList &N){
	LNode *m=M,*n=N;//m,n指向M,N
	LNode *s;//用于新建结点
	LNode *p=s;//p代表公共结点的起始处
	while(m->next!=NULL){//找到M,N的最后一个结点
		m=m->next;
	}
	while(n->next!=NULL){
		n=n->next;
	}
	//同时在此时的m,n后插入公共结点的数据
	printf("请插入公共结点,以9999表示结束:");
	int x;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		m->next=s;
		m=m->next;
		n->next=s;
		n=n->next;
		scanf("%d",&x);
	}
	m->next=NULL;
	n->next=NULL;
	return p;
}

//找出两个链表的公共结点
LinkList Find_First_Common(LinkList &M,LinkList &N){
	int lenM=Length(M),lenN=Length(N),k;//k为长度之差
	LinkList Long;
	LinkList Short;
	//确定链表长短,分别指向第一个数据元素(非头结点)
	if(lenM>lenN){
	Long=M->next;//此处Long指向M中第一个含有数据的元素,当然也可以指向M的头结点
	Short=N->next;//只不过比较头结点是没有意义的,因为打印的内容是NULL,造成打印失败
	k=lenM-lenN;
	}
	else{
	Long=N->next;
	Short=M->next;
	k=lenN-lenM;
	}
	while(k!=0){//长链表先遍历k个结点,k等于O时跳出
		Long=Long->next;
		k--;
	}
	while(Long!=NULL){
		if(Long==Short)
			return Long;
		else{
		Long=Long->next;
		Short=Short->next;
		}
	}
	return NULL;
}
 
 
int main(){
	LinkList M;
	LinkList N;
	InitListDai(M);
	InitListDai(N);
	printf("输入M独有部分,以9999结束:");
	List_TailInsertDai(M);
	printf("输入N独有部分,以9999结束:");
	List_TailInsertDai(N);
	printf("输入M,N链表的公共结点部分,以9999结束:\n");
	TailInsert_Common(M,N);
	printf("M链表为:");
	printListDai(M);
	printf("N链表为:");
	printListDai(N);
	printf("利用算法找到的公共结点为:");
	printList(Find_First_Common(M,N));
	//注意,公共结点起始处含有数据元素
	//所以打印公共结点应该用不带头结点的打印方式
	return 0;
}

 

9.


 
#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 
 
 
bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}

//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}
 
//尾插法 带头
LinkList List_TailInsertDai(LinkList &L){
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}
//递增输出单链表,并释放结点空间。
/*
每次遍历找出最小值并释放此结点的空间
最后还需判断是否只剩头结点,并释放头结点的空间
*/
void Min_Del(LinkList &head){
	LNode *pre,*p,*u;//pre记录最小值的前驱结点,默认第一个结点为数据最小点,p为工作指针,u用于释放空间
	while(head->next!=NULL){
		pre=head;
		p=head->next;
		while(p->next!=NULL){//每次比较p->next和pre->next,当P->next为NULL,说明最后一个结点已经比较完了
			if(p->next->data<pre->next->data)//通过比较更新最小结点的前驱结点
				pre=p;
			p=p->next;//每次比较后p后移

		}//找到最小结点后就要进行打印和空间的释放了
		printf("%d ",pre->next->data);
		u=pre->next;//u定位要释放的结点,即pre->next
		pre->next=u->next;
		free(u);
	}
	free(head);
}
 
 
int main(){
	LinkList M;
	InitListDai(M);
	printf("建立单链表,以9999结束:");
	List_TailInsertDai(M);
	printf("链表为:");
	printListDai(M);
	printf("递增打印该链表中>>>>>> 结果为:");
	Min_Del(M);
	printf("\n该链表的存储空间已被释放\n");
}

10.


 
#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 
 
 
bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}

//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}
 
//尾插法 带头
LinkList List_TailInsertDai(LinkList &L){
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}
//分解两个带头结点的单链表为A,B(A含有原表中序号为奇数的元素,B含有原表中序号为偶数的元素)
/*
设置一个为0的int型数值,用来记录当前访问的是第几个结点,每次工作指针p后移则+1
p最开始指向A->next,根据int型的奇偶型判断插入A还是B中
*/
LinkList DisCreat_1(LinkList &A){
	int k=0;
	LinkList B=(LinkList)malloc(sizeof(LNode));
	InitListDai(B);
	LNode *ra=A,*rb=B;//ra rb分别为A,B的尾指针
	LNode *p=A->next;
	A->next=NULL;//先把AB的头结点置空,便于后续的插入
	B->next=NULL;
	while(p!=NULL){//循环条件不应为p->next为空
		k++;
		if(k%2==1){
			ra->next=p;
			ra=p;
		}
		else{
			rb->next=p;
			rb=p;
		}
		p=p->next;
	}
	ra->next=NULL;
	rb->next=NULL;
	return B;
}
 
 
int main(){
	LinkList A;
	LinkList B;
	InitListDai(A);
	printf("建立单链表,以9999结束:");
	List_TailInsertDai(A);
	printf("链表为:");
	printListDai(A);
	printf("拆分链表,A中含有原表中序号为奇数的所有元素,B中含有原表中序号为偶数的所有元素");
	B=DisCreat_1(A);
	printf("A:");
	printListDai(A);
	printf("B:");
	printListDai(B);
}

11.


 
#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 
 
 
bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}

//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}
 
//尾插法 带头
LinkList List_TailInsertDai(LinkList &L){
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}
//拆分线性表
LinkList DisCreat_2(LinkList &A){//注释中的A,B均理解为拆分后的A,B
	LinkList B=(LinkList)malloc(sizeof(LNode));
	B->next=NULL;
	//假设最开始AB为空,ra始终指向A的表尾
	//p为工作指针,每轮循环的开始指向A的下一个需要生成的结点,同时为B的创建提供条件,
	//q:循环过程中在p之后,防止断链
	LNode *ra=A,*p=A->next,*q;
	while(p!=NULL){//循环条件不应为p->next为空
		ra=p;//ra必须始终指向A的表尾,故一开始便指向p的所在处,
		p=p->next;//为了生成B,p从A处后移,移动到B的元素处
		q=p->next;//当前p要进行前插操作,用q记录p的下一个结点,防止断链
		p->next=B->next;//前插
		B->next=p;//前插
		ra->next=q;//p前插后,将A此时的最后一个元素与A的下一个需要生成的结点相连
		p=q;//p完成了本轮使命,继续移动到A下一个需要生成的结点处
	}
	ra->next=NULL;//将A的表尾置空,B采用头插法,表尾已经为空,不用管
	return B;
}
 
 
int main(){
	LinkList A;
	LinkList B;
	InitListDai(A);
	printf("建立单链表,以9999结束:");
	List_TailInsertDai(A);
	printf("链表为:");
	printListDai(A);
	printf("拆分链表");
	B=DisCreat_2(A);
	printf("A:");
	printListDai(A);
	printf("B:");
	printListDai(B);
}

12.


 
#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 
 
 
bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}

//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}
 
//尾插法 带头
LinkList List_TailInsertDai(LinkList &L){
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}
//删除有序线性表中的相同元素
void Del_Same(LinkList &L){
	LNode *p=L->next,*q=p->next,*del;//*p为工作指针,q为p->next,用来找出相同元素,del记录需要删除的元素
	while(p->next!=NULL){
		if(p==NULL)
			return;
		if(p->data!=q->data){
			p=q;
			q=q->next;
		}
		else{
			del=q;
			q=q->next;
			p->next=q;
			free(del);
		}
	}
}
 
 
int main(){
	LinkList L;
	InitListDai(L);
	printf("建立单链表,以9999结束:");
	List_TailInsertDai(L);
	printf("链表为:");
	printListDai(L);
	printf("删除重复元素:");
	Del_Same(L);
	printf("删除后:");
	printListDai(L);
	return 0;
}

13.


 
#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 
 
 
bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}

//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}
 
//尾插法 带头
LinkList List_TailInsertDai(LinkList &L){
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}
//两个有序递增线性表合并成一个递减的线性表,以单链表方式存储,并且用原来两个单链表的结点存放归并后的单链表
void MergeUpToDown(LinkList &A,LinkList &B){
	LNode *a=A->next,*b=B->next,*r;//*a,*b分别为A,B的工作指针,*r记录工作指针的后继结点,防止断链
	A->next=NULL;
	while(a!=NULL&&b!=NULL){
		if(a->data<=b->data){
			r=a->next;
			a->next=A->next;
			A->next=a;
			a=r;
		}
		else{
			r=b->next;
			b->next=A->next;
			A->next=b;
			b=r;
		}
	}
	if(a!=NULL)
		//若最后A还剩下一些元素,要对a操作
		//而当b指向a所指向的地方时,对b操作等于对a操作
		b=a;//b指向a所指向的地方,对b操作等于对a操作
	while(b!=NULL){//若最后B还剩下一些元素,不执行if语句直接对b操作
		r=b->next;
		b->next=A->next;
		A->next=b;
		b=r;
	}
	free(B);//最后把仅剩下的B的头结点free掉
	}

 
 
int main(){
	LinkList A;
	LinkList B;
	InitListDai(A);
	InitListDai(B);
	printf("建立单链表A,以9999结束:");
	List_TailInsertDai(A);
	printf("链表A为:");
	printListDai(A);
	printf("建立单链表B,以9999结束:");
	List_TailInsertDai(B);
	printf("链表B为:");
	printListDai(B);
	printf("归并递增为递减之后:");
	MergeUpToDown(A,B);
	printListDai(A);
	return 0;
}

14.


 
#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 
 
 
bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}

//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}
 
//尾插法 带头
LinkList List_TailInsertDai(LinkList &L){
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}
//用两个有序递增单链表的公共元素形成一个新的链表
LinkList Get_Common(LinkList &A,LinkList &B){
	LNode *a=A->next,*b=B->next,*r,*s;//*a,*b分别为A,B的工作指针,*r为C的尾指针,s用于产生C的新节点
	LinkList C=(LinkList)malloc(sizeof(LNode));
	r=C;
	while(a&&b){
		if(a->data<b->data)
			a=a->next;
		else if(a->data>b->data)
			b=b->next;
		else{
			s=(LNode *)malloc(sizeof(LNode));
			s->data=a->data;
			r->next=s;
			r=s;
			a=a->next;
			b=b->next;
		}
	}
	r->next=NULL;
	return C;
}

 
 
int main(){
	LinkList A;
	LinkList B;
	LinkList C;
	InitListDai(A);
	InitListDai(B);
	InitListDai(C);
	printf("建立单链表A,以9999结束:");
	List_TailInsertDai(A);
	printf("链表A为:");
	printListDai(A);
	printf("建立单链表B,以9999结束:");
	List_TailInsertDai(B);
	printf("链表B为:");
	printListDai(B);
	printf("A,B的公共元素为:");
	C=Get_Common(A,B);
	printListDai(C);
	return 0;
}

15.


 
#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 
 
 
bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}

//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}
 
//尾插法 带头
LinkList List_TailInsertDai(LinkList &L){
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}
//求两个有序递增单链表A,B的交集,并存放在A链表中
LinkList Union(LinkList &A,LinkList &B){
	LNode *pa=A->next,*pb=B->next,*u;//pa,pb分别为A,B的工作指针,u用于记录需要被释放的结点
	LNode *pc=A;//结果要保留在A中,借用A的头结点
	while(pa&&pb){
		if(pa->data==pb->data){
			//A中符合结果的结点存放到pc中
			pc->next=pa;
			pc=pa;
			pa=pa->next;
			//释放B中的结点
			u=pb;
			pb=pb->next;
			free(u);
		}
		else if(pa->data>pb->data){
			u=pb;
			pb=pb->next;
			free(u);
		}
		else{
			u=pa;
			pa=pa->next;
			free(u);
		}
	}
	while(pa){
		u=pa;
		pa=pa->next;
		free(u);
	}
	while(pb){
		u=pb;
		pb=pb->next;
		free(u);
	}
	pc->next=NULL;
	free(B);
	return A;
}

 
 
int main(){
	LinkList A;
	LinkList B;
	InitListDai(A);
	InitListDai(B);
	printf("建立单链表A,以9999结束:");
	List_TailInsertDai(A);
	printf("链表A为:");
	printListDai(A);
	printf("建立单链表B,以9999结束:");
	List_TailInsertDai(B);
	printf("链表B为:");
	printListDai(B);
	printf("A,B的交集为:");
	printListDai(Union(A,B));
	return 0;
}

16.


 
#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 
 
 
bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	return true;
}

//打印单链表 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (L->next!= NULL) {
            printf("%d ",L->next->data);
            L = L->next;
        }
        printf("\n");
    }
}
 
//尾插法 带头
LinkList List_TailInsertDai(LinkList &L){
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	}
	r->next=NULL;
	return L;
}
//B是A的连续子序列吗
int Pattern(LinkList &A,LinkList &B){
	LNode *a=A->next,*b=B->next,*m=a;//a,b分别为A,B的工作指针,m记录每次比较A的开始结点
	while(a&&b)
		if(a->data==b->data){
			a=a->next;
			b=b->next;
		}
		else{
			a=m->next;
			m=a;
			b=B->next;
		}
		if(b==NULL)
			return 1;
		else
			return 0;
}

int main(){
	LinkList A;
	LinkList B;
	InitListDai(A);
	InitListDai(B);
	printf("建立单链表A,以9999结束:");
	List_TailInsertDai(A);
	printf("链表A为:");
	printListDai(A);
	printf("建立单链表B,以9999结束:");
	List_TailInsertDai(B);
	printf("链表B为:");
	printListDai(B);
	printf("B是否为A的子序列?是:1  否:0 ------>>  ");
	printf("%d\n",Pattern(A,B));
	return 0;
}

17.

算法思想:设置两个指针p,q,分别从头结点的左右两边扫描,直到它们指向同一个结点(p=q,当结点个数为奇数时)或相邻(p->next=q或q->prior=p,当结点个数为偶数时)时停止,若它们所指的结点的值相等,则继续扫描,扫描完成后返回1,否则说明不对称,返回0。


 
#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct DNode{    
	int data;    
	struct DNode *prior,*next;     
}DNode, *DLinkList; 
 
//初始化一个循环双链表 
bool InitDLinkList(DLinkList &L){
	L=(DNode*)malloc(sizeof(DNode));
	if(L==NULL) return false;
	L->prior=L;//	头结点prior指向头结点
	L->next=L;//	头结点next指向头结点
	return true;
}

//打印循环双链表 带头
void printDLinkListDai(DLinkList L){
    if (L->next==L) {
        printf("链表为空,打印失败\n");
    }else{
        DNode *p=L->next;
		while(p!=L){
			printf("%d ",p->data);
			p=p->next;
		}
        printf("\n");
    }
}
 
//尾插法建立双循环链表 带头  注意顺序
DLinkList DLinkList_TailInsertDai(DLinkList &L){
	int x;
	L=(DNode *)malloc(sizeof(DNode));
	DNode *s;
	DNode *r=L;//r始终指向链表最后一个元素,初始在L处
	scanf("%d",&x);
	while(x!=9999){
		s=(DNode *)malloc(sizeof(DNode));
		s->data=x;
		r->next=s;//尾指针的next本来指向L,现在指向新的结点
		s->prior=r;//新结点的前驱指向原来的尾结点
		s->next=L;//新结点变成尾结点,指向L
		L->prior=s;//L的前驱指向新的尾结点
		r=s;//更新尾结点
		scanf("%d",&x);
	}
	return L;
}
//判断带头结点的循环双链表是否对称
int Symmetry(DLinkList &L){
	DNode *p=L->next,*q=L->prior;
	while(p!=q&&p->next!=q)
		if(p->data==q->data){
			p=p->next;
			q=q->prior;
		}
		else
			return 0;
	return 1;
}

int main(){
	DLinkList L;
	InitDLinkList(L);
	DLinkList_TailInsertDai(L);
	printDLinkListDai(L);
	int i;
	i=Symmetry(L);
	if(i==1)
		printf("带头结点的循环双链表是对称的\n");
	else
		printf("带头结点的循环双链表不是对称的\n");
	return 0;
}

18.


 
#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 
 
//初始化一个循环单链表 
bool InitList(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=L;//	头结点next指向头结点
	return true;
}

//打印循环双链表 带头
void printList(LinkList L){
    if (L->next==L) {
        printf("链表为空,打印失败\n");
    }else{
        LNode *p=L->next;
		while(p!=L){
			printf("%d ",p->data);
			p=p->next;
		}
        printf("\n");
    }
}
 
//尾插法建立循环单链表
LinkList List_TailInsert(LinkList &L){
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *s;
	LNode *r=L;//r始终指向链表最后一个元素,初始在L处
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;//尾指针的next本来指向L,现在指向新的结点
		s->next=L;//新结点变成尾结点,指向L
		r=s;//更新尾结点
		scanf("%d",&x);
	}
	return L;
}
//连接两个循环单链表并保持循环形式 带头 书中答案为不带头版本
LinkList Link(LinkList &h1,LinkList &h2){
	LNode *p=h1->next,*q=h2->next;//p q分别指向h1 h2的第一个结点
	while(p->next!=h1)//找出h1的尾结点
		p=p->next;
	h2->next=NULL;//把h2从头结点后断开,变成一条线
	p->next=q;//将h1的尾部和h2的第一个结点连接
	while(q->next!=h2)//找到h2的尾结点
		q=q->next;
	q->next=h1;//h2的最后一个结点指向h1,形成循环
	free(h2);//释放h2这个结点
	return h1;
}
int main(){
	LinkList h1;
	LinkList h2;
	InitList(h1);
	InitList(h2);
    List_TailInsert(h1);
	List_TailInsert(h2);
	Link(h1,h2);
	printList(h1);
	return 0;
}

19.


 
#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *next;     
}LNode, *LinkList; 
 
//初始化一个循环单链表 
bool InitList(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=L;//	头结点next指向头结点
	return true;
}

//打印循环双链表 带头
void printList(LinkList L){
    if (L->next==L) {
        printf("链表为空,打印失败\n");
    }else{
        LNode *p=L->next;
		while(p!=L){
			printf("%d ",p->data);
			p=p->next;
		}
        printf("\n");
    }
}
 
//尾插法建立循环单链表
LinkList List_TailInsert(LinkList &L){
	int x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *s;
	LNode *r=L;//r始终指向链表最后一个元素,初始在L处
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;//尾指针的next本来指向L,现在指向新的结点
		s->next=L;//新结点变成尾结点,指向L
		r=s;//更新尾结点
		scanf("%d",&x);
	}
	return L;
}
//依次找出带头循环单链表中最小值结点并输出,然后删除该结点,直到链表为空,删除表头结点。
void Del_All(LinkList &L){
	LNode *p,*pre,*minp,*minpre;//p为工作指针,pre为p的前驱,minp代表最小值结点指针,minpre为其前驱
	while(L->next!=L){//表不为空,继续循环,直到只剩一个头结点
		p=L->next;//每次循环p指向第一个结点
		pre=L;//每次循环pre指向L
		minp=p;//默认第一个结点为最小值结点
		minpre=pre;
		while(p!=L){//p若未循环一趟,继续循环,找到最小值结点
			if(p->data<minp->data){//更新最小值结点
			minp=p;
			minpre=pre;
			}
			pre=pre->next;//查找下一个pre和p结点
			p=p->next;
		}
		printf("%d ",minp->data);//输出
		minpre->next=minp->next;//删除
		free(minp);//释放
	}
	free(L);//最后释放头结点
}

int main(){
	LinkList L;
	InitList(L);
    List_TailInsert(L);
	Del_All(L);
	return 0;
}

20.


 
#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct DNode{    
	int data,freq;    
	struct DNode *pred,*next;     
}DNode, *DLinkList; 
 
//初始化一个双链表 
bool InitDLinkList(DLinkList &L){
	L=(DNode*)malloc(sizeof(DNode));
	if(L==NULL) return false;
	L->next=NULL;//	头结点next为空
	L->pred=NULL;//头结点prior为空
	//L->freq=0;
	printf("初始化完成\n");
	return true;
}

//打印循环双链表 带头
void printDLinkList(DLinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        DNode *p=L->next;
		while(p!=NULL){
			printf("%d ",p->data);
			p=p->next;
		}
        printf("\n");
    }
}

//打印循环双链表中每个结点的频度 带头
void printFreq(DLinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        DNode *p=L->next;
		while(p!=NULL){
			printf("%d ",p->freq);
			p=p->next;
		}
        printf("\n");
    }
}
//尾插法建立循环单链表
DLinkList List_TailInsert(DLinkList &L){
	int x;
	L=(DNode *)malloc(sizeof(DNode));
	DNode *s;
	DNode *r=L;//r始终指向链表最后一个元素,初始在L处
	scanf("%d",&x);
	while(x!=9999){
		s=(DNode *)malloc(sizeof(DNode));
		s->data=x;
		s->freq=0;//插入的数据初始频度为0
		r->next=s;//尾指针的next本来指向NULL,现在指向新的结点
		s->pred=r;
		s->next=NULL;//新结点变成尾结点,指向NULL
		r=s;//更新尾结点
		scanf("%d",&x);
	}
	printf("建立完成:");
	return L;
	
}
//频繁访问的结点总是靠近表头
DLinkList Locate(DLinkList &L,int x){
//本算法先查找数据x,查找成功时结点的访问频度+1
//最后将该结点按照频度递减插入链表中合适的位置(同频度最近访问的靠前)
	DNode *p=L->next,*q;//p为工作指针,q为p的前驱,用于查找插入位置
	while(p&&p->data!=x)
		p=p->next;//查找值为x的结点
	if(!p){//p遍历完,没找到符合的x
		printf("不存在值为%d的结点\n",x);
		exit(0);//程序结束时返回0给系统
	}
	else{//找到了符合的x,将对x的结点进行操作
		p->freq++;//频度+1
		p->next->pred=p->pred;//将p结点摘下,此时指向p结点的指针都已更改,但是由p指出的指针都存在,可以画图理解
		p->pred->next=p->next;//将p结点摘下,此时指向p结点的指针都已更改,但是由p指出的指针都存在,可以画图理解
		q=p->pred;//以下查找p结点插入的位置
		while(q!=L&&q->freq<=p->freq)
			q=q->pred;
		p->next=q->next;//找到第一个大于x所在结点的频度的q结点之后,把p变成q的后继结点
		q->next->pred=p;//找到第一个大于x所在结点的频度的q结点之后,把p变成q的后继结点
		//上面两行代码保证了x所在结点排在同频率的第一个
		p->pred=q;//找到第一个大于x所在结点的频度的q结点之后,把p变成q的后继结点
		q->next=p;//找到第一个大于x所在结点的频度的q结点之后,把p变成q的后继结点
	}
	return L;//按照题目要求,本题应该返回p,这里返回L,是为了方便可视化验证
}


int main(){
	DLinkList L;
	InitDLinkList(L);
    List_TailInsert(L);
	printDLinkList(L);
	printf("初始频度:");
	printFreq(L);
	Locate(L,2);//*****
	printf("第1次查找后(查找存在的值2):");
	printf("频度变为:");
	printFreq(L);
	printf("*************************** ");
	printf("链表变为:");
	printDLinkList(L);
	Locate(L,2);//*****
	printf("第2次查找后(查找存在的值2):");
	printf("频度变为:");
	printFreq(L);
	printf("*************************** ");
	printf("链表变为:");
	printDLinkList(L);
	Locate(L,3);
	printf("第3次查找后(查找存在的值3):");
	printf("频度变为:");
	printFreq(L);
	printf("*************************** ");
	printf("链表变为:");
	printDLinkList(L);
	printf("第4次查找后(查找不存在的值5):");
	Locate(L,5);
	return 0;
}

21.

 
 
#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *link;     
}LNode, *LinkList; 
 
 
bool InitListDai(LinkList &list){
	list=(LNode*)malloc(sizeof(LNode));
	if(list==NULL) return false;
	list->link=NULL;
	return true;
}
 
//打印单链表 带头
void printListDai(LinkList list){
    if (list->link==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (list->link!= NULL) {
            printf("%d ",list->link->data);
            list = list->link;
        }
        printf("\n");
    }
}
 
//尾插法 带头
LinkList List_TailInsertDai(LinkList &list){
	int x;
	list=(LNode *)malloc(sizeof(LNode));
	LNode *r=list;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->link=s;
		r=s;
		scanf("%d",&x);
	}
	r->link=NULL;
	return list;
}
//查找链表list倒数第k个结点,并输出该结点的data值
int Search_k(LinkList &list,int k){
	LNode *p=list->link,*q=list->link;
	int count=0;//count用于构建p和q相差k个位置的条件
	while(p!=NULL){//执行完之后p和q相差k个位置
		if(count<k)
			count++;
		else
			q=q->link;
		p=p->link;
	}
	if(count<k)
		return 0;
	else{
		printf("%d",q->data);
		return 1;
	}
}

 
int main(){
	LinkList list;
	InitListDai(list);
	List_TailInsertDai(list);
	printListDai(list);
	Search_k(list,4);
	printf("\n");
	return 0;
}

22.

 
#include<stdio.h>  
#include<stdlib.h>  
//字符串结构体
typedef struct LNode{    
	char data;    
	struct LNode *next;     
}LNode, *LinkList; 
 
 //初始化带头结点的单链表
bool InitListDai(LinkList &L){
	L=(LNode*)malloc(sizeof(LNode));
	if(L==NULL) return false;
	L->next=NULL;
	printf("初始化完成\n");
	return true;
}
 
//打印单链表中的字符串 带头
void printListDai(LinkList L){
    if (L->next==NULL) {
        printf("链表为空,打印失败\n");
    }else{
		LNode *p=L->next;
        while (p!= NULL) {
            printf("%c",p->data);
            p=p->next;
        }
        printf("\n");
    }
}
 
//利用尾插法在单链表中插入字符串 带头
LinkList List_TailInsertDai(LinkList &L){
	char x;
	L=(LNode *)malloc(sizeof(LNode));
	LNode *r=L;
	LNode *s;
	while((x=getchar())!='\n'){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		x=getchar();
	}
	r->next=NULL;
	return L;
}

//求单链表中字符串的长度
int Listlen(LinkList L){
	int len=0;
	while(L->next!=NULL){
	len++;
	L=L->next;
	}
	return len;
}
//找出共同后缀的起始地址
LNode* find_addr(LinkList &str1,LinkList &str2){
	int m,n;
	LNode *p,*q;
	m=Listlen(str1);
	n=Listlen(str2);
	for(p=str1;m>n;m--)
		p=p->next;
	for(q=str2;m<n;n--)
		q=q->next;
	while(p->next!=NULL&&p->next!=q->next){
	p=p->next;
	q=q->next;
	}//while结束时,p指向共同后缀第一个元素结点的前一个结点
	printf("共同后缀的起始位置元素为:%c\n",p->next->data);//应该以return p->next结束,此处改编是为了验证代码能否正确实现
	return p->next;
}
//将共同后缀与两个链表拼接(此方法是为了程序的实现,答案中不必写,因为默认str1 str2在计算机中已经存储好了,不用单独建立)
void MergeStrWithCommon(LinkList &str1,LinkList &str2,LinkList &common){
	LNode *p=str1->next,*q=str2->next,*c=common->next;
	while(p->next!=NULL)
		p=p->next;
	while(q->next!=NULL)
		q=q->next;
	p->next=c;
	q->next=c;
	free(common);
}

int main(){
	LinkList str1;
	LinkList str2;
	LinkList common;//公共后缀部分
	InitListDai(str1);
	InitListDai(str2);
	InitListDai(common);
	printf("输入str1单独存储部分,以回车键结束:");
	List_TailInsertDai(str1);
	printf("输入str2单独存储部分,以回车键结束:");
	List_TailInsertDai(str2);
	printf("输入共同后缀部分,以回车键结束:");
	List_TailInsertDai(common);
	MergeStrWithCommon(str1,str2,common);
	printf("str1:");
	printListDai(str1);
	printf("str2:");
	printListDai(str2);

	printf("\n");
	find_addr(str1,str2);
	return 0;
}

23.

数组大小用变量定义的相关资料,点击此处查看

#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *link;     
}LNode, *LinkList; 
 
 
bool InitListDai(LinkList &list){
	list=(LNode*)malloc(sizeof(LNode));
	if(list==NULL) return false;
	list->link=NULL;
	return true;
}
 
//打印单链表 带头
void printListDai(LinkList list){
    if (list->link==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (list->link!= NULL) {
            printf("%d ",list->link->data);
            list = list->link;
        }
        printf("\n");
    }
}
 
//尾插法 带头
LinkList List_TailInsertDai(LinkList &list){
	int x;
	list=(LNode *)malloc(sizeof(LNode));
	LNode *r=list;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->link=s;
		r=s;
		scanf("%d",&x);
	}
	r->link=NULL;
	return list;
}
//
void func(LinkList &L,int n){
	LNode *p=L,*r;
	int *q,m;//*q用于定义一个q[n+1],m用于记录|data|
	//由于|data|<n 故|data|可能为0,1,2,... ,n,故申请数组的空间为n+1个int的空间
	q=(int *)malloc(sizeof(int)*(n+1));
	for(int i=0;i<n+1;i++)//数组下标从0开始
		q[i]=0;
	while(p->link!=NULL){
		m=p->link->data>0?p->link->data:-p->link->data;
		if(q[m]==0){
			q[m]=1;
			p=p->link;
		}
		else{
			r=p->link;
			p->link=r->link;
			free(r);
		}
	}
	printf("func()方法已执行\n");
	free(q);
	
}
 
 
int main(){
	LinkList head;
	InitListDai(head);
	List_TailInsertDai(head);
	printListDai(head);
	func(head,10);
	printListDai(head);
	printf("\n");
	return 0;
}

24.

 

借鉴龟兔赛跑算法的思想,为了确认是否存在环,需要设置两个指针,fast和slow,fast每次走两步,slow每次走一步,如果环存在,fast一定先进入环,而slow后进入环。

当slow刚进入环中时,fast早就已经进入环中了,且fast可能已经在环中绕了n圈,由于此时fast和slow都在环中,故二者的距离肯定是小于环的长度的。

随后二者继续走若干步,slow从入口处开始走,fast从slow进入环中时刻fast所处的位置继续走,当slow走完环的一圈,fast从slow进入环中后又走了整整两圈的长度,在这个过程中fast与slow相遇过。

相当于甲乙在操场长跑,甲站在起跑线开始跑,乙站在起跑线前面100米开始跑,乙跑步的速度是甲的两倍,刚开始乙在甲前面100米,乙是碰不到甲的,当甲跑完一圈,乙已经跑完了两圈,而在乙跑完两圈的过程中,必定会碰到甲。

所以可以得出的结论是,在slow与fast初次相遇时,slow最多在环中走了一圈,而fast可以走多圈。

根据fast的速度是slow的速度的两倍,可以得出结论,在二者相遇时,fast走过的路程是slow的整整两倍。因此可以通过此结论建立方程式。

设头结点到环入口处的距离为a,环的入口处到相遇点的距离为x,环长为r,在fast与slow相遇时,fast绕了n圈。

由以上分析可知,相遇时slow在环中最多走了一圈,即gif.latex?x%5Cleq%20r,故slow的路程为gif.latex?a&plus;x

而当slow刚进入环中时,fast早就已经进入环中了,且fast可能已经在环中绕了n圈,并停留在入口处前是的x距离处,故fast的路程为gif.latex?a&plus;n*r&plus;x。 

根据二者相遇时,fast走过的路程是slow的整整两倍可知:2(gif.latex?a&plus;x)= gif.latex?a&plus;n*r&plus;x,即gif.latex?a%3Dn*r-x

而此处的a即为头结点到环入口处的距离,也就是说找到了头结点到环入口距离与环的入口处到相遇点的距离x的关系,则可以看出,如果此时在头结点处设置一个指针p1,在相遇点处设置一个指针p2,二者每次均走一步,当p1从头结点往后走a步,p2指针就沿着环走了gif.latex?gif.latex?n*r-x步,两者就相遇了,且相遇的地方为入口处。

#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *link;     
}LNode, *LinkList; 
 
 
bool InitListDai(LinkList &list){
	list=(LNode*)malloc(sizeof(LNode));
	if(list==NULL) return false;
	list->link=NULL;
	return true;
}
 
//打印单链表 带头
void printListDai(LinkList list){
    if (list->link==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (list->link!= NULL) {
            printf("%d ",list->link->data);
            list = list->link;
        }
        printf("\n");
    }
}
 
//尾插法 带头
LinkList List_TailInsertDai(LinkList &list){
	int x;
	list=(LNode *)malloc(sizeof(LNode));
	LNode *r=list;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->link=s;
		r=s;
		scanf("%d",&x);
	}
	r->link=NULL;
	return list;
}
//单链表不成环的时候使其成环,并且环的入口点设置在L的next->next
//只是为了方便验证本题找到单链表环的入口点而编写的方法
void MakeACircle(LinkList &L){
	LNode *p=L;
	while(p->link!=NULL)
		p=p->link;
	p->link=L->link->link;
	printf("已经成环,入口在第二个元素处\n");
}

//找到单链表环的入口点
LNode* FindLoopStart(LinkList &L){
	LNode *fast=L,*slow=L;
	while(fast->link!=NULL&&fast->link->link!=NULL){//fast每次走两步,所以其后两步不能为空
	fast=fast->link->link;
	slow=slow->link;
	if(slow==fast)
		break;
	}//如果有环,必定能找到环,见分析
	if(fast->link==NULL||fast->link->link==NULL)//有环fast后两步就不能为空,为空肯定没有环
		return NULL;
	LNode *p1=L,*p2=slow;//为何设置p1和p2分别在头结点处和相遇处,见分析
	while(p1!=p2){
	p1=p1->link;
	p2=p2->link;
	}//设置好p1和p2,一直走下去必定能够找到入口处,见分析
	printf("环的起始点:%d\n",p1->data);
	return p1;
}

 

int main(){
	LinkList head;
	InitListDai(head);
	List_TailInsertDai(head);
	printListDai(head);
	MakeACircle(head);
	FindLoopStart(head);
	printf("\n");
	return 0;
}

25.

#include<stdio.h>  
#include<stdlib.h>  
 
typedef struct LNode{    
	int data;    
	struct LNode *link;     
}LNode, *LinkList; 
 
 
bool InitListDai(LinkList &list){
	list=(LNode*)malloc(sizeof(LNode));
	if(list==NULL) return false;
	list->link=NULL;
	return true;
}
 
//打印单链表 带头
void printListDai(LinkList list){
    if (list->link==NULL) {
        printf("链表为空,打印失败\n");
    }else{
        while (list->link!= NULL) {
            printf("%d ",list->link->data);
            list = list->link;
        }
        printf("\n");
    }
}
 
//尾插法 带头
LinkList List_TailInsertDai(LinkList &list){
	int x;
	list=(LNode *)malloc(sizeof(LNode));
	LNode *r=list;
	LNode *s;
	scanf("%d",&x);
	while(x!=9999){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=x;
		r->link=s;
		r=s;
		scanf("%d",&x);
	}
	r->link=NULL;
	return list;
}

//重新排列带头单链表的结点顺序
void Change_List(LinkList &L){
	LNode *p,*q,*r,*s;
	p=L;
	q=L;
	while(q->link!=NULL){//寻找中间结点p
		p=p->link;//p走一步
		q=q->link;//q走第一步
		if(q->link!=NULL)//符合条件q走第二步
			q=q->link;
	}
	q=p->link;
	//若链表为奇数个数,例如1 2 3 4 5 此时p指向3,q指向4
	//若链表为偶数个数,例如1 2 3 4 5 6 此时p指向3,q指向4
	//可知p指向中间结点,q指向后半段链表的首结点,q开始全部要逆置
	//逆置时采用指针反向思想,先把第一个结点拆开,将其作为最后一个结点,后续指针全部反向
	p->link=NULL;//先把前后两部分拆开,即拆开p
	while(q!=NULL){//头插法逆置思想
		r=q->link;//防止断链
		q->link=p->link;//让q的下一个结点指向p所指向的NULL
		p->link=q;//再把p原本指向NULL的指针指向q
		//以上几步使得p指向q,q指向NULL
		q=r;//继续处理下一个结点
	}//逆置完成,1 2 3 4 5 可变成 1 2 3 5 4 ,1 2 3 4 可变成 1 2 4 3
	s=L->link;//s指向前半部分第一个结点
	q=p->link;//q指向后半部分第一个结点
	p->link=NULL;//再次把前后两部分拆开,即拆开p
	while(q!=NULL){
		r=q->link;//设置到重新插入操作,r防止断链
		q->link=s->link;//把q插入到s的后面,例如本来s后面是1,现在让q的后面变成1,下一步让s的后面变成q即可
		s->link=q;
		s=q->link;//继续在前半部分当前结点的下一个结点后面插入结点,而下一个待操作的结点现在变成了q->link
		q=r;//后半部分当前结点插入完成,继续操作后半部分的下一个结点
	}
	printf("重新排列带头单链表的结点顺序完成!\n");
}

int main(){
	LinkList head;
	InitListDai(head);
	List_TailInsertDai(head);
	printListDai(head);
	Change_List(head);
	printListDai(head);
	printf("\n");
	return 0;
}

本章完

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值