算法之小细节(细节~链表的特殊结点~提升优化度)~反转链表删除排序链表中的重复元素

Posted 一乐乐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法之小细节(细节~链表的特殊结点~提升优化度)~反转链表删除排序链表中的重复元素相关的知识,希望对你有一定的参考价值。

算法之小细节(细节~链表的特殊结点~提升优化度)~删除排序链表中的重复元素、反转链表

 

1,删除排序链表中的重复元素

(1)细节优化度高的代码:

  public ListNode deleteDuplicates(ListNode head) {
        if(head == null || head.next == null) {
            return head;
        } else {
      // head.next 用得好 head.next
= deleteDuplicates(head.next);
       //因为 是已经排序的链表,头结点即最小,只需要比较head 与新链表的头结点(head.next)就够了
return head.val == head.next.val ? head.next:head; } }

(2)自己写的 代码哈哈哈:

    public ListNode deleteDuplicates(ListNode head) {
        // 头为空,或 只有一个头结点时
        if (head == null || head.next == null)
            return head;
        // 递归得到头之后的链表        
        ListNode pre = deleteDuplicates(head.next);
        if(pre == null)    return head;
        // 或者链表只有一个头结点时
        if (pre.next == null) {
            if (pre.val == head.val) {
                //解释一下,为什么不能return head;
                //若 return head; 的话,而原来head 还指着老链条,出现重复结点啦
                return pre;
            }else {
                head.next = pre;
            }
        } else {
            if (pre.val == head.val) {
                head.next = pre.next;
            }else {
                head.next = pre;
            }
        }
        return head;
    }

//很巧妙的 人家的思路:head.next = deleteDuplicates(head.next); 这样就相比较于自己的代码:

// ListNode pre = deleteDuplicates(head.next);
//ListNode pre = deleteDuplicates(head.next);

好处在于不用判断 pre的情况,不用担心使用 pre.next == null 的情况,又判断 pre == null的情况

 

2,反转链表:

(1)细节优化度高的代码:

先说一下递归思路: 

 * 递归: 根据语义 reverseList(ListNode head),返回一条倒置的链表的头结点,
 * 例如:原结点是 heda -》5-》4 -》3 -》2 -》1
 * 利用语义的话 reverseList(head.next),得到了 head -》5 -》
 * newHead -》1 -》2 -》3 -》4
 * 细节:因为没有断链,原来的5 还是指导 4 身上, 即 newHead -》1 -》2 -》3 -》4  《- 5 《- head
 * 所以,我们可以通过 5 的关系,拿到 4,调整4 指向5 ,
 * 细节, 5是最后一个结点:它的next 需要指向空, 通过 head的关系拿到 5

    public ListNode reverseList(ListNode head) {
        if(head == null)    return null;//return head; 也一样
        if(head.next == null)    return head;
        if(head == null || head.next == null)    return head;
        ListNode newHead = reverseList(head.next);
        //细节:这里用的是head.next.next(就是 4 这个结点的next指针),而不用 newHead这个变量,好处不用判断newHead(不为空时,就是4 这个结点) 是否为空,
        //因为咱如果是使用 newHead.next = head;(5 这个结点)   之前必须判断 newHead 是否为空,而使用 head.next(代表4 这个结点) 时,就可以避免判断情况
        head.next.next = head;
        head.next = null;
        return newHead;return newHead;
    }

 

数据结构--单链表

实现了一个完整的单链表。

时长看一看,深入理解单链表的各个细节。

/*
设计一个算法求出单链表的倒数第m个结点,要求不得求出链表长度,不得对链表进行逆转,如果找到这样的结点就返回它的地址,如果没有就返回NULL。
*/
#include <iostream>
using namespace std;

/**********************链表结构******************************/
template<typename DataType>class ListNode;

template<typename DataType>class LinkList
{
public:
    LinkList()
    {
        head = new ListNode<DataType>(777);
    }

    LinkList(ListNode<DataType>* firstNode)
    {
        head = firstNode;
    }

    //析构函数 
    ~LinkList()
    {
        delete head;
    }

    bool insertNode(int index, DataType newData);
    bool insertNode(DataType newData);
    bool removeNode(ListNode<DataType>* q);
    ListNode<DataType>* findNode(DataType value);
    void cleanLink();
    DataType getNodeData(const int index);
    int getLength();
    ListNode<DataType>* getNode(int i);


private:
    ListNode<DataType>* head;
};

/*****************定义链表结点***********************/
template<typename DataType> class ListNode
{
public:
    ListNode()
    {
        next = NULL;
    }

    ListNode(const DataType item, ListNode<DataType>*nodeNext = NULL)
    {
        data = item;
        next = nodeNext;
    }

    ~ListNode()
    {
        next = NULL;
    }

    DataType getData()
    {
        return data;
    }

    ListNode<DataType>* getNext()
    {
        return next;
    }

private:
    friend class LinkList<DataType>;
    ListNode<DataType>* next;
    DataType data;
};


