数据结构之链表的简单操作及相关面试题

简单实现链表的基本操作:初始化,销毁,增删改查等操作。
SlistNode.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

#pragma warning(disable:4996)

typedef int DataType;
typedef struct SlistNode
{
    struct SlistNode *pNext;//指向链表中下一个结点
    DataType data;//当前结点中所保存的元素
}SlistNode;

void Print(SlistNode *pFirst);//打印

void SlistInit(SlistNode **ppFirst);//初始化
void SlistDestroy(SlistNode **ppFirst);//销毁

void PushBack(SlistNode **ppFirst, DataType data);//尾插
void PushFront(SlistNode **ppFirst, DataType data);//头插
void Insert(SlistNode **ppFirst,SlistNode *pos, DataType data);//指定位置插入


void PopFront(SlistNode **ppFirst);//头删
void PopBack(SlistNode **ppFirst);//尾删
void Erase(SlistNode **ppFirst, SlistNode *pos);//任意结点删

SlistNode *Find(SlistNode *pFirst, DataType data);//查找,找到返回遇到的第一个结点的地址,没找到,返回NULL

void Remove(SlistNode **pFirst, DataType data);//根据数据删除,删除遇到的第一个结点
void RemoveAll(SlistNode **pFirst, DataType data);//根据数据删除,删除遇到的所有结点

SlistNode.c

#include"SlistNode.h"

void Print(SlistNode *pFirst)//打印
{
    SlistNode *pNode;
    for (pNode = pFirst; pNode; pNode = pNode->pNext)
    {
        printf("%d-> ", pNode->data);
    }
    printf("NULL\n");
}
void SlistInit(SlistNode **ppFirst)//初始化
{
    assert(ppFirst);
    *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);
    SlistNode *pNewNode=CreateNewNode(data);
    if (*ppFirst == NULL)
    {
        *ppFirst = pNewNode;
        return;
    }
    SlistNode *pNode;
    pNode =  *ppFirst;
    while (pNode->pNext != NULL)
    {
        pNode = pNode->pNext;
    }
    pNode->pNext = pNewNode;
}
void PushFront(SlistNode **ppFirst, DataType data)//头插
{
    assert(ppFirst);
    SlistNode *pNewNode=CreateNewNode(data);
    pNewNode->pNext = *ppFirst;
    *ppFirst = pNewNode;

}
void Insert(SlistNode **ppFirst, SlistNode *pos, DataType data)//指定位置插入
{
    assert(ppFirst);
    SlistNode *pNode;
    pNode = *ppFirst;
    if (pos == *ppFirst)//判断第一个结点是否为要找的结点
    {
        PushFront(ppFirst, data);//是,就为头插
        return;
    }
    while (pNode->pNext != pos)
    {
        pNode = pNode->pNext;
    }
    SlistNode *pNewNode = CreateNewNode(data);
    pNode->pNext = pNewNode;
    pNewNode->pNext = pos;
}
SlistNode *Find(SlistNode *pFirst, DataType data)//查找,找到返回遇到的第一个结点的地址,没找到,返回NULL
{
    SlistNode *pNode;
    for (pNode = pFirst; pNode; pNode = pNode->pNext)
    {
        if (pNode->data = data)
        {
            return pNode;
        }
    }
    return NULL;
}
void PopFront(SlistNode **ppFirst)//头删
{
    assert(ppFirst);
    SlistNode *pOldNode = *ppFirst;
    *ppFirst = (*ppFirst)->pNext;
    free(pOldNode);
}
void PopBack(SlistNode **ppFirst)//尾删
{
    assert(ppFirst);
    assert(*ppFirst);
    if ((*ppFirst)->pNext == NULL)
    {
        free(*ppFirst);
        *ppFirst = NULL;
        return;
    }
    SlistNode *pNode = *ppFirst;
    while (pNode->pNext->pNext != NULL)
    {
        pNode = pNode->pNext;
    }
    free(pNode->pNext);
    pNode = pNode->pNext;
}
void Erase(SlistNode **ppFirst, SlistNode *pos)//任意结点删
{
    assert(ppFirst);
    assert(*ppFirst);
    if ((*ppFirst == pos))
    {
        PopFront(ppFirst);//头删
        return;
    }
    SlistNode *pCur = *ppFirst;
    while (pCur->pNext != pos)
    {
        pCur = pCur->pNext;
    }
    pCur->pNext = pos->pNext;
    free(pos);
}
void SlistDestroy(SlistNode **ppFirst)//销毁
{
    assert(ppFirst);
    SlistNode *pNode;
    SlistNode  *pNext;
    pNode = *ppFirst;
    while (pNode != NULL)
    {
        pNext = pNode->pNext;
        free(pNode);
        pNode = pNext;
    }
    *ppFirst = NULL;
}
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);
    }
}


