zoukankan      html  css  js  c++  java
  • 循环链表设计与API实现

    基本概念
    循环链表的定义:将单链表中最后一个数据元素的next指针指向第一个元素

    循环链表拥有单链表的全部操作

    创建链表
    销毁链表
    获取链表长度
    清空链表
    获取第pos个元素操作
    插入元素到位置pos
    删除位置pos处的元素

    新增功能:游标的定义

    在循环链表中能够定义一个“当前”指针,这个指针通常称为游标,能够通过这个游标来遍历链表中的全部元素。

    循环链表新操作

    将游标重置指向链表中的第一个数据元素
    CircleListNode* CircleList_Reset(CircleList* list);

    获取当前游标指向的数据元素
    CircleListNode* CircleList_Current(CircleList* list);

    将游标移动指向到链表中的下一个数据元素
    CircleListNode* CircleList_Next(CircleList* list);

    直接指定删除链表中的某个数据元素
    CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node);
    // 依据元素的值 删除 元素 pk依据元素的位置 删除 元素

    最后加了一个循环链表的应用:求解约瑟夫问题

    约瑟夫问题-循环链表典型应用
    n 个人围成一个圆圈,首先第 1 个人从 1 開始一个人一个人顺时针报数,报到第 m 个人,令其出列。

    然后再从下一 个人開始从 1 顺时针报数,报到第 m 个人。再令其出列,…。如此下去,求出列顺序。

    代码:

    // circlelist.h
    // 循环链表API声明
    
    #ifndef _CIRCLELIST_H_
    #define _CIRCLELIST_H_
    
    typedef void CircleList;
    
    typedef struct _tag_CircleListNode
    {
    	struct _tag_CircleListNode *next;
    }CircleListNode;
    
    // 创建链表
    CircleList* CircleList_Create();
    
    // 销毁链表
    void CircleList_Destroy(CircleList* list);
    
    // 清空链表
    void CircleList_Clear(CircleList* list);
    
    // 获取链表的长度
    int CircleList_Length(CircleList* list);
    
    // 在pos位置插入结点node
    int CircleList_Insert(CircleList* list,CircleListNode* node, int pos);
    
    // 获取pos位置的结点
    CircleListNode* CircleList_Get(CircleList* list, int pos);
    
    // 删除pos位置的结点
    CircleListNode* CircleList_Delete(CircleList* list, int pos);
    
    // 依据结点的值进行数据删除
    CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node);
    
    // 重置游标
    CircleListNode* CircleList_Reset(CircleList* list);
    
    // 获取当前游标所指结点
    CircleListNode* CircleList_Current(CircleList* list);
    
    // 将原始游标所指结点返回给上层,然后让游标移到下一个结点
    CircleListNode* CircleList_Next(CircleList* list);
    
    #endif

    // circlelist.cpp
    // 循环链表API实现
    
    #include <iostream>
    #include <cstdio>
    #include "circlelist.h"
    
    typedef struct _tag_CircleList
    {
    	CircleListNode header;
    	CircleListNode *silder;
    	int length;
    }TCircleList;
    
    // 创建链表
    CircleList* CircleList_Create()
    {
    	TCircleList *ret = (TCircleList *)malloc(sizeof(TCircleList));
    	if (ret == NULL) {
    		return NULL;
    	}
    
    	// 初始化
    	ret->header.next = NULL;
    	ret->silder = NULL;
    	ret->length = 0;
    
    	return ret;
    }
    
    // 销毁链表
    void CircleList_Destroy(CircleList* list)
    {
    	if (list == NULL) {
    		return;
    	}
    	free(list);
    	return;
    }
    
    // 清空链表
    void CircleList_Clear(CircleList* list)
    {
    	if (list == NULL) {
    		return;
    	}
    	TCircleList *tList = (TCircleList *)list;
    	tList->header.next = NULL;
    	tList->silder = NULL;
    	tList->length = 0;
    
    	return;
    }
    
    // 获取链表的长度
    int CircleList_Length(CircleList* list)
    {
    	if (list == NULL) {
    		return -1;
    	}
    	TCircleList *tList = (TCircleList *)list;
    	return tList->length;
    }
    
    // 在pos位置插入结点node
    int CircleList_Insert(CircleList* list, CircleListNode* node, int pos)
    {
    	if (list == NULL || node == NULL || pos < 0) {
    		return -1;
    	}
    
    	TCircleList *tList = (TCircleList *)list;
    
    	CircleListNode *cur = (CircleListNode *)tList;
    
    	for (int i = 0; i < pos; ++i) {
    		cur = cur->next;
    	}
    
    	node->next = cur->next;
    	cur->next = node;
    
    	// 假设是第一次插入
    	if (tList->length == 0) {
    		tList->silder = node;
    	}
    
    	++tList->length; // 记得长度加1
    
    	// 假设是头插法
    	if (cur == (CircleListNode *)tList) {
    		// 获取最后一个元素
    		CircleListNode *last = CircleList_Get(tList, tList->length - 1);
    		last->next = cur->next;
    	}
    
    	return 0;
    }
    
    // 获取pos位置的结点
    CircleListNode* CircleList_Get(CircleList* list, int pos)
    {
    	// 由于是循环链表,所以这里不须要排除pos>length的情况
    	if (list == NULL || pos < 0) {
    		return NULL;
    	}
    
    	TCircleList *tList = (TCircleList *)list;
    	CircleListNode *cur = (CircleListNode *)tList;
    
    	for (int i = 0; i < pos; ++i) {
    		cur = cur->next;
    	}
    
    	return cur->next;
    }
    
    // 删除pos位置的结点
    CircleListNode* CircleList_Delete(CircleList* list, int pos)
    {
    	TCircleList *tList = (TCircleList *)list;
    	CircleListNode *ret = NULL;
    
    	if (tList != NULL && pos >= 0 && tList->length > 0) {
    		CircleListNode *cur = (CircleListNode *)tList;
    		for (int i = 0; i < pos; ++i) {
    			cur = cur->next;
    		}
    
    		// 若删除头结点,须要求出尾结点
    		CircleListNode *last = NULL;
    		if (cur == (CircleListNode *)tList)  {
    			last = CircleList_Get(tList, tList->length - 1);
    		}
    
    		ret = cur->next;
    		cur->next = ret->next;
    
    		--tList->length;
    
    		// 若删除头结点
    		if (last != NULL) {
    			tList->header.next = ret->next;
    			last->next = ret->next;
    		}
    
    		// 若删除的元素为游标所指的元素
    		if (tList->silder == ret) {
    			tList->silder = ret->next;
    		}
    
    		// 若删除元素后链表长度为0
    		if (tList->length == 0) {
    			tList->header.next = NULL;
    			tList->silder = NULL;
    		}
    	}
    
    	return ret;
    }
    
    // 依据结点的值进行数据删除
    CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node)
    {
    	TCircleList *tList = (TCircleList *)list;
    	CircleListNode *ret = NULL;
    
    	if (list != NULL && node != NULL) {
    		CircleListNode *cur = (CircleListNode *)tList;
    		int i = 0;
    		for (i = 0; i < tList->length; ++i) {
    			if (cur->next == node) {
    				ret = cur->next;
    				break;
    			}
    
    			cur = cur->next;
    		}
    
    		// 假设找到
    		if (ret != NULL) {
    			CircleList_Delete(tList, i);
    		}
    	}
    
    	return ret;
    }
    
    // 重置游标
    CircleListNode* CircleList_Reset(CircleList* list)
    {
    	TCircleList *tList = (TCircleList *)list;
    	CircleListNode* ret = NULL;
    
    	if (list != NULL) {
    		tList->silder = tList->header.next;
    		ret = tList->silder;
    	}
    
    	return NULL;
    }
    
    // 获取当前游标所指结点
    CircleListNode* CircleList_Current(CircleList* list)
    {
    	TCircleList *tList = (TCircleList *)list;
    	CircleListNode* ret = NULL;
    	if (list != NULL) {
    		ret = tList->silder;
    	}
    
    	return ret;
    }
    
    // 将原始游标所指结点返回给上层,然后让游标移到下一个结点
    CircleListNode* CircleList_Next(CircleList* list)
    {
    	TCircleList *tList = (TCircleList *)list;
    	CircleListNode* ret = NULL;
    	if (list != NULL && tList->silder != NULL) {
    		ret = tList->silder;
    		tList->silder = ret->next;
    	}
    	return ret;
    }

    // joseph.h
    // 用循环链表API求解约瑟夫问题
    
    #include <cstdio>
    #include "circlelist.h"
    
    const int maxp = 8;
    
    struct Person
    {
    	CircleListNode circlenode;
    	int id;
    };
    
    void joseph()
    {
    	Person s[maxp];
    	for (int i = 0; i < maxp; ++i) {
    		s[i].id = i + 1;
    	}
    
    	CircleList *list = NULL;
    	list = CircleList_Create();
    
    	// 插入元素
    	for (int i = 0; i < maxp; ++i) {
    		// 尾插法
    		int ret = CircleList_Insert(list, (CircleListNode *)&s[i], CircleList_Length(list));
    		if (ret < 0) {
    			printf("function CircleList_Insert err: %d
    ", ret);
    		}
    	}
    
    	// 遍历链表
    	for (int i = 0; i < CircleList_Length(list); ++i) {
    		Person *tmp = (Person *)CircleList_Get(list, i);
    		if (tmp == NULL) {
    			printf("function CircleList_Get err.
    ");
    		}
    		printf("age: %d
    ", tmp->id);
    	}
    
    	// 求解约瑟夫问题
    	while (CircleList_Length(list) > 0)
    	{
    		Person* pv = NULL;
    		for (int i = 1; i < 3; i++)
    		{
    			CircleList_Next(list);
    		}
    		pv = (Person*)CircleList_Current(list);
    		printf("%d ", pv->id);
    		CircleList_DeleteNode(list, (CircleListNode *)pv); //依据结点的值,进行结点元素的删除
    	}
    	printf("
    ");
    
    	CircleList_Destroy(list);
    
    }

    // main.cpp
    // 循环链表測试程序
    
    #include <iostream>
    #include <cstdio>
    #include "circlelist.h"
    #include "joseph.h"
    
    const int maxn = 5;
    
    struct Student
    {
    	CircleListNode circlenode;
    	char name[32];
    	int age;
    };
    
    void play01()
    {
    	Student s[maxn];
    	for (int i = 0; i < maxn; ++i) {
    		s[i].age = i + 1;
    	}
    
    	CircleList *list = NULL;
    
    	list = CircleList_Create(); // 创建链表
    
    	// 插入元素
    	for (int i = 0; i < maxn; ++i) {
    		// 尾插法
    		int ret = CircleList_Insert(list, (CircleListNode *)&s[i], CircleList_Length(list));
    		if (ret < 0) {
    			printf("function CircleList_Insert err: %d
    ", ret);
    		}
    	}
    
    	// 遍历链表
    	// 这里遍历打印两边,能够证明这是一个循环链表
    	for (int i = 0; i < 2 * CircleList_Length(list); ++i) {
    		Student *tmp = (Student *)CircleList_Get(list, i);
    		if (tmp == NULL) {
    			printf("function CircleList_Get err.
    ");
    		}
    		printf("age: %d
    ", tmp->age);
    	}
    
    	// 删除结点,通过结点位置
    	while (CircleList_Length(list)) {
    		Student *tmp = (Student *)CircleList_Delete(list, CircleList_Length(list) - 1);
    		if (tmp == NULL) {
    			printf("function CircleList_Delete err.
    ");
    		}
    		printf("age: %d
    ", tmp->age);
    	}
    
    	// 销毁链表
    	CircleList_Destroy(list);
    
    }
    
    int main()
    {
    	play01(); // 为了測试数据的生命周期,所以另写一个函数调用执行
    	joseph();
    
    	return 0;
    }

  • 相关阅读:
    图书排列
    L1-059 敲笨钟 (20 分)
    区间移位
    取球博弈
    poj 2456 Aggressive cows
    对局匹配
    发现环
    数字划分
    哥德巴赫分解
    把数组排成最小的数
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/7156802.html
Copyright © 2011-2022 走看看