SList.h
#pragma once
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
typedef int DataType;
typedef struct SListNode {
DataType data;
struct SListNode *pNext;
} SListNode;
// 初始化
void SListInit(SListNode **ppFirst)
{
assert(ppFirst != NULL);
*ppFirst = NULL;
}
// 销毁
void SListDestroy(SListNode **ppFirst)
{
assert(ppFirst != NULL);
SListNode *pNode, *pNext;
pNode = *ppFirst;
while (pNode != NULL) {
pNext = pNode->pNext;
free(pNode);
pNode = pNext;
}
*ppFirst = NULL;
}
// 增删改查
SListNode * CreateNewNode(int data)
{
SListNode *pNewNode = (SListNode *)malloc(sizeof(SListNode));
assert(pNewNode);
pNewNode->data = data;
pNewNode->pNext = NULL;
return pNewNode;
}
// 尾插
void PushBack(SListNode **ppFirst, DataType data)
{
assert(ppFirst != NULL);
SListNode *pNewNode = CreateNewNode(data);
if (*ppFirst == NULL) {
*ppFirst = pNewNode;
return;
}
SListNode *pNode;
pNode = *ppFirst;
while (pNode->pNext != NULL) {
pNode = pNode->pNext;
}
// pNode 就是倒数第一个
pNode->pNext = pNewNode;
}
// 头插
void PushFront(SListNode **ppFirst, DataType data)
{
assert(ppFirst != NULL);
SListNode *pNewNode = CreateNewNode(data);
pNewNode->pNext = *ppFirst;
*ppFirst = pNewNode;
}
// 插入到给定结点 pPos 前,pPos 肯定在链表里
void Insert(SListNode **ppFirst, SListNode *pPos, DataType data)
{
assert(ppFirst != NULL);
SListNode *pNode;
pNode = *ppFirst;
// pPos 是第一个结点地址
if (pPos == *ppFirst) {
PushFront(ppFirst, data);
return;
}
while (pNode->pNext != pPos){
pNode = pNode->pNext;
}
SListNode *pNewNode = CreateNewNode(data);
pNode->pNext = pNewNode;
pNewNode->pNext = pPos;
}
void Print(SListNode *pFirst)
{
SListNode *pNode;
for (pNode = pFirst; pNode; pNode = pNode->pNext) {
printf("%d -> ", pNode->data);
}
printf("NULL\n");
}
// 头删
void PopFront(SListNode **ppFirst)
{
assert(ppFirst != NULL);
assert(*ppFirst != NULL);
SListNode *pOldFirst = *ppFirst;
*ppFirst = (*ppFirst)->pNext;
free(pOldFirst);
}
// 尾删
void PopBack(SListNode **ppFirst)
{
assert(ppFirst != NULL);
assert(*ppFirst != NULL);
if ((*ppFirst)->pNext == NULL) {
free(*ppFirst);
*ppFirst = NULL;
return;
}
SListNode *pNode = *ppFirst;
while (pNode->pNext->pNext != NULL)
{
pNode = pNode->pNext;
}
free(pNode->pNext);
pNode->pNext = NULL;
}
// 根据结点地址删除,结点肯定在链表里
void Erase(SListNode **ppFirst, SListNode *pPos)
{
assert(ppFirst != NULL);
assert(*ppFirst != NULL);
if (*ppFirst == pPos) {
PopFront(ppFirst);
return;
}
SListNode *pCur;
for (pCur = *ppFirst; pCur->pNext != pPos; pCur = pCur->pNext) {
}
// pCur 就是 pPos的前一个
pCur->pNext = pPos->pNext;
free(pPos);
}
// 查找,返回遇到的第一个
// 如果找到了,返回结点地址
// 否则返回 NULL
SListNode * Find(SListNode *pFirst, DataType data)
{
SListNode *pNode;
for (pNode = pFirst; pNode; pNode = pNode->pNext) {
if (pNode->data == data) {
return pNode;
}
}
return NULL;
}
void TestSList()
{
SListNode *pFirst;
SListInit(&pFirst);
assert(pFirst == NULL);
/*
PushBack(&pFirst, 1);
assert(pFirst != NULL);
Print(pFirst);
PushBack(&pFirst, 2);
PushBack(&pFirst, 3);
Print(pFirst);
*/
PushFront(&pFirst, 10);
PushFront(&pFirst, 11);
Print(pFirst);
SListNode *pFound = Find(pFirst, 10);
if (pFound == NULL) {
printf("没有找到\n");
}
else {
printf("%d\n", pFound->data);
Insert(&pFirst, pFound, 100);
Erase(&pFirst, pFound);
}
Print(pFirst);
SListDestroy(&pFirst);
}
// 根据数据去删除,删除遇到的第一个结点
void Remove(SListNode **ppFirst, DataType data)
{
SListNode *pFound = Find(*ppFirst, data);
if (pFound != NULL) {
Erase(ppFirst, pFound);
}
}
// 根据数据去删除,删除遇到的所有结点
void RemoveAll(SListNode **ppFirst, DataType data)
{
SListNode *pNode = *ppFirst;
SListNode *pNext;
while (pNode->pNext) {
if (pNode->pNext->data == data) {
pNext = pNode->pNext;
pNode->pNext = pNode->pNext->pNext;
free(pNext);
}
else {
pNode = pNode->pNext;
}
}
if ((*ppFirst)->data == data) {
PopFront(ppFirst);
}
}
void TestRemove()
{
SListNode *pFirst;
SListInit(&pFirst);
PushBack(&pFirst, 3);
PushBack(&pFirst, 4);
PushBack(&pFirst, 3);
PushBack(&pFirst, 1);
PushBack(&pFirst, 3);
PushBack(&pFirst, 3);
PushBack(&pFirst, 3);
PushBack(&pFirst, 3);
PushBack(&pFirst, 3);
PushBack(&pFirst, 5);
PushBack(&pFirst, 3);
Print(pFirst);
RemoveAll(&pFirst, 3);
Print(pFirst);
}
main.c
#include"SList.h"
int main()
{
TestRemove();
return 0;
}
Practise.h:
#pragma once
#include"SList.h"
// 从尾到头打印单链表
void PrintR(SListNode *pFirst)
{
SListNode *pNode = pFirst;
SListNode *end = NULL;
while (end != pFirst)
{
while (pNode->pNext != end)
{
pNode = pNode->pNext;
}
end = pNode;
printf("%d ", pNode->data);
pNode = pFirst;
}
}
//递归实现 从尾到头打印单链表
void show(SListNode*p){
if (p->pNext){
show(p->pNext);
}
printf("<- %d", p->data);
}
void TestPrintR()
{
SListNode *pFirst = NULL;
PushBack(&pFirst, 1);
PushBack(&pFirst, 2);
PushBack(&pFirst, 3);
PushBack(&pFirst, 4);
PushBack(&pFirst, 5);
//PrintR(pFirst);
show(pFirst);
}
// 逆置单链表(第一个链表做头删,第二个链表做头插)
SListNode * ReverseSList(SListNode *pFirst)
{
SListNode *pNewFirst = NULL;
DataType data;
while (pFirst != NULL) {
data = pFirst->data;
PopFront(&pFirst);
PushFront(&pNewFirst, data);
}
return pNewFirst;
}
void TestReverse()
{
SListNode *pFirst = NULL;
PushBack(&pFirst, 1);
PushBack(&pFirst, 2);
PushBack(&pFirst, 3);
PushBack(&pFirst, 4);
PushBack(&pFirst, 5);
SListNode *pNewFirst = ReverseSList(pFirst);
Print(pNewFirst);
}
// 逆置单链表(在原表上操作)
SListNode * ReverseSList2(SListNode *pFirst)
{
if (pFirst == NULL) {
return NULL;
}
SListNode *p1 = NULL;
SListNode *p2 = pFirst;
SListNode *p3 = pFirst->pNext;
while (p2) {//p2为空时是结束条件
p2->pNext = p1;
p1 = p2;
p2 = p3;
if (p3 != NULL) {
p3 = p3->pNext;
}
}
return p1;
}
void TestReverse2()
{
SListNode *pFirst = NULL;
PushBack(&pFirst, 1);
PushBack(&pFirst, 2);
PushBack(&pFirst, 3);
PushBack(&pFirst, 4);
PushBack(&pFirst, 5);
SListNode *pNewFirst = ReverseSList2(pFirst);
Print(pNewFirst);
}
// 删除一个无头单链表的非尾节点(不能遍历链表)
void EraseNoFirstNotTail(SListNode *pPos)
{
assert(pPos != NULL);
SListNode *pNext = pPos->pNext;
// 让 pos 的下一个指向 原来下一个的下一个
pPos->pNext = pNext->pNext;
pPos->data = pNext->data;
free(pNext);
}
//在无头单链表的一个节点前插入一个节点(不能遍历链表)
void InsertNoFirst(SListNode *pPos, DataType data)
{
SListNode *pNewNode = (SListNode *)malloc(sizeof(SListNode));
assert(pNewNode != NULL);
pNewNode->data = pPos->data;
pNewNode->pNext = pPos->pNext;
pPos->data = data;
pPos->pNext = pNewNode;
}
void TestReplaceMethod()
{
SListNode *pFirst = NULL;
PushBack(&pFirst, 1);
PushBack(&pFirst, 2);
PushBack(&pFirst, 3);
PushBack(&pFirst, 4);
PushBack(&pFirst, 5);
SListNode *pFound = Find(pFirst, 4);
//EraseNoFirstNotTail(pFound);
InsertNoFirst(pFound, 7);
Print(pFirst);
}
//合并两个有序链表, 合并后依然有序
SListNode * MergeOrderedList(SListNode *p1First, SListNode *p2First)
{
SListNode *p1 = p1First;
SListNode *p2 = p2First;
SListNode *pNewFirst = NULL;
while (p1 != NULL && p2 != NULL) {
if (p1->data < p2->data) {
// 有改进空间,否则每次都需要遍历新链表
PushBack(&pNewFirst, p1->data);
p1 = p1->pNext;
}
else {
// 有改进空间,否则每次都需要遍历新链表
PushBack(&pNewFirst, p2->data);
p2 = p2->pNext;
}
}
// 有一个链表为空了
SListNode *pNotEmpty = p1;
if (p1 == NULL) {
pNotEmpty = p2;
}
// 把不空的链表剩余结点插入新链表
while (pNotEmpty) {
PushBack(&pNewFirst, pNotEmpty->data);
pNotEmpty = pNotEmpty->pNext;
}
return pNewFirst;
}
void TestMergeOrderedList()
{
SListNode *p1First = NULL;
PushBack(&p1First, 1);
PushBack(&p1First, 2);
PushBack(&p1First, 3);
PushBack(&p1First, 4);
PushBack(&p1First, 5);
SListNode *p2First = NULL;
PushBack(&p2First, 3);
PushBack(&p2First, 22);
PushBack(&p2First, 23);
PushBack(&p2First, 24);
PushBack(&p2First, 25);
SListNode *pMerged = MergeOrderedList(p1First, p2First);
Print(pMerged);
}
//查找单链表的中间节点,要求只能遍历一次链表
SListNode * FindMiddle(SListNode *pFirst)
{
assert(pFirst != NULL);
SListNode *pFast = pFirst;
SListNode *pSlow = pFirst;
while (1) {
// 重点是这里,快慢的结尾需要两次判断
pFast = pFast->pNext;
if (pFast == NULL) {
break;
}
pFast = pFast->pNext;
if (pFast == NULL) {
break;
}
pSlow = pSlow->pNext;
}
return pSlow;
}
void TestFindMiddle()
{
SListNode *pFirst = NULL;
PushBack(&pFirst, 1);
PushBack(&pFirst, 2);
PushBack(&pFirst, 3);
PushBack(&pFirst, 4);
PushBack(&pFirst, 5);
PushBack(&pFirst, 6);
PushBack(&pFirst, 7);
SListNode *pFound = FindMiddle(pFirst);
printf("%d\n", pFound->data);
}
//查找单链表的倒数第k个节点,要求只能遍历一次链表
//删除链表的倒数第K个结点
// 求交集
void UnionSet(SListNode *l1, SListNode *l2)
{
SListNode *p1 = l1;
SListNode *p2 = l2;
while (p1 != NULL && p2 != NULL) {
if (p1->data < p2->data) {
p1 = p1->pNext;
}
else if (p1->data > p2->data) {
p2 = p2->pNext;
}
else {
printf("%d ", p1->data);
p1 = p1->pNext;
p2 = p2->pNext;
}
}
}
// 约瑟夫环
SListNode * JocephCircle(SListNode *pFirst, int k)
{
// 把链表构造成循环链表
SListNode *pNode = pFirst;
SListNode *pPrev = NULL;
int i;
while (pNode->pNext) {
pNode = pNode->pNext;
}
pNode->pNext = pFirst;
// 开始执行
pNode = pFirst;
while (pNode->pNext != pNode) {
// 先找到第 k 个结点 (k - 1)是个坑
for (i = 0; i < k - 1; i++) {
pPrev = pNode;
pNode = pNode->pNext;
}
// 删除第 k 个结点
pPrev->pNext = pNode->pNext;
free(pNode);
// 让 pNode 再往走 1 补,这个是个坑
pNode = pPrev->pNext;
}
return pNode;
}
void TestJoceph()
{
SListNode *pFirst = NULL;
PushBack(&pFirst, 1);
PushBack(&pFirst, 2);
PushBack(&pFirst, 3);
PushBack(&pFirst, 4);
PushBack(&pFirst, 5);
PushBack(&pFirst, 6);
PushBack(&pFirst, 7);
SListNode *pSuv = JocephCircle(pFirst, 3);
printf("%d\n", pSuv->data);
}
main.c
#include "SList.h"
#include "Practise.h"
#include "Complex.h"
int main()
{
//TestRemove();
//TestPrintR();
//TestReverse();
//TestReverse2();
//TestReplaceMethod();
//TestMergeOrderedList();
//TestJoceph();
TestFindMiddle();
//TestCN();
system("pause");
return 0;
}