环形链表

虽然现在开发多用Java了,闲着没事拿指针来练练手还是挺有意思的。约瑟夫的问题的解决方案有很多,可以用一个循环10不到解决,但要推导出一个公式;用一维数组加两个循环也可以,这种删除一个数据,后面元素的下标都要跟着变,不太可取。

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

typedef struct Linknode
{
	int data;
	struct Linknode *pNext;
}node,*PNODE;

//尾部插入
PNODE addback(PNODE phead,int data){
	PNODE pnew= (PNODE)malloc(sizeof(node));
	pnew->data=data;
	if(phead==NULL){//一个节点的环
		phead=pnew;
		pnew->pNext=phead;
	}
	else{//多个节点
		PNODE p=phead;
		while(p->pNext!=phead){//循环到尾部
			p=p->pNext;
		}
		p->pNext=pnew;//链接到新的节点
		pnew->pNext=phead;//头尾相连
	}
	return phead;
}
//头部插入
PNODE addfront(PNODE phead,int data){

	PNODE pnew=((PNODE)malloc(sizeof(node)));
	pnew->data=data;
	//一个节点的环
	if(phead==NULL){
		phead=pnew;
		pnew->pNext=phead;
	}else{	//多个节点
		PNODE p=phead;
		while(p->pNext!=phead){//循环到尾部
			p=p->pNext;
		}
		p->pNext=pnew;
		pnew->pNext=phead;
		phead=pnew;
	}
	return phead;
} 

void showall(PNODE phead){
	printf("----------------showall-----------------\n");
	if(phead==NULL){
		return;
	}else if(phead->pNext==phead){//只有一个节点
		printf("%d,%p,%p",phead->data,phead,phead->pNext);
	}else{
		PNODE p=phead;
		while(p->pNext!=phead){
		  printf("\n%d,%p,%p",p->data,p,p->pNext);
		  p=p->pNext;
		}
		printf("\n%d,%p,%p",p->data,p,p->pNext); //补充相等的情况
	}
}

PNODE findfirst(PNODE phead,int data){//找到第一个对应值为data的结点
	if(phead==NULL){
	  return NULL;
	}else if(phead->pNext==phead){
		//只有一个节点
		if(phead->data==data){
		  return phead;
		}
	}else{
		PNODE p=phead;
		while(p->pNext!=phead){
			if(p->data==data){
				return phead;
			}
		  p=p->pNext;
		}
		if(p->data==data){
			return phead;
		}
	}
} 

PNODE deletefirst(PNODE phead,int data,PNODE* ppNext){//删除第一个对应值为data的结点
	PNODE p1=NULL;
	PNODE p2=NULL;
	p1=phead;
	while(p1->pNext!=phead){
		if(p1->data==data){
			break;
		}else{
			p2=p1;
			p1=p1->pNext;
		}
	}
	if(p1!=phead){
		p2->pNext=p1->pNext;
		*ppNext=p1->pNext;
		free(p1);
	}else{//刚好是头结点
		PNODE p=phead;
		while(p->pNext!=phead){
			p=p->pNext;
		}
		phead=phead->pNext;
		*ppNext=p1->pNext;
		free(p1);
		p->pNext=phead;
	}
	return phead;
}

int getnum(PNODE phead){//计算结点的个数
   	if(phead==NULL){
	  return 0;
	}else if(phead->pNext==phead){
		//只有一个节点
		return 1;
	}else{
		int i=1;
		PNODE p=phead;
		while(p->pNext!=phead){
		  i++;
		  p=p->pNext;
		}
		return i;
	}
}

//如果存在结点值为finddata的结点,则在其前面插入data
PNODE insertfirst(PNODE phead,int finddata,int data){

	PNODE p1=NULL;
	PNODE p2=NULL;
	p1=phead;
	while(p1->pNext!=phead){
		if(p1->data==finddata){
			break;
		}else{
			p2=p1;
			p1=p1->pNext;
		}
	}

	PNODE pnew=((PNODE)malloc(sizeof(node)));
	pnew->data=data;

	if(p1!=phead){
		pnew->pNext=p1;
		p2->pNext=pnew;
	}else{//刚好是头结点
		PNODE p=phead;
		while(p->pNext!=phead){//循环到尾部
			p=p->pNext;
		}
		p->pNext=pnew;
		pnew->pNext=phead;
		phead=pnew;
	}
	return phead;	

}

main(){
//	printf("node有%d字节\n",sizeof(node));
//	printf("PNODE有%d字节\n",sizeof(PNODE));

	PNODE phead=NULL;
	printf("----------------addfront-----------------\n");
	for(int i=0;i<5;i++){
		phead=addfront(phead,i);//插入数据
	}
	showall(phead);

//	printf("\n----------------addback-----------------\n");
//	phead=NULL;
//	for(int i=0;i<5;i++){
//		phead=addback(phead,i);//插入数据
//	}
//	showall(phead);
//
//	printf("\n---- findfirst(找到第一个值为3的结点)-----------------\n");
//	PNODE pfind=findfirst(phead,3);
//	pfind->data=77777;
//	showall(phead);
//
//	printf("\n------deletefirst(删除值为2的结点)-----------------\n");
//	phead=deletefirst(phead,2);
//	showall(phead);
//
//	printf("\n------insertfirst(在结点为4的前面插入999999999)-----------------\n");
//	phead=insertfirst(phead,4,999999999);
//	showall(phead);

    printf("\n\n\n");
    //约瑟夫问题
	PNODE p=phead;
	while(getnum(phead)!=1){
		for(int i=1;i<=3;i++){
			p=p->pNext;
		}
		phead=deletefirst(phead,p->data,&p);
		//删除之后p要从下一个结点继续,所以需有第 3个参数改变其地址
		printf("\n");
		showall(phead);
	}
	printf("\n");
	printf("最后剩下的是%d\n",phead->data);

}

