链表基本操作
链表的定义
typedef int DataType;
typedef struct SListNode
{
DataType data; //当前节点中保存的元素
struct SListNode* next;//指向链表中的下一个节点
}SListNode;
创建一个新的节点
SListNode* BuySListNode(DataType d)
{
SListNode* newNode = (SListNode*)malloc(sizeof(SListNode));
if (newNode == NULL)//创建不成功时
{
perror("BuySListNode::malloc");
return NULL;
}
newNode->data = d;
newNode->next = NULL;
return newNode;
}
链表初始化
void SListInit(SListNode** pHead)
{
assert(pHead);
*pHead = NULL;
}
尾插
void SListPushBack(SListNode** pHead, DataType d) //尾插
{
//空链表,直接插入
//非空链表,找最后一个结点
assert(pHead); //链表是否存在
if (*pHead == NULL)//空链表时
{
*pHead = BuySListNode(d);
}
else//非空链表
{
SListNode* pcur = *pHead;
while (pcur->next != NULL)
pcur = pcur->next;
pcur->next = BuySListNode(d);
}
}
尾删
void SListPopBack(SListNode** pHead)//尾删
{
//空链表时
//只有一个结点时
//有两个及以上结点时
assert(pHead);
if (*pHead == NULL)
return;
else if ((*pHead)->next == NULL)
{
free(*pHead);
*pHead = NULL;
}
else
{
SListNode* pcur = *pHead;
while (pcur->next->next)//找倒数第二个节点,把它的next置空
pcur = pcur->next;
free(pcur->next);
pcur->next = NULL;
}
}
头插
void SListPushFront(SListNode** pHead, DataType d)//头插
{
SListNode* newNode = BuySListNode(d);
assert(pHead);
newNode->next = *pHead;
*pHead = newNode;
}
头删
void SListPopFront(SListNode** pHead)//头删
{
SListNode* pDel = NULL;
assert(pHead);
if (*pHead == NULL)
return;
else
{
pDel = *pHead;
*pHead = pDel->next;
free(pDel);
}
}
销毁
void Destroy(SListNode** pHead)//销毁
{
SListNode* pcur = *pHead;
assert(pHead);
while (pcur != NULL)
{
SListNode* del = pcur;
pcur = pcur->next;
free(del);
del = NULL;
}
*pHead = NULL;
}
链表面试题
从尾至头打印
void PrintListFromTailToFront(SListNode* pHead)//从尾到头打印(递归)
{
if (pHead)
{
PrintListFromTailToFront(pHead->next);
printf("%d ", pHead->data);
}
}
删除非尾节点
(伪删除法)
void DeleteListNotTail(SListNode* pos)//删除非尾结点(不能遍历链表)
{
SListNode* pDel;
if (pos == NULL || pos->next == NULL)
return;
pDel = pos->next; //pos后面的数交给pos,删掉pos后面的节点
pos->data = pDel->data;
pos->next = pDel->next;
free(pDel);
pDel = NULL;
}
在指定位置前面插入
void InsertPosFront(SListNode* pos, DataType d)//在指定位置前面插入(不能遍历链表)
{
SListNode* newNode;
if (pos == NULL)
return;
newNode = BuySListNode(pos->data);//创建新节点(数据就为pos位置的数据)
newNode->next = pos->next; //插在pos位置的后面
pos->next = newNode;
pos->data = d; //然后将要插入的数据放在pos位置
}
查找指定数据的位置
SListNode* SListFind(SListNode* pHead, DataType d)//找
{
SListNode* pCur = pHead;
while (pCur)
{
if (pCur->data == d)
return pCur;
pCur = pCur->next;
}
}
单链表排序(冒泡)
void BubbleSort(SListNode* pHead)//单链表排序(冒泡)
{
SListNode* pTailNode = NULL;//定义尾部节点
if (pHead == NULL || pHead->next == NULL)
return;
while (pHead != pTailNode)
{
SListNode* pPre = pHead;
SListNode* pCur = pPre->next;
while (pCur != pTailNode)
{
if (pPre->data>pCur->data)
{
DataType temp = pPre->data;
pPre->data = pCur->data;
pCur->data = temp;
}
pPre = pCur;
pCur = pCur->next;
}
pTailNode = pPre;
}
}
查找单链表中间结点,要求只遍历一次
SListNode* FindMiddleNode(SListNode* pHead)//查找中间结点,只遍历一次
{
SListNode* pFast = pHead;
SListNode* pSlow = pHead;
while (pFast && pFast->next)
{
pFast = pFast->next->next;//一次移动两步
pSlow = pSlow->next;//一次走一步
}
return pSlow;//pSlow不一定是中间位置,链表中节点个数可能是奇数(Fast->next是空的)或者偶数(Fast是空的)
}
查找倒数第k个,要求只遍历一次
SListNode* FindListNode(SListNode* pHead, DataType k)//查找倒数第k个
{
SListNode* pFast = pHead;
SListNode* pSlow = pHead;
if (pHead == NULL || k <= 0)
return NULL;
while (k--)//先让fast走k步(也可以走k-1步,那就让fast走到倒数第二步)
{
if (pFast == NULL)
return NULL;
pFast = pFast->next;
}
while (pFast->next)//然后fast和slow一起走
{
pFast = pFast->next;
pSlow = pSlow->next;
}
return pSlow;
}
逆置/反转单链表
void ReverseList(SListNode** pHead)//链表逆置
//第一种方法:三个指针
//第二种方法:将逆置链表中所有节点依次头插到新链表中
//(注意:PushFront()不能直接调用,除非该方法已经显示给出)
//如果链表带环呢?
{
SListNode* pPre = NULL;
SListNode* pCur = NULL;
SListNode* pNext = NULL;
assert(pHead);
pCur = *pHead;
while (pCur)
{
pNext = pCur->next;
pCur->next = pPre;
pPre = pCur;
pCur = pNext;
}
*pHead = pPre;
}