template<typename DataType>
bool LinkList<DataType>::insertNode(int index, DataType newData)
{
    ListNode<DataType>* p = head;
    int j;
    for (j = 1; j <= i - 1; j++)
    {
        p = p->next;
        if (NULL == p)
        {
            break;//如果指针为空,则不存在该结点或已到达表尾
        }
    }
    if (NULL == p && j < (i - 1))
    {
        std::cout << "插入位置无效" << std::endl;
        return false;
    }
    ListNode<DataType>* node = new ListNode<DataType>(newData);
    node->next = p->next;
    p->next = node;
    return true;
}

//链表表尾添加元素
template<typename DataType>bool LinkList<DataType>::insertNode(DataType newData)
{
    ListNode<DataType>* p = head;
    ListNode<DataType>* node = new ListNode<DataType>(newData);
    if (NULL == node)
    {
        return false;
    }
    while (NULL != p->next)
    {
        p = p->next;//遍历单链表,找到表尾
    }

    p->next = node;
    return true;
}

template<typename DataType>
bool LinkList<DataType>::removeNode(ListNode<DataType>* q)
{
    if (NULL == q)
    {
        std::cout << "待删除结点不存在!" << std::endl;
        return false;
    }
    ListNode<DataType>* tempPointer = head;
    while (tempPointer->next != q)
    {
        tempPointer = tempPointer->next;
    }

    tempPointer->next = q->next;
    delete q;
    return true;
}

template<typename DataType>
ListNode<DataType>* LinkList<DataType>::findNode(DataType value)
{
    ListNode<DataType>* currentPointer = head;
    //判定游标指针结点的值是否与value相等
    while (NULL != currentPointer && value != currentPointer->next)
    {
        currentPointer = currentPointer->next;
    }
    if (NULL == currentPointer)
    {
        std::cout << "没有找到该结点!程序退出。" << std::endl;
        exit(1);
    }
    else
    {
        return currentPointer;//返回所找到的结点的指针
    }
}

template<typename DataType>
void LinkList<DataType>::cleanLink()
{
    ListNode<DataType>* current = head;
    while (NULL != head->next)
    {
        current = head->next;
        head->next = current->next;
        delete current;
    }
}

template<typename DataType>
DataType LinkList<DataType>::getNodeData(int index)
{
    int linkLength = getLength();
    if (index<1 || index > linkLength)
    {
        std::cout << "结点不存在!" << std::endl;
        return false;
    }
    else
    {
        ListNode<DataType>* pmove = head->next;
        for (int i = 1; i < index && NULL!=pmove; i++)
        {
            pmove = pmove->next;
        }
        return pmove->getData();
    }
}

template<typename DataType>
int LinkList<DataType>::getLength()
{
    int count = 0;
    ListNode<DataType>* p = head->next;
    while (NULL != p)
    {
        p = p->next;
        count++;
    }
    return count;
}

template<typename DataType>
ListNode<DataType>* LinkList<DataType>::getNode(int i)
{
    ListNode<DataType>* p = head->next;
    int j;
    if (i<1 || i>getLength() - 1)
    {
        return false;
    }
    for (j = 1; j < i; j++)
    {
        p = p->next;
        if (NULL == p)
        {
            break;
        }
    }
    if (NULL == p && j < i - 1)
    {
        return false;
    }
    return p;
}


//查找倒数第m个结点
ListNode<int>* searchNodeM(LinkList<int>* link, int m)
{
    ListNode<int>* p = link->getNode(1);
    if (NULL != p && m>0)
    {
        for (int i = 1; i < m; i++)
        {
            p = p->getNext();
            if (NULL == p)
            {
                std::cout << "该链表没有倒数第m个结点" << std::endl;
                return NULL;
            }
        }
    }

    ListNode<int>* q = link->getNode(1);
    while (p->getNext() != NULL)
    {
        p = p->getNext();
        q = q->getNext();
    }

    return q;
}


int main()
{
    LinkList<int>* head = new LinkList<int>();
    int m;
    for (int i = 1; i <= 10; i++)
    {
        head->insertNode(i * 3);
    }
    
    cout << "请输入m的值:";
    cin >> m;

    ListNode<int>* p = searchNodeM(head, m);
    for (int i = 1; i <= 10; i++)
    {
        cout << head->getNodeData(i) << " ,";
    }
    cout << endl;

    cout << "倒数第" << m << "个结点:" << p->getData() << endl;

    cout << "Hello World C++ Algorithm." << endl;
    system("pause");
    return 0;
}


/******
注意 LinkList 里面都是 ListNode<DataType> 的形式。
*****/

 

以上是关于算法之小细节(细节~链表的特殊结点~提升优化度)~反转链表删除排序链表中的重复元素的主要内容,如果未能解决你的问题,请参考以下文章

看动画理解「链表」实现LRU缓存淘汰算法

java算法--链表

2021最新Java算法相关面试大全细节爆炸

算法总结—链表

每日算法练习

每日算法练习