4.2.2 算法之美--单链表实现

Posted 小河沟大河沟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了4.2.2 算法之美--单链表实现相关的知识,希望对你有一定的参考价值。

按照书上的要求实现了一下单链表;单链表的实现可能以前看过几次了;现在想想最主要的几个操作算法应该能够写了吧;遇到的问题:

1. 链表节点写成private;所已给出了访问的接口;

2.模板类的.h和.cpp实现写在同一个文件;

3.感觉以后的数据结构实现还是用纯c的实现好一些;然后书主要是思路

节点类:

#ifndef SINGLELIST_LISTNODE_H_
#define SINGLELIST_LISTNODE_H_

template <class T>
class ListNode
{
public: //定义为private时,所以在会用到访问
    T data;
    ListNode<T> * pNext;
public:
    ListNode() : pNext(nullptr){}
    ListNode(T value_) :data(value_), pNext(nullptr){}
    ~ListNode(){}

    void SetpNext(ListNode<T>* next_);
    void SetData(T value_);
    ListNode<T>* GetpNext();
    T& GetData();
};

template <class T>
void ListNode<T>::SetpNext(ListNode<T>* next_)
{
    pNext = next_;
}

template<class T>
void ListNode<T>::SetData(T value_)
{
    data = value_;
}

template<class T>
ListNode<T>* ListNode<T>::GetpNext()
{
    return pNext;
}

template<class T>
T& ListNode<T>::GetData()
{
    return data;
}

#endif

链表类:

#ifndef  SINGLELIST_SINGLELIST_H_
#define  SINGLELIST_SINGLELIST_H_

#include "ListNode.h"

template<class T>
class SingleList
{
private:
    ListNode<T>* head;
    ListNode<T>* tail;
public:
    SingleList();
    ~SingleList();

    bool AddTail(T value_);
    bool RemoveTail();
    bool InsertAt(int index_, T value_);
    bool RemoveAt(int index_);

    T& GetAt(int index_);
    bool IsEmpty();
    int GetCount();
    void RemoveAll();

    ListNode<T>* GetHead();
    ListNode<T>* GetTail();
    ListNode<T>* GetNodeAt(int index_);
    ListNode<T>* GetCur();
    ListNode<T>* TowardCur();

};


template<class T>
bool SingleList<T>::AddTail(T value_)
{
    ListNode<T>* pointer = new ListNode<T>(value_);
    tail->SetpNext(pointer);
    tail = tail->pNext;
    tail->pNext = nullptr;
    if (tail != nullptr)
    {
        return true;
    }
    else
    {
        return false;
    }
}

template<class T>
//在索引值指向的节点前插入新节点
bool SingleList<T>::InsertAt(int index_, T value_)
{
    if (index_ > this->GetCount() || index_ < 0)
    {
        cerr << "A wrong position!\\n";
        return false;
    }

    ListNode<T>* current = head;
    while (index_)
    {
        current = current->pNext;
        index_--;
    }
    ListNode<T>* add = new ListNode<T>(value_);
    add->pNext = current->pNext;
    current->pNext = add;

    if (current != nullptr)
    {
        return true;
    }
    else
    {
        return false;
    }
}

template<class T>
bool SingleList<T>::RemoveTail()
{
    return RemoveAt(this->GetCount() - 1);
}

template<class T>
bool SingleList<T>::RemoveAt(int index_)
{
    if (index_ > this->GetCount() || index_ < 0)
    {
        cerr << "A wrong position!\\n";
        return false;
    }
    ListNode<T>* current = head;
    while (index_ - 1)
    {
        current = current->pNext;
        index_--;
    }
    ListNode<T>* deletePoint = current->pNext;

    if (current->pNext->pNext == nullptr)
    {
        current->pNext = nullptr;
    }
    else
        current->pNext = current->pNext->pNext;
    delete deletePoint;
    return true;
}

template<class T>
SingleList<T>::SingleList()
{
    head = new ListNode<T>();
    tail = head;
    tail->pNext = NULL;
}

template<class T>
SingleList<T>::~SingleList()
{
    RemoveAll();
    delete head;
}

