其他分享
首页 > 其他分享> > 小甲鱼笔记:数据结构——线性表(四)循环链表和双向链表,约瑟夫问题,魔术师发牌问题,判断一个单链表是否有环

小甲鱼笔记:数据结构——线性表(四)循环链表和双向链表,约瑟夫问题,魔术师发牌问题,判断一个单链表是否有环

作者:互联网

一、循环链表

1. 背景

2.初始化循环链表

void ds_init(node **pNode)//**表示链表上的一个元素 如果
{
	int item;
	node *temp;
	node *target;

	printf("输入结点的值,输入0完成初始化\n");
	while(1){
		scanf("%d",&item);
		fflush(stdin);
		if(item == 0)
			return;
		
		if((*pNode) ==NULL){
		/*循环链表中只有一个结点*/
		*pNode =(node*)malloc(sizeof(struct CLinkList));
		if(!(*pNode)){
			exit(0);
			(*pNode)->data = item;
			(*pNode)->next =*pNode;
			}
		else{
			/*找到next指向第一个结点的结点*/
			for(target =(*pNode);target->next !=(*pNode);target =target->next)
				;
			/*生成一个新结点*/
			temp = (node *)malloc(sizeof(struct CLinkList));

			if(!temp)
				exit(0);
			temp->data = item;
			temp->next = *pNode;
			target->next =temp;
		}
	} 
}

3. 循环链表的插入

/*链表存储结构的定义*/
typedef struct CLinkList{
	int data;
	struct CLinkList *next;
}node;

/*插入结点*/
/*参数:链表的第一个结点,插入的位置*/
void ds_insert(node **pNode,int i){
	node *temp;
	node *target;
	node *p;
	int item;
	int j = 1;
	printf("请输入要插入结点的值:");
	scanf(”%d“,&item);
	
	if(i =1){
		//新插入的节点作为第一个节点
		temp =(node *)malloc(struct CLinkList);

		if(!temp)
			exit(0);
		
		temp->data =item;
	/*寻找最后一个节点*/
	for(target =(*pNode);target->next!=(*pNode);target =target->next)	
			;
		temp->next =(pNode);
		target->next =temp;
		*pNode =temp;
	}
	else{
		target =*pNode;
		for(;j < (i-1);++j){
			target=target->next;
		}
		//target指向第三个元素
		temp = (node *)malloc(sizeof(struct CLinkList));
		if(!temp)
			exit(0);
		temp->data =item;
		p = target->next;
		target->next = temp;
		temp->next = p;
	}
}

4. 循环链表的删除

void ds_delete(node **pNode,int i){
	node *target;
	node *temp;
	int j = 1;
	if(i == 1){
	//删除的第一个结点
	/*找到最后一个结点*/
	for(target = *pNode;target->next !=*pNode;target = target->next)
		;
		temp =*pNode;
		*pNode =(*pNode)->next;
		target->next =*pNode;
		free(temp);
	}
	else{
		target= *pNode;
		for(;j<i-1;++j){
			target=target->next;
		}
		temp = target->next;
		target->next = temp->next;
		free(temp);
	}
}

5. 返回结点所在的位置

int ds_search(node *pNode,int elem){
	node *target;
	int i = 1;
	for(target = pNode;target->data !=elem && target->next !=pNode;++i){
		target = target->next;
	}
	if(target->next == pNode)/*表中不存在改元素*/
		return 0;
	else
		return 1;
}

二、约瑟夫问题

1.问题提出

2. 代码实现

#include <stdio.h>
#include <stdlib.h>
typeof struct node{
	int data;
	struct node *next;
}node;
node *create(int n){
	node *p =NULL,*head;
	head = (node *)malloc(sizeof (node ));
	p = head;
	node *s;
	int i = 1;
	
	if( 0 !=n ){
		while( i <= n){
			s = (node *)malloc(sizeof(node));
			s->data = i++;
			p->next = s;
			p = s;
		}
		s->next = head->next;
	}
	free(head);
	
	return s->next;
}

int main(){
	int n = 41;
	int m = 3;
	int i;
	node *p = create(n);
	node *temp;
	m %=n;
	
	while( p !=p->next){
		for(i = 1;i <= m-1;i++){
			p = p->next; 
		}
		printf("%d->",p->next->data);
		
		temp = p->next;		//删除第m个节点
		p->next = temp->next;
		free(temp);
		
		p = p->next;
	}
	printf("%d\n",p->data);
	return 0;
}

三、循环链表的特点

在这里插入图片描述

1、例题:实现将两个线性表(a1,a2,…,an)和(b1,b2,…,bm)连接成一个线性表()a1,…,an,b1,…,bm)的运算

