您的位置:首页 > 编程语言 > C语言/C++

单链表中一些经典的问题-->约瑟夫环,链表逆序,查找链表结点...(上)

2018-03-27 17:13 483 查看
上篇博客中写了关于单链表的一些基本操作,接下来是对单链表的一些扩展问题,接下来实现如下问题:

     ---->从尾到头打印单链表--->删除链表的非尾结点,不遍历链表--->约瑟夫环--->使用冒泡方式对单链表进行排序--->单链表的逆序---(三个指针)---->单链表的逆序---(使用头插法)--->合并两个有序链表,合并起来依然要有序--->查找链表的中间结点,只遍历一次链表--->查找链表的倒数第K个结点等等。

下面用C语言代码实现:

    slist.c

//从尾到头打印单链表
void PrintSlistTail(pNode pHead)  //递归方式
{
if (pHead)
{
PrintSlistTail(pHead->_pNext);
printf("%d-->", pHead->_data);
}
}

// 删除链表的非尾结点,要求不能遍历链表
void DeleteNotTailNode( pNode pos) //替换法
{
pNode pCur = NULL;
if (NULL == pos || NULL == pos->_pNext)
{
return;
}
pCur=pos->_pNext;
pos->_data=pos->_pNext->_data;
pos->_pNext = pos->_pNext->_pNext;
free(pCur);                //释放结点
}

// 约瑟夫环
void JosephCirclePre(pNode *pHead)  //构成环
{
assert(pHead);
pNode pCur = NULL;
if (*pHead == NULL)
{
return;
}
pCur = *pHead;
while (pCur->_pNext)
{
pCur = pCur->_pNext;
}
pCur->_pNext = *pHead;
}
void JosephCircle(pNode* pHead, const int M)  //删除结点
{
assert(pHead);
pNode pCur = NULL;
int count = 0;
if (*pHead == NULL)
{
return;
}
pCur = *pHead;
while (pCur!=pCur->_pNext)
{
count = M;
while (--count)
{
pCur = pCur->_pNext;
}
pCur->_data = pCur->_pNext->_data;
pCur->_pNext = pCur->_pNext->_pNext;
}
pCur->_pNext = NULL;
*pHead = pCur;
}
// 使用冒泡方式对单链表进行排序
void BubbleSort(pNode pHead)
{
assert(pHead);
int i = 0;
int j = 0;
pNode pCur =NULL;
int size = SListSize(pHead);
for (i = 0; i < size-1; i++)
{
pCur = pHead;
for (j = 0; j < size - 1 - i; j++)
{
if ((pCur->_data)>(pCur->_pNext->_data))
{
int tmp = pCur->_data;
pCur->_data = pCur->_pNext->_data;
pCur->_pNext->_data = tmp;
}
pCur = pCur->_pNext;
}
}
}

// 单链表的逆序---三个指针
void ReverseSList(pNode* pHead)
{
assert(pHead);
pNode pPre = NULL;
pNode pCur = NULL;
pNode pNext = NULL;
if (*pHead == NULL)
{
return;
}
pCur = *pHead;
while (pCur)
{
pNext=pCur->_pNext;
pCur->_pNext = pPre;
pPre = pCur;
pCur = pNext;
}
*pHead = pPre;
}

// 单链表的逆序---使用头插法
pNode ReverseSListOP(pNode pHead)
{
pNode pNewNode=NULL;
pNode pCur = pHead;
while (pCur)
{
SListPushFront(&pNewNode, pCur->_data);
pCur = pCur->_pNext;
}
return pNewNode;
}

// 合并两个有序链表,合并起来依然要有序
pNode MergeSList(pNode pHead1, pNode pHead2)
{
pNode pNewNode = NULL;
pNode pCur1 =NULL;
pNode pCur2 = NULL;
if (pHead1 == NULL)  //判空
{
return pHead2;
}
else if (pHead2 == NULL)
{
return pHead1;
}
pCur1 = pHead1;
pCur2 = pHead2;
while (pCur1!=NULL && pCur2!=NULL)
{
if ((pCur1->_data) < (pCur2->_data))
{
sListPushBack(&pNewNode, pCur1->_data);
pCur1 = pCur1->_pNext;
}
else
{
sListPushBack(&pNewNode, pCur2->_data);
pCur2 = pCur2->_pNext;
}
}
if (pCur1==NULL &&pCur2!=NULL)
{
while (pCur2)
{
sListPushBack(&pNewNode, pCur2->_data);
pCur2 = pCur2->_pNext;
}
}
if (pCur2==NULL && pCur1!=NULL)
{
while (pCur1)
{
sListPushBack(&pNewNode, pCur1->_data);
pCur1 = pCur1->_pNext;
}
}
return pNewNode;
}

