码迷,mamicode.com
首页 > 编程语言 > 详细

数据结构与算法学习02:链表

时间:2016-04-22 20:55:16      阅读:268      评论:0      收藏:0      [点我收藏+]

标签:

一、链表
链表是一种动态集合,它是由一系列元素组成的一个列表。
数组也可以实现列表这种数据结构,但数组是静态的,而链表是动态。
通常,我们定义一个结点类(或结构体)来表示链表的元素,它由两部分组成:数值域和指针域。数值域存储当前结点的键,指针域存储下一个节点的地址。

template <class Type>
struct nodeType
{
    Type info;
    nodeType<Type> *link;
};

链表的一些基本操作如下:

  • 初始化为空表
  • 判断是否为空
  • 打印(遍历)链表
  • 计算链表的长度
  • 删除整个链表
  • 获取第一个节点的键
  • 获取最后一个节点的键
  • 查找指定键
  • 插入一个键
  • 删除指定键
  • 复制链表

大致的链表类图如下所示:
技术分享

与其它的定义可能有所不同,这里维护了两个指针,头指针和尾指针,尾指针是为了方便某些操作,如返回最后一个元素。同时,还维护了一个int型变量来表示链表中元素的个数。这种额外的开销在实际应用时可能不可取,但为某些操作带来很大的便利。
插入和删除以及查找函数定义为纯虚函数,这是因为有序链表和无序链表的相关操作不一样,所以由它们自己实现。这也意味着这个类是抽象类。

注意:上图中有两个陌生的公共成员函数:begin()和end(),它们返回一个迭代器类型(个人喜欢这样叫)的对象。迭代器对象可以很方便地实现链表的遍历等操作,它的类图如下:
技术分享

下面给出链表类的代码实现:linkedListType.h,这里把结点类和迭代器类的定义也放在这个文件了。由于用到了模板,只能把实现代码也放在定义文件内,看起来会比较长哦。

#ifndef _LINKEDLISTTYPE_H
#define _LINKEDLISTTYPE_H
#include "stdafx.h"

//节点类定义
template <class Type>
struct nodeType
{
    Type info;
    nodeType<Type> *link;
};

//迭代器类定义
template <class Type>
class linkedListIterator
{
public:
    linkedListIterator();    //构造函数
    linkedListIterator(nodeType<Type> *ptr); //复制构造函数
    Type operator*();    //解引用操作符重载
    linkedListIterator<Type> operator++();  //自增操作符重载
    bool operator==(const linkedListIterator<Type>& right) const;   //相等操作符重载
    bool operator!=(const linkedListIterator<Type>& right) const;    //不等操作符重载
private:
    nodeType<Type> *current;   //当前结点
};

//链表类定义
template <class Type>
class linkedListType
{
public:
    linkedListType();    //构造函数
    linkedListType(const linkedListType<Type>& otherList);    //复制构造函数
    ~linkedListType();    //析构函数
    const linkedListType<Type>& operator=(const linkedListType<Type>&);    //重载赋值操作符
    void initializeList();    //初始化为空表
    bool isEmptyList() const;    //判空
    void print() const;      //遍历链表
    int length() const;      //长度
    void destroyList();        //销毁链表
    Type front() const;        //返回第一节点的键
    Type back() const;        //返回最后一个节点的键
    virtual bool search(const Type& searchItem) const = 0;    
    virtual void insertFirst(const Type& newItem) = 0;    
    virtual void insertLast(const Type& newItem) = 0;    
    virtual void deleteNode(const Type& deleteItem) = 0;    
    linkedListIterator<Type> begin();    
    linkedListIterator<Type> end();        
protected:
    int count; 
    nodeType<Type> *first;
    nodeType<Type> *last;
private:
    void copyList(const linkedListType<Type>& otherList);    
};

//下面是链表类的实现
template <class Type>
linkedListType<Type>::linkedListType() 
{
    first = NULL;
    last = NULL;
    count = 0;
}

template <class Type>
linkedListType<Type>::linkedListType(const linkedListType<Type>& otherList)
{
    first = NULL;
    copyList(otherList);
}

