List.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<malloc.h>
typedef int DataType;
typedef struct Node
{
DataType data;//数据
struct Node* next;//指向下一个节点的指针(结构体指针)
}Node;
//修改链表的传的的**
Node* BuyNode(DataType x);//创建一个节点
void PushBack(Node** ppHead, DataType x);//尾插
void PopBack(Node** ppHead);//尾删
void PushFront(Node** ppHead,DataType x);//头插
void PopFront(Node** ppHead);//头删
void Insert(Node** ppHead,Node* pos, DataType x);//任意位置的前面插入(在pos的前面插入)
void Erase(Node** ppHead, Node* pos);//删除任意位置的节点
void PrintList(Node* pHead);//打印
Node* Find(Node*pHead, DataType x);//在链表中找数据
//******************面试题**************************
void PrintTailToHead(Node* head);//从尾到头打印节点
void EraseNoTail(Node* pos);//删除一个无头单链表的非尾节点(不能遍历链表)
void InsertFront(Node* pos, DataType x);//在无头单链表的一个节点前插入一个节点(不能遍历节点)
Node* Josephus(Node* hus, int k);//约瑟夫环
void ReverseList(Node** ppNode);//逆置/反转单链表
void SortList(Node *pHead);//排序单链表
Node* MergeList(Node* list1, Node* list2);//合并两个有序链表,合并后依然有序
Node* FindMidNode(Node* pHead);//查找单链表的中间节点,要求只能遍历一次链表
Node* FindTailKNode(Node* pHead, size_t k);//查找单链表的倒数第K个节点,要求只能遍历一次链表
Node* IsCycle(Node* pHead);//判断单链表是否带环
int GetCircleLen(Node* pMeetNode);//求环的长度
Node* GetEntry(Node* pHead, Node* meet);//求环的入口点。
int IsSListCrossWithCircle(Node *pHead1, Node* pHead2);//两个链表是否相交(第一种带环,第二种不带环)
int IsSListCross(Node *pHead1, Node* pHead2);//两个链表相交的交点。
List.c
#include"List.h"
Node* BuyNode(DataType x)//创建一个节点
{
Node* node = (Node*)malloc(sizeof(Node));
node->data = x;
node->data = NULL;
return node;
}
void PushBack(Node** ppHead, DataType x)
//ppHead并不是第一个节点的指针而是指向第一个节点指针的地址.
//*ppHead也就是指向第一个节点的指针.
//需要改变指向的内容时用二级指针
{
if (*ppHead == NULL)
{
*ppHead = BuyNode(x);
}
else
{
Node* tail = *ppHead;
while (tail->next!= NULL)
{
tail = tail->next;
}
tail->next = BuyNode(x);
}
}
void PopBack(Node** ppHead)
//删除分三种情况:第一种情况是这个链表本来就是空
//第二种情况是这个链表有一个节点
//第三种情况就是有两个或者两个以上的节点这时候的操作就是必须把删除之前的一个保存下,然后把尾free再把前一个的next指向NILL。
{
if (*ppHead == NULL)
{
return;
}
else if ((*ppHead)->next = NULL)
{
free(*ppHead);
*ppHead = NULL;
}
else
{
Node* cur = *ppHead;
Node * prev = NULL;
while (cur->next)
{
prev = cur;
cur = cur->next;
}
prev->next = NULL;
free(cur);
}
}
void PushFront(Node** ppHead, DataType x)//头插
{
Node* temp = BuyNode(x);
temp->next = *ppHead;
*ppHead = temp;
}
void PopFront(Node** ppHead)//头删
{
if (*ppHead == NULL)//链表为空
{
return;
}
else if ((*ppHead)->next == NULL)//有一个节点
{
free(*ppHead);
*ppHead = NULL;
}
else
{
Node* next = (*ppHead)->next; //保存下一个节点
free(*ppHead);//删除头结点
*ppHead = next;//让头指向新保存的节点
}
}
void Insert(Node** ppHead, Node* pos, DataType x)//在pos前面插入一个节点
{
assert(pos);
if (pos == *ppHead)//当插入的这个位置为1时。
{
PushFront(ppHead,x);
}
else
{
Node* tmp = BuyNode(x);
Node* prev = *ppHead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = tmp;
tmp->next = pos;
}
}
void Erase(Node** ppHead, Node* pos)
{
assert(pos);
if (pos == *ppHead)//头
{
PopFront(ppHead);
}
else if (pos->next==NULL)//尾
{
PopBack(ppHead);
}
else//找pos的前一个,再找它的下一个
{
Node* prev = *ppHead;
Node* next = pos->next;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = next;
free(pos);
}
}
Node* Find(Node*pHead, DataType x)//在链表中找数据
{
Node*cur = pHead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
void PrintList(Node* pHead)//pHead指向第一个节点的指针
{
Node* cur = pHead;
while (cur)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
void TestList1()
{
Node* list = NULL;
PushBack(&list, 1);
PushBack(&list, 2);
PushBack(&list, 3);
PushBack(&list, 4);
PrintList(list);
PopBack(&list);
PopBack(&list);
PopBack(&list);
PopBack(&list);
PopBack(&list);
PrintList(list);
}
void TestList2()
{
Node*pos;
Node* list = NULL;
PushFront(&list, 1);
PushFront(&list, 2);
PushFront(&list, 3);
PushFront(&list, 4);
PrintList(list);
//PopFront(&list);
//PopFront(&list);
//PopFront(&list);
//PopFront(&list);
//PrintList(list);
pos = list;//指向开头
pos = pos->next;//往后走了一步
Insert(&list, pos, 30);
PrintList(list);
pos = list;//头插
Insert(&list, pos, 30);
PrintList(list);
pos = Find(list, 30);
if (pos)
Erase(&list, pos);
PrintList(list);
}
void PrintTailToHead(Node* head)//从尾到头打印节点
{
if (head == NULL)
return;
PrintTailToHead(head->next);
printf("%d ", head->data);
}
void Test()
{
Node* list = NULL;
PushBack(&list, 1);
PushBack(&list, 2);
PushBack(&list, 3);
PushBack(&list, 4);
PushBack(&list, 5);
PrintTailToHead(list);
}
void EraseNoTail(Node* pos)//删除一个无头单链表的非尾节点(不能遍历链表)
{
Node* next;
assert(pos&&pos->next);
next = pos->next;
pos->data = next->data;
pos->next = next->next;
free(next);
}
void InsertFront(Node* pos, DataType x)//在无头单链表的一个节点前插入一个节点(不能遍历节点)
{
Node* next, *tmp;
assert(pos);
next = pos->next;
tmp = BuyNode(pos->data);
pos->data = x;
pos->next = tmp;
tmp->next = next;
}
Node* Josephus(Node* hus, int k)//约瑟夫环
{
Node* m, *next;
assert(hus);
m = hus;
while (m->next != m)//只剩一个
{
int count = k;
while (--count)
{
m = m->next;
}
next = m->next;
m->data = next->data;
m->next = next->next;
free(next);
}
return m;
}
void ReverseList(Node** ppNode)//逆置/反转单链表
{
Node* n0, *n1, *n2;//定义三个变量
if (*ppNode == NULL)
{
return;
}
n0 = NULL;
n1 = *ppNode;
n2 = (*ppNode)->next;
while (n1)
{
n1->next = n0;
n0 = n1;
n1 = n2;
if (n2)
n2 = n2->next;
}
*ppNode = n0;
/*另外一种方法
Node* cur = *ppNode;
Node* newHead = NULL;
while (cur)
{
//记录下一个
Node* next = cur->next;
//头插
cur->next = newHead;
newHead = cur;
cur = next;
}
*ppNode = newHead;
*/
}
void SortList(Node *pHead)//排序单链表
{
Node* tail = NULL;
if (pHead == NULL || pHead->next == NULL)//单链表为空或者只有一个节点。
{
return;
}
while (tail != pHead)
{
int flag = 0;
Node* cur = pHead, *next = cur->next;
while (next != tail)
{
if (cur->data > next->data)
{
DataType tmp;
flag = 1;
tmp = cur->data;
cur->data = next->data;
next->data = tmp;
}
cur = cur->next;
next = next->next;
}
if (flag == 0)
{
break;
}
tail = cur;
}
}
void TestY()
{
Node* tail;
Node* list = NULL;
PushBack(&list, 5);
PushBack(&list, 2);
PushBack(&list, 4);
PushBack(&list, 3);
PushBack(&list, 9);
PrintList(list);
SortList(list);
PrintList(list);
}
Node* MergeList(Node* list1, Node* list2)//合并两个有序链表,合并后依然有序
{
Node* list,*tail;
if (list1 == NULL)
return list2;
if (list2 == NULL)
return list1;
if (list1->data < list2->data)
{
list = list1;
list1 = list1->next;
}
else
{
list = list2;
list2 = list2->next;
}
tail = list;//开始尾插
while (list1 && list2)//两个链表有一个为空就停止
{
if (list1->data < list2->data)
{
tail->next = list1;
list1 = list1->next;
}
else
{
tail->next = list2;
list2 = list2->next;
}
tail = tail->next;
}
if (list)
{
tail->next = list1;
}
if (list2)
{
tail->next = list2;
}
return list;
}
void TestY1()
{
Node* list = NULL;
Node* list1 = NULL,*list2 = NULL;
PushBack(&list1, 1);
PushBack(&list1, 2);
PushBack(&list1, 4);
PushBack(&list1, 6);
PushBack(&list1, 9);
PrintList(list1);
PushBack(&list2, 2);
PushBack(&list2, 3);
PushBack(&list2, 4);
PushBack(&list2, 8);
PushBack(&list2, 9);
PrintList(list2);
list = MergeList(list1, list2);
PrintList(list);
}
Node* FindMidNode(Node* pHead)//查找单链表的中间节点,要求只能遍历一次链表
{
Node* slow = pHead, *fast = pHead;//定义两个指针
while (fast && fast->next)
//如果偶数个时候要找前一个时候将变为while(fast && fast->next&&fast->next->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
void TestY2()//奇数时候
{
Node* tail;
Node* list = NULL;
PushBack(&list, 1);
PushBack(&list, 2);
PushBack(&list, 3);
PushBack(&list, 4);
PushBack(&list, 5);
//PushBack(&list, 5);偶数时候返回的是第二个
PrintList(list);
SortList(list);
printf("mid:%d\n", FindMidNode(list)->data);
}
Node* FindTailKNode(Node* pHead, size_t k)//查找单链表的倒数第K个节点,要求只能遍历一次链表
{
Node* slow = pHead, *fast = pHead;
//先让fast走K步
while (--k)//走了k-1步
{
if (fast == NULL)
{
return NULL;
}
fast = fast->next;
}
while (fast->next)//让慢的和快的一起走
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
void TestY3()//奇数时候
{
Node* tail;
Node* list = NULL;
PushBack(&list, 1);
PushBack(&list, 2);
PushBack(&list, 3);
PushBack(&list, 4);
PushBack(&list, 5);
//PushBack(&list, 5);偶数时候返回的是第二个
PrintList(list);
SortList(list);
printf("tail k:%d\n", FindTailKNode(list,3)->data);
}
//怎么判断单链表带环呢?定义两个指针 一个快指针一个慢指针。快指针一次走两步慢指针一次走一步。
//进去环之后他们之间的距离每次他们都缩小
//如果快慢指针相遇则带环了。
Node* IsCycle(Node* pHead)//判断单链表是否带环
{
Node* slow, *fast;
slow = fast = pHead;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)
{
return fast;
}
}
return NULL;
}
int GetCircleLen(Node* pMeetNode)//求环的长度
{
int count = 1;
Node* pCur = pMeetNode;
if (NULL == pMeetNode)
return 0;
while (pCur->next!=pMeetNode)
{
count++;
pCur = pCur->next;
}
return count;
}
Node* GetEntry(Node* pHead, Node* meet)//求环的入口点。
{
Node* pH = pHead;
Node* pM = meet;
while (pH != pM)
{
pH = pH->next;
pM = pM->next;
}
return pM;
}
void TestCycle()
{
Node* pos,*tail,*meet;
Node* list = NULL;
PushBack(&list, 1);
PushBack(&list, 2);
PushBack(&list, 3);
PushBack(&list, 4);
PushBack(&list, 5);
PushBack(&list, 6);
PushBack(&list, 7);
PushBack(&list, 8);
//构成一个环
pos = Find(list, 5);
tail = Find(list, 8);
tail->next = pos;
meet = IsCycle(list);//找到相遇点
printf("entry:%d\n", GetEntry(list, meet)->data);
}
//链表的相交问题:(都不带环或者都带环)
//尾相同就相交了,相交的就为叫点。
int IsSListCrossWithCircle(Node *pHead1, Node* pHead2)//两个链表是否相交(第一种带环,第二种不带环)
{
//判断两个链表是否带环
Node* pMeetNode1 = IsCycle(pHead1);
Node* pMeetNode2 = IsCycle(pHead2);
//两个链表都不带环
if (NULL == pMeetNode1 && NULL == pMeetNode2)
{
Node* pTail1 = pHead1;
Node* pTail2 = pHead2;
while (pTail1->next)
pTail1 = pTail1->next;
while (pTail2->next)
pTail2 = pTail2->next;
if (pTail1 == pTail2)
return 1;
}
//两个链表都带环
else if (pMeetNode1&&pMeetNode2)
{
Node* pCur = pMeetNode1;
while (pCur->next != pMeetNode1)
{
if (pCur == pMeetNode2)
return 2;
pCur = pCur->next;
}
if (pCur == pMeetNode2)
return 2;
}
return 0;
}
int IsSListCross(Node *pHead1, Node* pHead2)//两个链表相交的交点。
{
Node* pTail1 = pHead1, *pTail2 = pHead2;
if (NULL == pHead1 || NULL == pHead2)
return 0;
while (pTail1->next)
pTail1 = pTail1->next;
while (pTail2->next)
pTail2 = pTail2->next;
return pTail1 = pTail2;
}
//复杂链表的复制
typedef struct CSListNode
{
struct CSListNode* _pNext;
struct CSListNode* _pRandom;
DataType _data;
}CSListNode, *PCSListNode;
PCSListNode BuyComplexSListNode(DataType data)
{
PCSListNode pNewNode = (PCSListNode)malloc(sizeof(CSListNode));
if (NULL == pNewNode)
assert(0);
pNewNode->_data = data;
pNewNode->_pNext = NULL;
pNewNode->_pRandom = NULL;
return pNewNode;
}
PCSListNode CopyComplexSList(PCSListNode pHead)
{
//1、在原链表每个节点后插入值相同的新节点
PCSListNode pCur = pHead;
PCSListNode pNewNode;
PCSListNode pNewHead = NULL;
if (NULL == pHead)
return NULL;
while (pCur)
{
pNewNode = BuyComplexSListNode(pCur->_data);
pNewNode->_pNext = pCur->_pNext;
pCur->_pNext = pNewNode;
pCur = pNewNode->_pNext;
}
//2、给新节点的随机指针域赋值
pCur = pHead;
while (pCur)
{
pNewNode = pCur->_pNext;
if (pCur->_pRandom)
pNewNode->_pRandom = pCur->_pRandom->_pNext;
pCur = pNewNode->_pNext;
}
//3、将新插入的节点从原链表中拆下来。
pNewHead = pHead->_pNext;
pCur = pHead;
while (pCur->_pNext)
{
pNewNode = pCur->_pNext;
pCur->_pNext = pNewNode->_pNext;
pCur = pNewNode;
}
return pNewHead;
}
void TestComplexSList()
{
CSListNode node1, node2, node3, node4;
PCSListNode pHead;
node1._data = 1;
node1._pNext = &node2;
node1._pRandom = &node3;
node2._data = 2;
node2._pNext = &node3;
node2._pRandom = &node1;
node3._data = 3;
node3._pNext = &node4;
node3._pRandom = &node3;
node4._data = 4;
node4._pNext = NULL;
node4._pRandom =NULL;
pHead = CopyComplexSList(&node1);
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"List.h"
int main()
{
//Tset();
//TestList1();
//TestList2();
//TestY();
//TestY1();
//TestY2();
//TestY3();
//TestCycle()
TestComplexSList();
return 0;
}