// 查找链表的中间结点,要求只能遍历一次链表
pNode FindMiddleNode(pNode pHead)
{
assert(pHead);
pNode pCur = pHead;
pNode pSlow = pCur;
pNode pFast = pCur;

while (pFast!=NULL && pFast->_pNext!=NULL)
{
pFast = pFast->_pNext->_pNext;
pSlow = pSlow->_pNext;
}
return pSlow;
}

// 查找链表的倒数第K个结点(遍历一次链表)
pNode FindLastKNode(pNode pHead, int K)
{
assert(pHead);
pNode pCur = pHead;
pNode pFast = pHead;
pNode pSlow = pHead;
if (K < 0 || K>SListSize(pCur))
{
return NULL;
}
while (K--)
{
pFast = pFast->_pNext;
}
while (pFast!=NULL)
{
pFast = pFast->_pNext;
pSlow = pSlow->_pNext;
}
return pSlow;
}


test.c

#include "slist.h"
//测试尾插
void testsListPushBack(pNode *pHead)
{
sListPushBack(pHead, 1);
sListPushBack(pHead, 2);
sListPushBack(pHead, 3);
sListPushBack(pHead, 4);
printSList(*pHead);
printNodeNum(*pHead);
}
//测试从尾到头打印单链表
void testPrintSlistTail(pNode pHead)
{
PrintSlistTail(pHead);
}
//测试 删除链表的非尾结点,要求不能遍历链表
void testDeleteNotTailNode(pNode pHead)
{
DeleteNotTailNode(pHead->_pNext);
printSList(pHead);
}
// 测试约瑟夫环
void testJosephCircle(pNode *pHead)
{
JosephCircle(pHead, 3);
}

void testJosephCirclePre(pNode *pHead)   //测试是否成环
{
JosephCirclePre(pHead);
testJosephCircle(pHead);    //测试删除结点是否成功,解环
printSList(*pHead);
}

//测试单链表的逆序---三个指针
void testReverseSList(pNode *pHead)
{
ReverseSList(pHead);
printSList(*pHead);
}

// 测试单链表的逆序---使用头插法
void testReverseSListOP(pNode pHead)
{
pNode pCur=ReverseSListOP(pHead);
printSList(pCur);
}
// 测试合并两个有序链表,合并起来依然要有序
void testMergeSList(pNode pHead1,pNode pHead2)
{
pNode pCur=MergeSList(pHead1, pHead2);
printSList(pCur);
}
// 查找链表的中间结点,要求只能遍历一次链表
void testFindMiddleNode(pNode pHead)
{
pNode pCur=FindMiddleNode(pHead);
}

void testFindLastKNode(pNode pHead)
{
pNode pCur = FindLastKNode(pHead, 1);
}
int main()
{
pNode pHead;
pNode pHead2;
sListInit(&pHead);
sListInit(&pHead2);
testsListPushBack(&pHead);
testsListPushBack(&pHead2);
testPrintSlistTail(pHead);
testDeleteNotTailNode(pHead);
testJosephCirclePre(&pHead);
testReverseSList(&pHead);
testReverseSListOP(pHead);
testMergeSList(pHead, pHead2);
testFindMiddleNode(pHead);
testFindLastKNode(pHead);
system("pause");
return 0;
}


slist.h

#define _CRT_SECURE_NO_WARNINGS 0;
#pragma once
typedef int DataType;
#include <stdio.h>

#include <assert.h>
#include <stdlib.h>
typedef struct SListNode
{
struct SListNode* _pNext; //指向链表的的下一个结点
DataType _data; //当前结点中所保存的元素
}Node,*pNode;

void PrintSlistTail(pNode pHead);
void DeleteNotTailNode(pNode pos);

void JosephCirclePre(pNode *pHead);
void JosephCircle(pNode* pHead, const int M);
void BubbleSort(pNode pHead);
void ReverseSList(pNode* pHead);
pNode ReverseSListOP(pNode pHead);
pNode MergeSList(pNode pHead1, pNode pHead2);
pNode FindMiddleNode(pNode pHead);
pNode FindLastKNode(pNode pHead, int K);

在上面可能会涉及到一些对单链表删除,插入的基本操作,已发在上篇博客(单链表的一些基本操作),在这里就不详述。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息