C语言单向链表实现

LinkList.h

#pragma once
typedef int SDataType;
//链表节点	
typedef struct SListNode {
	SDataType _data;
	struct SListNode* _PNext;
}Node,*PNode;

typedef struct SList { //封装链表结构,类似于头节点
	PNode _pHead;//指向链表的第一个节点
} Slist;



void SListInit(SList *s);//初始化链表

void SListPushBack(SList* s, SDataType data);//在链表表尾部插入数据

void SListPopBack(SList* s);//删除链表最后一个节点

void SListPushFront(SList* s, SDataType data);//链表首部插入数据

void SListPopFront(SList* s);//删除链表第一个节点

void SListInsert(PNode pos, SDataType data);//在链表pos位置后插入数据

void SListErase(SList* s, PNode pos);//删除链表s中pos位置的节点

PNode SListFind(SList* s, SDataType data);//在链表s中查找数据data,查询成功返回指针,失败返回NULL

void SListRemove(SList* s, SDataType data);//移除链表中第一个值为data的元素

int SListSize(SList* s);//获取链表s的长度

int SListEmpty(SList* s);//检测链表是否为空

void SListClear(SList* s);//将链表中有效节点清空

void SListDestroy(SList* s);//销毁链表

void SListPrint(SList* s);//打印链表

 

LinkList.cpp

// LinkList.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "LinkList.h"


PNode BuySListNode(SDataType data) {
	Node* pNode = (Node*)malloc(sizeof(Node));
	pNode->_data = data;
	pNode->_PNext = NULL;
	return pNode;
}

void SListInit(SList* s) {
	//初始化链表
	assert(s);
	s->_pHead=BuySListNode(NULL);
}

void SListPushBack(SList* s, SDataType data) {
	//在链表表尾部插入数据
	//创建节点
		PNode pNewNode = BuySListNode(data);
		PNode pCur = s->_pHead;
		while (pCur->_PNext)
		{
			pCur = pCur->_PNext;
		}
		//最后一个节点指向新节点
		pCur->_PNext = pNewNode;
	
}

void SListPopBack(SList* s){
	//删除链表最后一个节点
	PNode pPre = s->_pHead;
	PNode pCur=pPre->_PNext;
	while (pCur->_PNext)
	{
		pPre = pCur;
		pCur = pCur->_PNext;
	}
	free(pCur);
	pPre->_PNext = NULL;
}

void SListPushFront(SList* s, SDataType data) {
	//链表首部插入数据
	PNode pNewNode = BuySListNode(data);
	pNewNode->_PNext = s->_pHead->_PNext;
	s->_pHead->_PNext = pNewNode;
}
void SListPopFront(SList* s){
	//删除链表第一个节点
	PNode pHead = s->_pHead;
	if (pHead) {//如果存在首节点
		PNode pFir = pHead->_PNext;
		PNode pSec = pFir->_PNext;
		pHead->_PNext = pSec;
		free(pFir);
	}
}void SListInsert(PNode pos, SDataType data) {
	//在链表pos位置后插入数据
	if (!pos) {
		return;
	}
	PNode pNew = BuySListNode(data);
	pNew->_PNext = pos->_PNext;
	pos->_PNext = pNew;
}

void SListErase(SList* s, PNode pos) {
	//删除链表s中pos位置的节点
	PNode pPre = s->_pHead;
	PNode pCur = pPre->_PNext;
	while (pCur&&pos!=pCur)
	{
		pPre = pCur;
		pCur = pCur->_PNext;
	}
	if (pCur) {
		pPre->_PNext = pCur->_PNext;
		free(pCur);
		pos = NULL;
	}

}

PNode SListFind(SList* s, SDataType data) {
	//在链表s中查找数据data,查询成功返回指针,失败返回NULL
	PNode pPre = s->_pHead;
	PNode pCur = pPre->_PNext;
	while (pCur&&pCur->_data!=data)
	{
		pPre = pCur;
		pCur = pCur->_PNext;
	}
	if (pCur) {
		return pPre->_PNext;
	}
	return NULL;
}

void SListRemove(SList* s, SDataType data) {
	//移除链表中第一个值为data的元素
	PNode pPre = s->_pHead;
	PNode pCur = pPre->_PNext;
	while (pCur && pCur->_data != data)
	{
		pPre = pCur;
		pCur = pCur->_PNext;
	}
	if (pCur) {
		pPre->_PNext = pCur->_PNext;
		free(pCur);
	}
}

int SListSize(SList* s) {
	//获取链表s的长度
	int count = 0;
	PNode pCur = s->_pHead;
	while (pCur->_PNext)
	{
		++count;
		pCur = pCur->_PNext;
	}
	return count;
}int SListEmpty(SList* s) {
	//检测链表是否为空
	return s->_pHead->_PNext == NULL ? 1 : 0;
}
void SListClear(SList* s) {
	//将链表中有效节点清空
	while (!SListEmpty(s))
	{
		SListPopFront(s);
	}
}

void SListDestroy(SList* s) {//销毁链表
	SListClear(s);
	free(s->_pHead);
}
void SListPrint(SList* s) {//打印链表
	PNode pCur = s->_pHead;
	while (pCur->_PNext)
	{
		pCur = pCur->_PNext;
		printf("%d\t",pCur->_data);
	}
	printf("\n");
}

 

约瑟夫问题是一个经典的数学问题,它的具体描述是:有n个人围成一圈,从第k个人开始报数,报到m的人出列,然后从下一个人开始重新报数,直到所有人都出列。现在我来介绍一下如何使用C语言单向链表实现约瑟夫问题。 首先,我们需要定义一个链表节点的结构体,包含两个成员变量:一个是保存人员编号的整型变量,另一个是指向下一个节点的指针。 ```c typedef struct Node { int data; struct Node* next; } Node; ``` 接下来,我们可以编写一个函数来创建一个包含n个节点的循环链表,并返回链表的头节点。 ```c Node* createCircularLinkedList(int n) { Node* head = NULL; Node* prev = NULL; for (int i = 1; i <= n; i++) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = i; if (head == NULL) { head = newNode; } else { prev->next = newNode; } prev = newNode; } prev->next = head; // 将最后一个节点的next指针指向头节点,形成循环链表 return head; } ``` 接下来,我们可以编写一个函数来模拟约瑟夫问题的求解过程。 ```c void josephusProblem(Node* head, int k, int m) { Node* current = head; Node* prev = NULL; // 找到从第k个人开始报数的节点 for (int i = 1; i < k; i++) { prev = current; current = current->next; } // 开始报数并出列,直到所有人都出列 while (current->next != current) { // 报数m次 for (int i = 1; i < m; i++) { prev = current; current = current->next; } // 出列 prev->next = current->next; Node* temp = current; current = current->next; free(temp); } // 输出最后一个出列的人员编号 printf("最后一个出列的人员编号:%d\n", current->data); // 释放头节点的内存 free(current); } ``` 最后,我们可以在主函数中调用上述函数来解决约瑟夫问题。 ```c int main() { int n, k, m; printf("请输入总人数n:"); scanf("%d", &n); printf("请输入从第k个人开始报数:"); scanf("%d", &k); printf("请输入报数m次出列:"); scanf("%d", &m); Node* head = createCircularLinkedList(n); josephusProblem(head, k, m); return 0; } ``` 这样,我们就可以通过C语言单向链表实现约瑟夫问题了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值