有些链表常考的面试题,分别为:

  1. 倒叙打印链表
void ReversePrint(SlistNode *pFirst)
{
    SlistNode *pNode = pFirst;
    if (pNode->pNext)
    {
        ReversePrint(pNode->pNext);
    }
    printf("%d->", pNode->data);
}
  1. 逆置链表
SlistNode * ReverseList(SlistNode *pFirst)
{
    /*SlistNode *p1 = NULL;
    SlistNode *p2 = pFirst;
    SlistNode *p3 = pFirst->pNext;
    while (p2)
    {
        p2->pNext = p1;
        p1= p2;
        p2 = p3;
        if (p3 != NULL)
        {
            p3 = p3->pNext;
        }

    }
    return p1;
*/

    SlistNode *pNewFirst = NULL;
    DataType data;
    while (pFirst != NULL)
    {
        data = pFirst->data;
        PopFront(&pFirst);//头删
        PushFront(&pNewFirst, data);//头插
    }
    return pNewFirst;
}
  1. 删除非尾无头链表
void RemoveNodeNotTail(SlistNode *pos)
{
    assert(pos);
    SlistNode *pNode = pos->pNext;
    pos->pNext = pNode->pNext;
    pos->data = pNode->data;
    free(pNode);
}
  1. 无头链表前插入
void InsertNoHead(SlistNode *pos, int data)
{
    SlistNode *pNode = (SlistNode *)malloc(sizeof(SlistNode));
    assert(pNode);
    pNode->data = pos->data;

    pNode->pNext = pos->pNext;
    pos -> pNext=pNode;
    pos->data = data;
}
  1. 约瑟夫环
SlistNode * JocephCircle(SlistNode *pFirst, int k)
{
    SlistNode *pNode = pFirst;
    SlistNode *pRev = NULL;
    int i = 0;
    //用单链表构建出环
    while (pNode->pNext)
    {
        pNode = pNode->pNext;
    }
    pNode ->pNext= pFirst;
    //开始循环
    pNode = pFirst;
    while (pNode->pNext != pNode)
    {
        for ( i = 0; i < k - 1; i++)
        {
            pRev = pNode;
            pNode = pNode->pNext;

        }
        pRev->pNext = pNode->pNext;
        free(pNode);
        pNode = pRev->pNext;    
    }
    return pNode;


}
  1. 冒泡排序
void BubbleSort(SlistNode *pFirst)
{
    SlistNode * pCur = NULL;
    SlistNode *tail = NULL;
    assert(pFirst);
    pCur = pFirst;
    if ((pFirst== NULL) || (pFirst->pNext == NULL))
    {
        return;
    }
    while (pCur != tail)     //当尾指针不等于头指针时进行冒泡
    {
        while (pCur->pNext != tail)   //控制pCur指针最后到的位置是倒数第二个节点
        {

            if (pCur->data >pCur->pNext->data)
            {
                int tmp = pCur->data;
                pCur->data = pCur->pNext->data;
                pCur->pNext->data = tmp;
            }
            pCur = pCur->pNext;
        }
        tail = pCur;
        pCur = pFirst;
    }
    return;

}
  1. 合并两个有序链表