template<class T>
T& SingleList<T>::GetAt(int index_)
{
    if (index_ > GetCount() || index_ < 0)
    {
        cerr << "A wrong position!\\n";
    }
    ListNode<T>* cur;
    cur = head->pNext;
    while (index_)
    {
        cur = cur->pNext;
        index_--;
    }
    return cur->GetData();
}

template<class T>
bool SingleList<T>::IsEmpty()
{
    return head->pNext == NULL;
}

template<class T>
int SingleList<T>::GetCount()
{
    int count = 0;
    ListNode<T>* cur = head->pNext;
    while (cur != nullptr)
    {
        cur = cur->pNext;
        count++;
    }
    return count;
}

template<class T>
void SingleList<T>::RemoveAll()
{
    ListNode<T>* cur;
    while (head->pNext != nullptr)
    {
        cur = head->pNext;
        head->pNext = cur->pNext;
        delete cur;
    }
    tail = head;
}

template<class T>
ListNode<T> * SingleList<T>::GetNodeAt(int index_)
{
    if (index_ > this->GetCount() - 1 || index_ < 0)
    {
        cerr << "A wrong position!\\n";
    }
    ListNode<T>* handle = head->pNext;
    while (index_)
    {
        handle = handle->pNext;
        index_--;
    }
    return handle;
}

template <class T>
ListNode<T>* SingleList<T>::GetHead(){//返回头指针  
    return head;
}

template <class T>
ListNode<T>* SingleList<T>::GetTail(){//返回尾指针  
    return tail;
}

template <class T>
ListNode<T>* SingleList<T>::GetCur(){
    return cur;
}

template <class T>
ListNode<T>* SingleList<T>::TowardCur(){
    cur = cur->GetLink();
    return cur
}

#endif

测试函数:

#include <iostream>  
#include "SingleList.h"  

using namespace std;

int main()
{
    SingleList<int> list;
    for (int i = 0; i < 9; i++)
        list.AddTail(i);

    cout << list.GetCount() << endl;

    cout << list.GetAt(3) << endl;

    list.RemoveAt(3);

    cout << list.GetCount() << endl;
    cout << list.GetAt(3) << endl;

    list.RemoveAll();
    cout << list.GetCount() << endl;

    system("PAUSE");
    return 0;
}

结果:

后续用纯c实现链表的基本操作:创建,增,删,改,查。

/*!
 * \\file singlist_c.cpp
 *
 * \\author ranjiewen
 * \\date 2017/02/25 12:15
 *
 * 
 */


/*********************************************************************************************************
以下为操作链表的算法,该链表为单链表。
链表以头指针为索引,头指针指向头节点,头节点指向首节点,以此类推,直到尾节点。
头节点中不存放数据,只存放指向首节点的指针,
设置头节点的目的是为了方便对链表的操作,如果不设置头节点,而是直接由头指针指向首节点,
这样在对头指针后的节点进行插入删除操作时就会与其他节点进行该操作时有所不同,便要作为一种特殊情况来分析
**********************************************************************************************************/

#include <stdio.h>
#include <stdlib.h>

typedef struct Node
{
    int data;
    struct Node* pNext;
    Node(int data_, Node* pNext_) :data(data_), pNext(pNext_){}

}Node,*pNode;

pNode CreateList();
void TraverseList(pNode);
bool IsEmpty(pNode);
int LengthList(pNode);
void SortList(pNode);
bool InsertList(pNode, int, int);
bool DeleteList(pNode, int, int*);
void ClearList(pNode);

int main()
{
    int len = 0;
    int data_del;
    pNode pHead = nullptr;
    //创建链表并遍历输出
    pHead = CreateList();
    TraverseList(pHead);

    //求链表长度并输出
    len = LengthList(pHead);
    if (!IsEmpty(pHead))
    {
        printf("This list\'s length is: %d\\n", len);
    }

    //向链表中插入数据并重新遍历输出
    if (InsertList(pHead,3,78))
    {
        printf("Insert successful!");
    }
    else
    {
        printf("Insert failed!");
    }
    TraverseList(pHead);

    //从链表中删除数据并重新遍历输出
    if (DeleteList(pHead,3,&data_del))
    {
        printf("delete succeed,the deleted data is : %d\\n", data_del);
    }
    else
    {
        printf("delete failed!");
    }
    TraverseList(pHead);

    //对链表排序,重新遍历输出
    SortList(pHead);
    printf("After sorted:");
    TraverseList(pHead);

    //清空链表,遍历输出
    ClearList(pHead);
    printf("After cleared:");
    TraverseList(pHead);
    
    return 0;
}