template <class Type>
linkedListType<Type>::~linkedListType() //destructor
{
    destroyList();
}

template <class Type>
const linkedListType<Type>& linkedListType<Type>::operator=(const linkedListType<Type>& otherList)
{
    if (this != &otherList) 
    {
        copyList(otherList);
    }
    return *this;
}

template <class Type>
bool linkedListType<Type>::isEmptyList() const
{
    return (first == NULL);
}

template <class Type>
void linkedListType<Type>::destroyList()
{
    nodeType<Type> *temp;  //临时保存当前需删除的节点
    while (first != NULL) 
    {
        temp = first; 
        first = first->link; 
        delete temp; 
    }
    last = NULL;
    count = 0;
}

template <class Type>
void linkedListType<Type>::initializeList()
{
    destroyList(); 
}

template <class Type>
void linkedListType<Type>::print() const
{
    nodeType<Type> *current; 
    current = first; 
    while (current != NULL) 
    {
        cout << current->info << " ";
        current = current->link;
    }
}

template <class Type>
int linkedListType<Type>::length() const
{
    return count;
}

template <class Type>
Type linkedListType<Type>::front() const
{
    assert(first != NULL);
    return first->info; 
}

template <class Type>
Type linkedListType<Type>::back() const
{
    assert(last != NULL);
    return last->info; 
}

template <class Type>
linkedListIterator<Type> linkedListType<Type>::begin()
{
    linkedListIterator<Type> temp(first);
    return temp;
}

template <class Type>
linkedListIterator<Type> linkedListType<Type>::end()
{
    linkedListIterator<Type> temp(NULL);
    return temp;
}

template <class Type>
void linkedListType<Type>::copyList(const linkedListType<Type>& otherList)
{
    nodeType<Type> *newNode; //新建结点
    nodeType<Type> *current; //当前需复制的结点    
    if (first != NULL) //先清空
        destroyList();

    if (otherList.first == NULL) //如果otherList是空表
    {
        first = NULL;
        last = NULL;
        count = 0;
    }
    else
    {
        count = otherList.count;//元素个数

        //复制第一个元素
        current = otherList.first;         
        first = new nodeType<Type>;
        first->info = current->info; 
        first->link = NULL;         
        last = first; 

        //复制下一个元素
        current = current->link; 
        while (current != NULL) 
        {
            newNode = new nodeType<Type>; 
            newNode->info = current->info; 
            newNode->link = NULL;            

            last->link = newNode; 
            last = newNode; 

            current = current->link;
        }            
    }
}

//下面是迭代器类的实现
template <class Type>
linkedListIterator<Type>::linkedListIterator()
{
    current = NULL;
}
template <class Type>
linkedListIterator<Type>::linkedListIterator(nodeType<Type> *ptr)
{
    current = ptr;
}
template <class Type>
Type linkedListIterator<Type>::operator*()
{
    return current->info;
}
template <class Type>
linkedListIterator<Type> linkedListIterator<Type>::operator++()
{
    current = current->link;
    return *this;
}
template <class Type>
bool linkedListIterator<Type>::operator==(const linkedListIterator<Type>& right) const
{
    return (current == right.current);
}
template <class Type>
bool linkedListIterator<Type>::operator!=(const linkedListIterator<Type>& right) const
{
    return (current != right.current);
}
#endif

二、无序链表
无序链表是相对有序列表而言的,它们在插入和删除操作的区别非常大,比如:
有序链表每插入一个元素都要找到正确的位置,而无序链表则可以随意在表头或表尾插入。
我们让无序链表继承链表ADT,这样可得到无序链表的类图:
技术分享

下面是无序链表的编程实现:unorderedLinkedList.h

#include "stdafx.h"
#include "linkedListType.h"

template <class Type>
class unorderedLinkedList: public linkedListType<Type>
{
public:
    bool search(const Type& searchItem) const;    //查找
    void insertFirst(const Type& newItem);        //从表头插入
    void insertLast(const Type& newItem);        //从表尾插入
    void deleteNode(const Type& deleteItem);    //删除
};