2、代码实现

//假设A,B为非空循环链表的尾指针
LinkList Connect(LinkList A,LinktList B){
	LinkList p = A-<next; //保存A表的头结点位置
	
	A->next = B->next->next;//B表的开始结点连接到A表尾

	free(B->next);//释放B表的头结点

	B->next = p;

	return B;//返回新循环链表的尾指针
}

四、判断单链表是否有环

#include "stdio.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef int Status;/*Status是函数的类型,其值是函数结果状态代码*/
typedef int ElemType;/*ElemType类型根据实际情况而定,这里假设为int*/

typedef struct Node{
	ElemType data;
	struct Node *next;
}Node,* LinkList;

/*初始化带头结点的空链表*/
Status InitList(LinkList *L){
	*L = (LinkList)malloc(sizeof(Node));/*产生头结点,并使L指向此头结点*/
	if(!(*L))/*存储分配失败*/
		return ERROR;
	(*L)->next = NULL;/*此指针域为空*/
	
	return OK;
}

/*初始条件:顺序线性表L已存在,操作结果:返回L中数据元素个数*/
int ListLength(LinkList L){
	int i = 0;
	LinkList p = L->next;//p指向第一个结点
	while(p){
		i++;
		p=p->next;
	}
	return i;
}
/*随机产生n个元素的值,建立带表头结点的单链线性表L(头插法)*/
void CreateListHead(LinkList *L,int n){
	ListList p;
	int i;
	srand(time);	//初始化随机数种子
	*L = (LinkList)malloc(sizeof(Node));
	(*L)->next =NULL;		//建立一个带头结点的单链表
	for(i = 0;i < n;i++){
		p = (LinkList)malloc(sizeof(Node));
		p->data = rand()%100 +1;	//随机产生100以内的数字
		p->next = (*L)->next;	
		(*L)->next = p;			//插入到表头
	}
}

/*随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法)*/
void CreateListTail(LinkList *L,int n){
	LinkList p,r;
	int i;
	
	srand(time(0));						//初始化随机数种子
	*L=(LinkList)malloc(sizeof(Node));	//L为整个线性表
	r = *L;								//r为指向尾部的结点

	for(i = 0;i < n ;i++){
		p->(Node)malloc(sizeof(Node));
		p->data = rand()%100+1;
		r->next = p;					//将表尾的终端节点的指针指向新结点
		r = p;							//将当前的新结点定义为表尾终端结点
	}
		r->next =(*L)->next->next;
}

//比较步数的方法 
int HasLoop1(LinkList L){
	LinkList cur1 = L;//定义结点 cur1
	int pos1 = 0; 		//cur1 的步数
	
	while(cur1){
		LinkList cur2 = L;				//定义结点cur2
		int pos2 = 0;					
		while(cur2){
			if(cur2 == cur1){			
				if(pos1 ==pos2)			//走过的步数一样
					break;				//说明没有环
				else{					//否则
					printf("环的位置在第%d个结点处:\n\n",pos2);
					return 1;			//有环并返回1
					}
				}
				cur2  = cur2->next;
				pos2 ++;				//cur2步数自增
			}
			cur1 = cur1->next;			//cur1继续向后一个结点
			pos1++;						//cur1步数自增
	}
			return 0;
}