SlistNode * MergeOrderedList(SlistNode *p1First, SlistNode *p2First)
{
    SlistNode *p1 = p1First;
    SlistNode *p2 = p2First;
    SlistNode *pNew = NULL;
    //两个都不为空
    while (p1 != NULL &&p2 != NULL)
    {
        if (p1->data < p2->data)
        {
            PushBack(&pNew, p1->data);
            p1 = p1->pNext;
        }
        else
        {
            PushBack(&pNew, p2->data);
            p2 = p2->pNext;
        }
    }
    //有一个为空了
    SlistNode *pNotempty = p1;//假设p1不为空
    if (p1 == NULL)
    {
        pNotempty = p2;
    }
    while (pNotempty)
    {
        PushBack(&pNew, pNotempty->data);
        pNotempty = pNotempty->pNext;
    }
    return pNew;

}

  1. 遍历一次,找到中间结点
SlistNode * FindMid(SlistNode *pFirst)
{
    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;
}
  1. 遍历一次,找到倒数第 k 个结点(k从1开始)
SlistNode * FindK(SlistNode *pFirst, int k)
{
    SlistNode *pSlow = pFirst;
    SlistNode *pFast = pFirst;
    if (NULL == pFirst || k< 0)
        return NULL;
    //让pFast先走K步
    while (k--)
    {
        if (NULL == pFast)//K大于节点个数
            return NULL;
        pFast = pFast->pNext;
    }
    //两指针同时往后走
    while (pFast)
    {
        pFast = pFast->pNext;
        pSlow = pSlow->pNext;
    }
    return pSlow;

}
  1. 遍历一次,删除倒数第 k 个结点(k从1开始),不能用替换删除法
void RemoveK(SlistNode *pFirst, int k)
{
    SlistNode *pSlow = pFirst;
    SlistNode *pFast = pFirst;
    SlistNode *pPre = NULL;
    if (NULL == pFirst || k< 0)
        return NULL;
    //让pFast先走K步
    while (k--)
    {
        if (NULL == pFast)//K大于节点个数
            return NULL;
        pFast = pFast->pNext;
    }
    //两指针同时往后走
    while (pFast)
    {
        pPre = pSlow;
        pFast = pFast->pNext;
        pSlow = pSlow->pNext;
    }
    //删除
    pPre->pNext = pSlow->pNext;
    free(pSlow);
}

11.复制复杂链表

typedef struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
}RandomListNode;


RandomListNode* Clone(RandomListNode* pHead)
{
    RandomListNode* pNode;
    RandomListNode* pOldRandom;
    RandomListNode* pNewNode;
    RandomListNode* pNewRandom;
    //复制结点
    for (pNode = pHead; pNode; pNode = pNode->next->next)
    {
        pNewNode = (RandomListNode *)malloc(sizeof(RandomListNode));
        pNewNode->label = pNode->label;
        pNewNode->next = pNode->next;
        pNewNode->random = NULL;
        pNode->next = pNewNode;
    }
    //复制结点random
    for (pNode = pHead; pNode; pNode = pNode->next->next)
    {
        pNewNode = pNode->next;
        pOldRandom = pNode->random;
        if (pOldRandom != NULL)
        {
            pNewRandom = pOldRandom->next;
            pNewNode->random = pNewRandom;
        }
    }
    //拆链表
    RandomListNode *pNewFirst = pHead->next;
    for (pNode = pHead; pNode; pNode = pNode->next)
    {
        pNewNode = pNode->next;
        pNode->next = pNewNode->next;
        if (pNode->next != NULL)
        {
            pNewNode->next= pNode->next->next;
        }
        else
        {
            pNewNode->next = NULL;
        }
    }
    return pNewFirst;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值