template <class Type>
bool unorderedLinkedList<Type>::search(const Type& searchItem)const
{
    nodeType<Type> *current; 
    current = first; 
    while (current != NULL) 
        if (current->info == searchItem) 
            return true;
        else
            current = current->link; 
    return false; 
}

template <class Type>
void unorderedLinkedList<Type>::insertFirst(const Type& newItem)
{
    //从表头插入一个元素
    nodeType<Type> *newNode; //新建一个结点
    newNode = new nodeType<Type>; 
    newNode->info = newItem;     
    newNode->link = first; 
    first = newNode; 

    //总的元素个数加1
    count++; 

    //如果是空表,则最后一个元素就是当前插入的元素,所以让last指向它
    if (last == NULL) 
        last = newNode;
}

template <class Type>
void unorderedLinkedList<Type>::insertLast(const Type& newItem)
{    
    nodeType<Type> *newNode; 
    newNode = new nodeType<Type>; 
    newNode->info = newItem; 
    newNode->link = NULL; 
    if (first == NULL) //空表的情况:first==NULL,这时插入的节点既是头结点也是尾结点
    {
        first = newNode;
        last = newNode;
        count++; //元素个数加一
    }
    else //不为空表的情况:这时只要调整尾结点指针
    {
        last->link = newNode; //从尾部插入
        last = newNode; //调整last指针        
        count++; 
    }
}

template <class Type>
void unorderedLinkedList<Type>::deleteNode(const Type& deleteItem)
{
    nodeType<Type> *current; //遍历链表用的游标
    nodeType<Type> *trailCurrent; //游标的上一个位置
    bool found;  //标记是否找到指定元素
    if (first == NULL) //情况1:空表
        cout << "Cannot delete from an empty list."<< endl;
    else
    {
        if (first->info == deleteItem) //情况2:第一个元素即为需要删除的元素
        {
            current = first;
            first = first->link;
            count--;
            if (first == NULL) //删除完后检查是否为空:为空则调整last指针
                last = NULL;
            delete current;
        }
        else //情况3:不是第一个元素,那只能一步步往下找了,找到了删掉它,没找到提示用户
        {
            found = false;
            trailCurrent = first; //目前游标的上一个位置是first,即第一个元素
            current = first->link; //目前游标的位置是first后面的元素,即第二个元素

            while (current != NULL && !found)
            {
                if (current->info != deleteItem)
                {
                    trailCurrent = current;
                    current = current-> link;
                }
                else
                    found = true;
            }
            if (found) //情况3.a:找到了,删掉它
            {
                trailCurrent->link = current->link;
                count--;
                if (last == current) //被删元素是最后一个元素,调整last指针
                    last = trailCurrent;         
                delete current; //记得释放内存哦
            }
            else  //情况3.b:没有找到,提示用户删除失败
                cout << "The item to be deleted is not in "<< "the list." << endl;
        }
    }
}

三、有序链表
有序链表中的元素都是按顺序链接的,第一个元素最小,最后一个元素最大,可以有重复元素。
让有序链表继承链表类,其类图如下:
技术分享

与无序链表不同的是它多了一个insert函数,因为有序链表从表头表尾插入都没实际意义,它们都要通过找到合适的位置再插入,所以定义了一个一般的插入方法来实现它们。
有序链表的操作相对无序链表比较复杂一点,下面以插入函数为例介绍分析方法。

插入一个元素:我们按照遍历链表查找第一个大于插入元素的情景进行分类
用一个current指针代表当前的游标元素,用一个trailCurrent指针指向current上一个元素

情况1:表为空,这时直接插入就可以,同时需要调整first和last指针,count+1
技术分享

情况2:插入元素比表里所有的元素都小,即插入位置为表头,这时插入的同时要调整first指针,同时count+1
技术分享
技术分享

情况3:插入元素的位置不不在表头,它在某个地方
3.a:插入元素比表中所有元素都大,也就是说没有找到比他大的元素,这时它插入表尾,需要调整last指针,count+1
技术分享
技术分享

3.b: 插入元素在表中间的某个位置。first和last都不需调整,只需count+1
技术分享
技术分享

