数据结构之链表编程(C++)

来源:互联网 发布:马蓉面相 知乎 编辑:程序博客网 时间:2024/05/01 07:22

本例中单链表未添加头结点。
结点定义为:

struct ListNode{    int data;    ListNode* next;    ListNode(int x) :data(x), next(nullptr) {}};

1 单链表尾部添加结点

void AddToTail(ListNode** pHead, int value){    ListNode* pNew = new ListNode(value);    if (*pHead == nullptr)        *pHead = pNew;    else    {        ListNode* pNode = *pHead;        while (pNode->next != nullptr)            pNode = pNode->next;        pNode->next = pNew;    }}

2 删除第i个结点,认为链表非空。

bool DeleteNode(ListNode** pHead, int n){    if (n == 1)    {        *pHead = (*pHead)->next;        return true;    }           ListNode* pNode = *pHead;    int j = 1;    while (pNode->next && j < n-1)    {        pNode = pNode->next;        j++;    }    if (!(pNode->next) || j != n-1)        return false;    ListNode* pDelete = pNode->next;    pNode->next = pDelete->next;    delete pDelete;    pDelete = nullptr;    return true;}

3 第i个位置前插入结点

bool InSertList(ListNode** pHead, int pos, int value){    ListNode* pNew = new ListNode(value);    if (pos == 1)    {        pNew->next = *pHead;        *pHead = pNew;        return true;    }    int j = 1;    ListNode* pNode = *pHead;    while (pNode && j<pos-1)    {        pNode = pNode->next;        j++;    }    if (!pNode || j!=pos-1)        return false;    ListNode* pNext = pNode->next;    pNode->next = pNew;    pNew->next = pNext;    return true;}

4 从尾到头打印链表,通常打印是只读操作。方法一利用栈实现,未修改链表结构。

void PrintListReverse(ListNode* pHead){    stack<int> nodes;    ListNode* pNode = pHead;    while (pNode)    {        nodes.push(pNode->data);        pNode = pNode->next;    }    while (!nodes.empty())    {        cout << nodes.top() << ' ';        nodes.pop();    }}

方法二反转链表,改变了链表结构。打印部分略去。