//创建链表,返回头指针
pNode CreateList()
{
    int value;
    pNode pHead = (pNode)malloc(sizeof(Node));
    pNode pCur = pHead;
    pCur->pNext = nullptr;
    if (pHead==nullptr)
    {
        printf("pHead malloc failed!");
        exit(-1);
    }
    printf("Input the first data(q to quit):");
    while (scanf("%d",&value)==1)
    {
        pNode pNew = (pNode)malloc(sizeof(Node));
        if (pNew==nullptr)
        {
            printf("pNew malloc failed!");
            exit(-1);
        }
        pNew->data = value;
        pNew->pNext = nullptr;
        pCur->pNext = pNew;
        pCur = pNew;  //移动当前节点到下一位置
        printf("Input next data(q to quit):");
    }
    return pHead;
}

//遍历链表
void TraverseList(pNode pHead)
{
    pNode pCur = pHead->pNext;
    printf("Now datas in the list are:\\n");
    while (pCur!=nullptr)
    {
        printf(" %d  ", pCur->data);
        pCur = pCur->pNext;
    }
    printf("\\n");
    return;
}

//判断链表是否为空
bool IsEmpty(pNode pHead)
{
    if (pHead->pNext!=nullptr)
    {
        return false;
    }
    return true;
}

//求链表的长度(不计入头结点)
int LengthList(pNode pHead)
{
    int len = 0;
    while (pHead->pNext!=nullptr)
    {
        len++;
        pHead = pHead->pNext;
    }
    return len;
}

//冒泡法对链表排序
void SortList(pNode pHead)
{
    pNode q, p;
    int temp;
    for (p = pHead->pNext; p != nullptr;p=p->pNext)
    {
        for (q = p->pNext; q != nullptr;q=q->pNext)
        {
            if (p->data>q->data) //从小到大排序
            {
                temp = p->data;
                p->data = q->data;
                q->data = temp;
            }
        }
    }
    return;
}

//在第pos个节点的后面插入一个新的节点,该节点数据为val
bool InsertList(pNode pHead, int pos, int val)
{
    if (pHead==nullptr)
    {
        return false; //或者pos大于链表长度
    }
    pNode pNew = (pNode)malloc(sizeof(Node));
    if (pNew==nullptr)
    {
        printf("new malloc failed!");
        exit(-1);
    }
    pNew->data = val;

    pNode pCur = pHead;
    while (--pos)
    {
        pCur = pCur->pNext;
    }
    pNew->pNext = pCur->pNext;
    pCur->pNext = pNew;

    return true;
}

//删除第pos个节点,并将删除的数据保存在pData所指向的位置
bool DeleteList(pNode pHead, int pos, int* pdata)
{
    pNode pCur = pHead;
    int i = 0;
    while (i<pos-1&&pCur->pNext!=nullptr)
    {
        pCur = pCur->pNext;
        i++;
    }

    if (pHead==nullptr||i>pos-1)
    {
        return false;
    }

    pNode pDel = pCur->pNext;
    pCur->pNext = pDel->pNext;
    *pdata = pDel->data;
    free(pDel);
    pDel = nullptr;

    return true;
}

//清空链表,即只剩下头结点,头结点没有数据
void ClearList(pNode pHead)
{
    pNode pCur=pHead->pNext;
    pNode ptemp=nullptr;
    while (pCur)
    {
        ptemp = pCur->pNext;  //用一个新的指针变量保存
        free(pCur);
        pCur = ptemp;
    }
    pHead->pNext = nullptr;
    return;
}

测试:

 

以上是关于4.2.2 算法之美--单链表实现的主要内容,如果未能解决你的问题,请参考以下文章

数据结构与算法学习——单链表相关算法

Python|单链表基本操作

如何用c语言实现单链表的逆置?

字符单链表识别数字,字母,其它字符,并分为三个循环链表的算法c++实现

单链表的逆置使用递归算法出现-842150451这个值,请求高手予以解决。。

单链表的逆置使用递归算法出现-842150451这个值,请求高手予以解决。。