有序链表的编程实现:orderedLinkedList.h

#include "linkedListType.h"

template <class Type>
class orderedLinkedList: public linkedListType<Type>
{
public:
    bool search(const Type& searchItem) const;    
    void insert(const Type& newItem);
    void insertFirst(const Type& newItem);
    void insertLast(const Type& newItem);
    void deleteNode(const Type& deleteItem);    
};

template <class Type>
bool orderedLinkedList<Type>::search(const Type& searchItem) const
{
    bool found = false;
    nodeType<Type> *current; //遍历链表的游标
    current = first; //从第一个元素开始查找
    while (current != NULL && !found)
        if (current->info >= searchItem)
            found = true;
        else
            current = current->link;
    if (found)
        found = (current->info == searchItem); //测试一下
    return found;
}

template <class Type>
void orderedLinkedList<Type>::insert(const Type& newItem)
{
    nodeType<Type> *current; //遍历链表的游标
    nodeType<Type> *trailCurrent; //游标的上一个元素
    nodeType<Type> *newNode; //新插入的元素
    bool found;//标记是否找到大于newItem的元素
    newNode = new nodeType<Type>; 
    newNode->info = newItem;
    newNode->link = NULL; 

    if (first == NULL) //情况1:空表,直接插入
    {
        first = newNode;
        last = newNode;
        count++;
    }
    else
    {
         //从第一个结点开始遍历,看能不能找到值大于newItem的元素,找到了就插入它前面,没找到就插入尾部
        current = first;
        found = false;
        while (current != NULL && !found)
            if (current->info >= newItem)//找到就标记
                found = true;
            else
            {
                trailCurrent = current;
                current = current->link;
            }
            if (current == first) //情况2:第一个元素就大于newItem,插入位置为链表头,需要调整first
            {
                newNode->link = first;
                first = newNode;
                count++;
            }
            else //情况3:插入位置不在链表头,可能在链表尾,即可能需要调整last
            {
                trailCurrent->link = newNode;
                newNode->link = current;
                if (current == NULL)//插入链表尾部,需要调整last
                    last = newNode;
                count++;
            }
    }
}

template <class Type>
void orderedLinkedList<Type>::insertFirst(const Type& newItem)
{
    insert(newItem);
}
template <class Type>
void orderedLinkedList<Type>::insertLast(const Type& newItem)
{
    insert(newItem);
}

template <class Type>
void orderedLinkedList<Type>::deleteNode(const Type& deleteItem)
{
    nodeType<Type> *current; //遍历链表的游标
    nodeType<Type> *trailCurrent; //游标的上一个元素
    bool found;    //标记是否找到等于newItem的元素

    if (first == NULL) //情况1:空表,不能删除
        cout << "Cannot delete from an empty list." << endl;
    else
    {
        //从第一个元素开始向后遍历,看能不能找到等于deleteItem的元素
        current = first;
        found = false;
        while (current != NULL && !found) 
            if (current->info >= deleteItem)//注意,我们找到大于等于的元素就标记,这个元素不一定等于deleteItem
                found = true;
            else
            {
                trailCurrent = current;
                current = current->link;
            }
            if (current == NULL) //情况2:没有找到
                cout << "The item to be deleted is not in the "    << "list." << endl;
            else
                if (current->info == deleteItem)                     
                {
                    if (first == current) //情况3:第一个元素等于newItem
                    {
                        first = first->link;
                        if (first == NULL)//删除完成后判断是否为空,如果为空则调整尾指针
                            last = NULL;
                        delete current;//记得释放内存
                    }
                    else //情况4:不在第一个位置找到了等于newItem的元素
                    {
                        trailCurrent->link = current->link;
                        if (current == last)//如果是最后一个元素,则删除之后要调整尾指针
                            last = trailCurrent;
                        delete current;
                    }
                    count--;
                }
                else 
                    cout << "The item to be deleted is not in the "<< "list." << endl;
    }
}

数据结构与算法学习02:链表

标签:

原文地址:http://blog.csdn.net/wen524/article/details/51203657

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!