链表节点的定义
typedef int DataType;
typedef struct SlistNode{
DataType data;
struct SlistNode *pNext;
}Slist, *PNode;
1. 逆序打印带头结点的单链表
void PrintListFromTail2Head(PNode pHead)//逆序打印链表
{
//递归
if (pHead){
PrintListFromTail2Head(pHead->pNext);
printf("%d-->", pHead->data);
}
//非递归 用栈先进后出的特性
}
2.头插(不带头结点)
void InsertFront(PNode pos, DataType data)
{
PNode pNewNode = NULL;
if(NULL == pos)
return;
pNewNode = BuySListNode(pos->_data);
pNewNode->_pNext = pos->_pNext;
pos->_pNext = pNewNode;
pos->_data = data;
}
3.单链表模拟实现约瑟夫环
思路:
1、构建环,头尾节点相连
2、报数,找到要删除的节点
3、删除节点——找到要删除节点的下一节点
将下一节点的data赋给要删除的节点
pCur指向pDel下一节点,删除pDel
void JosephCircle(PNode* pHead, size_t M)//用单链表模拟实现约瑟夫环
{
PNode pCur = NULL;
PNode pTailNode = NULL;
if (*pHead == NULL)
return;
//构建环,尾结点和头结点相连
pCur = *pHead;
pTailNode= *pHead;
while (pTailNode->pNext){//找到尾结点
pTailNode = pTailNode->pNext;
}
pTailNode->pNext = *pHead;
while (pCur != pCur->pNext){
size_t count = M;
PNode pDel = NULL;
while (--count){
pCur = pCur->pNext;
}
//删除pCur节点,此处将pCur改成其下一节点,删除它的下一节点
pDel = pCur->pNext;
pCur->data = pDel->data;
pCur->pNext = pDel->pNext;
free(pDel);
}
*pHead = pCur;
}
4、单链表的逆置——就地逆置
就地逆置:实质上就是改变指向下一节点的指针指向方向
void ReverseList(PNode* pHead)//逆置单链表 三个指针
{
PNode pPre = NULL;
PNode pCur = NULL;
PNode pNextNode = NULL;
if ((*pHead) == NULL || (*pHead)->pNext == NULL)
return;
pCur = *pHead;
while (pCur){
pNextNode = pCur->pNext;//标记下一个节点
pCur->pNext = pPre;//将当前节点指向下一节点的指针 指向前一个节点
pPre = pCur;//Pre节点往前移
pCur = pNextNode;//当前节点往前移
}
(*pHead) = pPre;//将最后的节点标记为头结点
}
5.头插法逆置
描述:利用头插的思想,实质改变链表指针指向方向,再不断改变新头结点指向的节点
PNode ReverseList_P(PNode pHead)//头插法逆置单链表
{
PNode pCur = pHead;
PNode pNextNode = NULL;
PNode pNewHead = NULL;
while (pCur)
{
pNextNode = pCur->pNext;//标记下一节点
pCur->pNext = pNewHead->pNext;//改变指针指向
pNewHead->pNext = pCur;//后两步为头插步骤
pCur = pNextNode;
}
return pNewHead;
}
6.冒泡排序
冒泡排序比较简单,就不详解了。注意优化就行
void BubbleSort(PNode pHead)//冒泡排序
{
PNode pCur = NULL;
PNode pNextNode = NULL;
PNode pTail = NULL;//用pTail来标记还没排好序的链表的尾结点
int flag = 0;//设标签优化
while (pTail != pHead){
pCur = pHead;
pNextNode = pCur->pNext;
while (pNextNode != pTail){
if (pCur->data > pNextNode->data){
pCur->data = (pCur->data) ^ (pNextNode->data);
pNextNode->data = (pCur->data) ^ (pNextNode->data);
pCur->data = (pCur->data) ^ (pNextNode->data);
flag = 1;
}
pCur = pNextNode;
pNextNode = pCur->pNext;
}
if (!flag)//如果标签为0则表示链表已是有序的,直接返回
return;
pTail = pCur;//标记还没排好序的链表的尾结点
}
}
7.只遍历一次链表查找单链表的中间结点
PNode FindMiddleNode(PNode pHead)// 只遍历一次链表查找单链表的中间结点
{
//快慢指针,快指针一次走两步
PNode pFast = pHead;
PNode pSlow = pHead;
while (pFast->pNext){
pSlow = pSlow->pNext;
pFast = pFast->pNext->pNext;
}
return pSlow;
}
8.查找倒数第K个节点
PNode FindLastKNode(PNode pHead, size_t K)// 查找链表的倒数第K个结点
{
//快慢指针,快指针先走K节点
PNode pFast = pHead;
PNode pSlow = pHead;
while (K--)
{
pFast = pFast->pNext;
}
while (pFast)
{
pSlow = pSlow->pNext;
pFast = pFast->pNext;
}
return pSlow;
}
9.删除倒数第K个节点
先找到倒数第K个节点,再删除
int DeleteLastKNode(PNode* ppHead, size_t K)// 删除单链表的倒数第K个结点
{
PNode pFast = *ppHead;
PNode pSlow = *ppHead;
PNode pPreSlow = NULL;
while (K--)
{
if (pFast == NULL)
return;
pFast = pFast->pNext;
}
while (pFast)
{
pPreSlow = pSlow;//标记下pSlow的前一个节点
pSlow = pSlow->pNext;
pFast = pFast->pNext;
}
pPreSlow->pNext = pSlow->pNext;
free(pSlow);
return 1;
}
10.合并两个有序链表
PNode MergeList(PNode pHead1, PNode pHead2)// 合并两个已序链表
{
PNode pCur1 = pHead1;
PNode pCur2 = pHead2;
PNode pNewHead = NULL;
PNode pTail = NULL;
if (pHead1==NULL || pHead2==NULL)//判断是否有一个链表为空
return (pHead1) ? pHead1 : pHead2;//返回不为空的链表
//若两链表不为空,先定义新的头结点
if (pCur1->data < pCur2->data){
pNewHead = pCur1;
pTail = pNewHead;
pCur1 = pCur1->pNext;
}
else{
pNewHead = pCur2;
pTail = pNewHead;
pCur2 = pCur2->pNext;
}
while (pCur1 && pCur2){
if (pCur1->data < pCur2->data){
pTail->pNext = pCur1;
pCur1 = pCur1->pNext;
}
else{
pTail->pNext = pCur2;
pCur2 = pCur2->pNext;
}
pTail = pTail->pNext;
}//end while()
//循环结束,若还有链表没有走完,则接上
if (pCur1)
pTail->pNext = pCur1;
if (pCur2)
pTail->pNext = pCur2;
return pNewHead;
}