版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载,请注明出处:http://blog.csdn.net/lindonglian

时间: 2024-11-04 21:03:04

环形链表的相关文章

环形链表---Java

/** * * @author Administrator * 功能:丢手帕问题 */ package com.litao; public class Demo4 { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub CycLink cycLink = new CycLink(); cycLink.setLen(9); cycLink.createLin

约瑟夫问题 环形链表及递归

//--------------------环形链表 //#include <windows.h> //#include <iostream> //using namespace std; // //#define R 40//人数 //#define N 4//每隔多少删去一个节点 // //struct node //{ // int id; // node *next; //}; // //void initCircle(node *phead, int num) //{ /

php实现单,双向链表,环形链表解决约瑟夫问题

传智播客PHP学院 韩顺平 PHP程序员玩转算法第一季  http://php.itcast.cn 聊天篇: 数学对我们编程来说,重不重要? 看你站在什么样的层次来说. 如果你应用程序开发,对数学要求不高 但是,如果你开发系统软件,比如(搜索/识别软件[图像,语言识别]/操作系统...)对数学高 建模.大量数学模型. 老师啊啊.我是学C++的.麻烦,谈哈对QT和MFC的看法嘛.前景什么的, 记住 : 打好基础,大有可为! 初中毕业能去传智学习吗? 学习It, 不管是java ,php ,c#,对

C# 数据结构 - 单链表 双链表 环形链表

链表特点(单链表 双链表) 优点:插入和删除非常快.因为单链表只需要修改Next指向的节点,双链表只需要指向Next和Prev的节点就可以完成插入和删除操作. 缺点:当需要查找某一个节点的时候就需要一个节点一个节点去访问,这样所花的时候就比较多了.(顺序表可以弥补这缺点,但插入和删除就非常耗性能) 单链表 单链表的构成:必须要有一个链表头(head),每个节点里面有一个Next用于指向下一个节点(类似于指针).最后一个节点的Next为null来标识链表的尾. 如下图 代码实现 1 /* ----

二叉树转换为双向环形链表

二叉树的节点与双向环形链表的节点类似,均含有两个指向不同方向的指针,因此他们之间的转化是可以实现的.下面介绍一种递归的实现方法.由于方法比较简单,就直接上代码了 二叉树的建立 node* create(const string& s) { node* res = new node; res->left = nullptr; res->right = nullptr; res->s = s; return res; } node* insert(node* root, const

代码题(15)— 环形链表

1.141. 环形链表 给定一个链表,判断链表中是否有环. /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: bool hasCycle(ListNode *head) { if(head == nullptr || h

java 环形链表实现约瑟夫(Joseph)问题

约瑟夫问题又名丢手绢问题.相传著名犹太历史学家 Josephus 利用其规则躲过了一场自杀游戏,而后投降了罗马. 问题: 已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.* 从编号为k的人开始报数,数到m的那个人出列:* 他的下一个人又从1开始报数,数到m的那个人又出列:* 依此规律重复下去,直到圆桌周围的人全部出列. 用节点来模拟游戏中的人,用链表来表示游戏中的人按一定的顺序排列.每一个节点给一个编号,从编号为k的节点开始计数,计到m的节点从链表中退出.之后m的下一个节点从新

142#环形链表2

题目描述 142#环形链表 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 说明:不允许修改给定的链表. 进阶: 你是否可以不用额外空间解决此题? 分析 使用双指针可以解决该问题. 链表没有环的判定可以参考第141题,环形链表. 现在在链表有环的情况下分析.设一个快指针和一个慢指针,这两个指针的初始位置都在head,慢指针移动速度为1,快指针是它的两倍. 如图,设从head到环形开始结点的距离是A,慢指针从环形开始结点走到相遇点走过的路程是B,环的长度是L(画图的

实现约瑟夫环形链表

题目 41个人排成一个圆圈,由第1个人 开始报数,每报数到第3人,该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止.约瑟夫与朋友在第16与第31个位置,于是活了下来.请用单向环形链表描述该结构并呈现整个自杀过程. 设计 首先要设计一个节点模型 class Node { int value; Node next; Node(int value) { this.value = value; } } 遍历并用 last 节点做成一个单向线性的链表,之后将自身的初始节点指向last.ne

Leetcode 142.环形链表II

环形链表II 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 说明:不允许修改给定的链表. 进阶:你是否可以不用额外空间解决此题? 链表头是X,环的第一个节点是Y,slow和fast第一次的交点是Z.各段的长度分别是a,b,c,如图所示.环的长度是L. 第一次相遇时slow走过的距离:a+b,fast走过的距离:a+b+c+b. 因为fast的速度是slow的两倍,所以fast走的距离是slow的两倍,有 2(a+b) = a+b+c+b,可以得到a=c(这个结论