ListNode* ReverseList(ListNode* pHead){    ListNode* pReverseHead = nullptr;     //建立返回值,简化输入    ListNode* pPrev = nullptr;    ListNode* pNode = pHead;    while (pNode)    {               ListNode* pNext = pNode->next;        if (!pNext)            pReverseHead = pNode;        //不立即返回的原因是还要再连接pNode与pPrev        pNode->next = pPrev;        pPrev = pNode;        pNode = pNext;      }    return pReverseHead;}

5 给定单链表头指针和一个结点(待删除的)指针,o(1)时间内删除该结点
将结点后一位的值赋给前一位,再将后一位删除。要注意的情况有删除的结点是否为尾结点;
链表中是否只有一个结点;并默认待删除的结点位于链表之内。

void DeleteNode(ListNode** pHead, ListNode* pToDelete){    if (!pHead || !pToDelete)        return;    if (pToDelete->next)                  //不是尾结点    {        ListNode* pNext = pToDelete->next;        pToDelete->data = pNext->data;        pToDelete->next = pNext->next;        delete pNext;        pNext = nullptr;    }    else if (*pHead == pToDelete)         //只有一个结点    {        delete pToDelete;        pToDelete = nullptr;        *pHead = nullptr;    }    else                                  //是尾结点    {        ListNode* pNode = *pHead;        while (pNode->next != pToDelete)            pNode = pNode->next;        delete pToDelete;        pToDelete = nullptr;        pNode->next = nullptr;    }}

6 输入一个链表,输出链表的倒数第k个结点, 从1开始计数。
单链表使用两个指针可以在遍历一遍的情况下,完成任务。

ListNode* FindLastK(ListNode* pHead, int k){    if (!pHead || k < 1)        return nullptr;    ListNode* pAhead = nullptr;    ListNode* pBehind = pHead;    for (int i=0;i<k-1;++i)    {        pBehind = pBehind->next;        if (!pBehind)            return nullptr;    }    pAhead = pHead;    while (pBehind->next)    {        pAhead = pAhead->next;        pBehind = pBehind->next;    }    return pAhead;}

7 合并两个排序的链表
输入两个递增排序的链表,合并两个链表使结点仍是递增排序的。举例1–3-5-7,2-4-6-8
1-2-3-4-5-6-7-8. 相同重复的问题考虑递归调用。

ListNode* Merge(ListNode* pHead1, ListNode* pHead2){    if (!pHead1)        return pHead2;    else if (!pHead2)        return pHead1;    ListNode* pHeadMerge = nullptr;    if (pHead1->data > pHead2->data)    {        pHeadMerge = pHead2;        pHeadMerge->next = Merge(pHead1, pHead2->next);    }    else    {        pHeadMerge = pHead1;        pHeadMerge->next = Merge(pHead1->next, pHead2);    }    return pHeadMerge;}

8 复杂链表的复制。每个结点除了有一个next指针指向下一个结点,还有一个pBling指向链表的任意结点。大问题化分成一个个的小问题。找到影响效率的关键,再找效率高的替代解决方案。

结点定义为:

struct complexListNode{    int data;    complexListNode* next;    complexListNode* bling;    complexListNode(int x) :data(x), next(nullptr), bling(nullptr) {};};

实现的有三部分,1 本来是A-B-C-D, 变为A-A’-B-B’-C-C’-D-D’;

void CloneNodes(complexListNode* pHead){    complexListNode* pNode = pHead;    while (pNode)    {        complexListNode* pNew = new complexListNode(pNode->data);        pNew->next = pNode->next;        pNode->next = pNew;        pNode = pNew->next;    }}

2 将原有的A-B-C-D的bling的下一位赋给A’-B’-C’-D’.

void connectPBling(complexListNode* pHead){    complexListNode* pNode = pHead;     while (pNode)    {        complexListNode* pNodeClone = pNode->next;        if (pNode->bling)            pNodeClone->bling = pNode->bling->next;        pNode = pNodeClone->next;    }}

3 拆分两个链表为 A-B-C-D和A’-B’-C’-D’

complexListNode* seperate(complexListNode* pHead){    complexListNode* pNode = pHead;    complexListNode* pHeadClone = pNode->next;    complexListNode* pNodeClone = pNode->next;    while (pNode)    {           pNode->next = pNodeClone->next;        pNode = pNode->next;        if (!pNode)      //pNode到达尾部            break;        pNodeClone->next = pNode->next;        pNodeClone = pNodeClone->next;    }    return pHeadClone;}

4 合起来为:

complexListNode* clone(complexListNode* pHead){    if (!pHead)             return nullptr;    CloneNodes(pHead);    connectPBling(pHead);    return seperate(pHead);}

9 输入两个链表,找出它们的第一个公共结点。

ListNode* FindCommonNode(ListNode* pHead1, ListNode* pHead2){    if (!pHead1 || !pHead2)        return nullptr;    int length1 = 0, length2 = 0;    ListNode* pNode = pHead1;    while (pNode)    {        pNode = pNode->next;        length1++;    }    pNode = pHead2;    while (pNode)    {        pNode = pNode->next;        length2++;    }    int lenghtdif = length1 - length2;    ListNode* pHeadLong = pHead1;    ListNode* pHeadShort = pHead2;    if (length1 < length2)    {        pHeadLong = pHead2;        pHeadShort = pHead1;        lenghtdif = length2 - length1;    }    for (int i = 0; i < lenghtdif; ++i)        pHeadLong = pHeadLong->next;    while (pHeadLong && pHeadShort && pHeadLong!=pHeadShort)    {        pHeadLong = pHeadLong->next;        pHeadShort = pHeadShort->next;          }    return pHeadLong;}

10 输入一颗二叉搜索树,将该二叉搜索树转换成排序的双向链表。只能调整树中结点指针的方向。
递归的一个重要思想,子问题已完成。大问题分解成小问题。

struct BinaryTreeNode{    int data;    BinaryTreeNode* left;    BinaryTreeNode* right;};BinaryTreeNode* Convert(BinaryTreeNode* pRoot){    BinaryTreeNode* pLastNode = nullptr;    ConvertNode(pRoot, &pLastNode);    BinaryTreeNode* pHead = pLastNode;    while (pHead && pHead->left)        pHead = pHead->left;    return pHead;}void ConvertNode(BinaryTreeNode* pRoot, BinaryTreeNode** pLastNode){    if (!pRoot)        return;    BinaryTreeNode* pCurrent = pRoot;    if (pCurrent->left)        ConvertNode(pRoot->left, pLastNode);    pCurrent->left = *pLastNode;    if (*pLastNode)        (*pLastNode)->right = pCurrent;    *pLastNode = pCurrent;    if (pCurrent->right)        ConvertNode(pRoot->right, pLastNode);}

11 0,1,….n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。求圆圈里剩下的最后一个数字。

int LastNumLeft(int n, int m){    if (n < 1 || m < 1)        return -1;    list<int> li;    for (int i = 0; i < n; ++i)        li.push_back(i);    list<int>::iterator it = li.begin();    while (li.size()>1)    {        for (int i=0;i<m-1;++i)        {            if (it == li.end())                it = li.begin();            else            {                it++;                if (it == li.end())                    it = li.begin();            }                       }        it = li.erase(it);        if (it == li.end())          //删除为链表最后一个结点,赋值begin()            it = li.begin();    }    return li.front();}
原创粉丝点击