//利用快慢指针
int HasLoop2(LinkList L){
	int step1 = 1;
	int step2 = 2;
	LinkList p = L;
	ListList q = L;
	
	while(p !=NULL && q !=NULL && q->next !=NULL){
		p = p->next;
		if(q->next !=NULL)
			q = q->next->next;
		
		printf(“p:%d,q:%d\n”,p->data,q->data);
		
		if(p == q){
			return 1;
		}
		return 0;
	}

int main(){
	LinkList L;
	Status i;
	char opp;
	ElemType e;
	int find;
	int temp;
	
	i = InitList(&L);
	printf("初始化L后:ListLength(L)=%d\n",ListLength(L))

	printf("\n1.创建有环链表(尾插法) \n2创建无循环链表(头插法)\n3.判断链表是否有环");
	while( opp !=''0){
		scanf("%c",&opp);
		switch(opp){
			case '1':
				CreateListTail(&L.20);
				printf("成功创建有环L(尾插法)\n");
				printf("\n");
				break;
			case '2':
				CreateListHead(&L,20); 
				printf("成功创建无环L(头插法)\n");
				printf("\n");
				break;
			case '3':
				printf("方法一:");
				if(HasLoop1(L)){
					printf("有环");
				}
				else{
					printf("无环");
				}
				printf("方法二:");
				if(HasLoop12(L)){
					printf("有环");
				}
				else{
					printf("无环");
				}
		}
	}
	
}

}

五、双向链表

1. 概述

2.双向链表的插入操作

在这里插入图片描述

s->next = p;
s->prior = p->prior;
p->prior->next = s;
p->prior = s;

3. 双向链表的删除操作

在这里插入图片描述

p->prior->next = p->next;
p->next->prior = p->prior;
free(p)

4. 小结

六、双向链表实战

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

#define OK 1
#define ERROR  0

typedef char ElemType;
typedef int  Status;//状态返回
typedef struct DualNode;//定义双向循环链表

typedef struct DualNode{
	ElemType data;
	struct DualNode *prior;
	struct DualNode *next;
}DualNode, *DuLinkList;

/*
* 
* 初始化循环链表
*/
Status InitList(DuLinkList *L) {
	DualNode *p, *q;
	int i;
	*L = (DuLinkList)malloc(sizeof(DualNode));
	if (!(*L)) {
		return ERROR;
	}
	(*L)->next = (*L)->prior = NULL;
	p = (*L);

	for ( i = 0; i < 26; i++)
	{
		q = (DualNode *)malloc(sizeof(DualNode));
		if (!q)
		{
			return ERROR;
		}
		q->data = 'A' + i;
		q->prior = p;
		q->next = p->next;	//p->next为NULL,让q->next = p->next ,此时q->next应当为NULL
		p->next = q;		//p->next 指向q结点

		p = q;				//让 p = q 让他们为同一个结点
	}
	p->next = (*L)->next;
	(*L)->next->prior = p;

	return OK;
}


void Caesar(DuLinkList *L, int i) {
	if (i > 0)
	{
		do
		{
			
			(*L) = (*L)->next;
		} while ( --i);
	}
	if (i < 0)
	{
		do 
		{
			(*L) = (*L)->next;
		} while (++i);
	}

}

int main() {
	DuLinkList L;
	int i,n;

	InitList(&L);
	printf("请输入一个整数:");
	scanf("%d",&n);
	printf("\n");
	Caesar(&L, n);
	for ( i = 0; i < 26; i++)
	{
		L = L->next;
		printf("%c",L->data);
	}
	return 0;
}

标签:结点,线性表,temp,int,next,链表,发牌,target
来源: https://blog.csdn.net/Mr_GYF/article/details/114824241