带头结点与不带头结点的单链表-LinkList

单链表有两种形式:带头结点的单链表和不带头结点的单链表。
关于单链表L的基本操作跟带头结点的单链表的基本操作稍有不同,特别的是在删除函数和插入函数中都加入了对第一个结点的判断,因为在插入和删除中第一个结点和其他结点时操作不同,要改变链表头指针的值。而带头结点的单链表无论插入和删除第几个元素,其操作都是统一的。

接下来具体分析。
1.带头节点的链表的插入,首先使用临时变量p等于要插入之前的节点(不管具体的插入位置),之后不管要插入的节点x是插到链表头还是插到链表的其他位置都是如下语句:
x->next= p->next;
p->next = x;

2.不带头结点的链表的插入,若要插到链表的开头则
x->next = head->next;
head = x;//这里不再是head->next = x
若插到链表的其他位置则
p = 插入之前的节点
x->next = p->next;
p->next = x;
3.带头结点的链表的删除,不解释,同样不存在删除位置的差异。

4.不带头结点的链表的删除,删除第一个节点时,head=head->next。删除其他节点时,head的值不会改变。

综上所述,带头节点的单链表,不论删除和插入的位置如何,不需要修改head的值,不带头结点的单链表则需要修改head的值。所以单链表一般为带头结点的单链表。

下面是一个带头结点的单链表LinkList示例
1.辅助文件包Assistance.h

#ifndef __ASSISTANCE_H__                // 如果没有定义__ASSISTANCE_H__
#define __ASSISTANCE_H__                // 那么定义__ASSISTANCE_H__

// 辅助软件包

// ANSI C++标准库头文件
#include <cstring>                  // 标准串操作
#include <iostream>                 // 标准流操作
#include <limits>                   // 极限
#include <cmath>                    // 数据函数
#include <fstream>                  // 文件输入输出
#include <cctype>                   // 字符处理
#include <ctime>                    // 日期和时间函数
#include <cstdlib>                  // 标准库
#include <cstdio>                   // 标准输入输出
#include <iomanip>                  // 输入输出流格式设置
#include <cstdarg>                  // 支持变长函数参数
#include <cassert>                  // 支持断言
using namespace std;                // 标准库包含在命名空间std中

// 自定义类型
enum Status {SUCCESS, FAIL, UNDER_FLOW, OVER_FLOW,RANGE_ERROR, DUPLICATE_ERROR,
    NOT_PRESENT, ENTRY_INSERTED, ENTRY_FOUND, VISITED, UNVISITED};

// 宏定义
#define DEFAULT_SIZE 1000           // 缺省元素个数
#define DEFAULT_INFINITY 1000000    // 缺省无穷大


// 辅助函数声明

char GetChar(istream &inStream = cin); // 从输入流inStream中跳过空格及制表符获取一字符

template <class ElemType >
void Swap(ElemType &e1, ElemType &e2);  // 交换e1, e2之值

template<class ElemType>
void Display(ElemType elem[], int n);   // 显示数组elem的各数据元素值

template <class ElemType>
void Write(const ElemType &e);          // 显示数据元素

// 辅助类
class Error;            // 通用异常类

char GetChar(istream &inStream)
// 操作结果:从输入流inStream中跳过空格及制表符获取一字符
{
    char ch;                                // 临时变量
    while ((ch = (inStream).peek()) != EOF  // 文件结束符(peek()函数从输入流中接受1
           // 字符,流的当前位置不变)
           && ((ch = (inStream).get()) == ' '   // 空格(get()函数从输入流中接受1字符,流
               // 的当前位置向后移1个位置)
               || ch == '\t'));                 // 制表符

    return ch;                              // 返回字符
}


// 通用异常类
#define MAX_ERROR_MESSAGE_LEN 100
class Error
{
private:
// 数据成员
    char message[MAX_ERROR_MESSAGE_LEN];// 异常信息

public:
//  方法声明
    Error(const char *mes = "一般性异常!");  // 构造函数
    ~Error(void) {};                   // 析构函数
    void Show() const;                  // 显示异常信息
};

// 通用异常类的实现部分
Error::Error(const char *mes)
// 操作结果:由mes构构通用异常对象
{
    strcpy(message, mes);               // 复制异常信息
}

void Error::Show()const
// 操作结果:显示异常信息
{
    cout << message << endl;            // 显示异常信息
}


template <class ElemType >
void Swap(ElemType &e1, ElemType &e2)
// 操作结果: 交换e1, e2之值
{
    ElemType temp;      // 临时变量
    // 循环赋值实现交换e1, e2
    temp = e1;  e1 = e2;  e2 = temp;
}

template<class ElemType>
void Display(ElemType elem[], int n)
// 操作结果: 显示数组elem的各数据元素值
{
    for (int i = 0; i < n; i++)
    {   // 显示数组elem
        cout << elem[i] << "  ";
    }
    cout << endl;
}

template <class ElemType>
void Write(const ElemType &e)
// 操作结果: 显示数据元素
{
    cout << e << "  ";
}

#endif

2.节点声明Node.h

//
// Created by YYL on 2017/5/4.
//

#ifndef _NODE_H_
#define _NODE_H_

#include <afxres.h>

template <class T>
struct Node{
    //数据元素
    T data;
    Node<T> *next;//指针域
    //构造函数
    Node();
    Node(T e,Node<T> *next=NULL);
};

//实现部分
template <class T>
Node<T>::Node() {
    next=NULL;
}

template<class T>
Node<T>::Node(T e, Node<T> *next) {
    data=e;
    this->next=next;//
}
#endif

3.单链表类的声明LinkList.h

//
// Created by YYL on 2017/5/4.
//

#ifndef _LK_LIST_H_
#define _LK_LIST_H_

#include "Node.h"
#include "Assistance.h"

//单链表类
template <class T>
class LinkList {
protected:
    Node<T> *head;//头结点指针
    int length;//单链表长度
public:
    LinkList();
    LinkList(T v[],int n);
    virtual ~LinkList();

    int getLength() const;
    bool isEmpty() const;//判断单链表是否为空
    bool clear();
    void traverse(void (*vist)(const T &)) const;//遍历单链表
    //指针函数作为参数,使用时只需传入函数即可实现传入 的函数遍历
    int LocalElem(const T&) const;
    Status GetElem(int position,T &e) const;//取出单链表position处的值并存入e中
    Status SetElem(int position,const T &e);
    Status DeleteElem(int position,T &e);
    Status InsertElem(int position,const T &e);
    Status InsertElem(const T &e);//在单链表尾删除

    //构造函数
    LinkList(const LinkList<T> &la);//复制构造函数
    LinkList<T> &operator=(const LinkList<T> &la);//赋值运算符

};


#endif

4.单链表的实现LinkList.cpp

//单链表:一个节点由两个域组成,一个存放数据元素data,一个域指向该单链表中的下一个节点的指针
#include "LinkList.h"
template<class T>
LinkList<T>::LinkList() {
    head=new Node<T>;
    assert(head);
    length=0;
}
//assert() 函数用法
// assert宏的原型定义在中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:
//void assert( int expression );
//assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,
//然后通过调用 abort 来终止程序运行。
template <class T>
LinkList::LinkList(T *v, int n) {
    Node<T> *p;
    p=head=new Node<T>;

    assert(head!=0);
    for(int i=0;i<n;i++){
        p->next=new Node<T>(v[i],NULL);
        p=p->next;
    }
    length=n;
}



template <class T>
LinkList<T>::~LinkList() {
    clear();
    delete head;
}

template<class T>
int LinkList<T>::getLength() const {
    return length;
}

template<class T>
bool LinkList<T>::isEmpty() const {
    return head->next==NULL;
}

template<class T>
bool LinkList<T>::clear(){
    Node<T> *p=head->next;
    while (p!=NULL){
        head->next=p->next;
        delete p;
        p=head->next;
    }
    length=0;
}

template<class T>
void LinkList<T>::traverse(void (*vist)(const T &) ) const {
    Node<T>*p=head->next;
    while(p!=NULL){
        (*vist)(p->data);
        p=p->next;
    }
}
//元素定位函数
template<class T>
int LinkList<T>::LocalElem(const T &e) const {
    Node<T> *p=head->next;
    int count=1;
    while(p!=NULL&&p->data!=e){
        count++;
        p=p->next;
    }
    return (p!=NULL)?count:0;
}
template <class T>//取出position处的值并存入e中
Status LinkList<T>::GetElem(int position, T &e) const {
    if(position<1||position>length)
        return RANGE_ERROR;
    else{
        Node<T> *p=head->next;
        int count;
        for(count=1;count<position;count++){
            p=p->next;
        }
        e=p->data;
        return ENTRY_FOUND;
    }
}

template<class T>
Status LinkList::SetElem(int position, const T &e) {//设置元素
if(position<1||position>length)
    return RANGE_ERROR;
else{
    Node<T> *p=head->next;
    int count;
    for(count=1;count<position;count++)
        p=p->next;
    p->data=e;
    return SUCCESS;
}
}

template<class T>//删除position处的元素
Status LinkList<T>::DeleteElem(int position, T &e) {
    if(position<1||position>length)
        return RANGE_ERROR;
    else{
        Node<T> *p=head,*q;
        for(int i=1;i<position;i++){
            p=p->next;
        }
        q = p->next;
        p->next = q->next;//删除结点
        e = q->data;
        length--;
        delete q;//释放被删的节点
        return SUCCESS;
    }
}

template<class T>//插入元素到指定位置
Status LinkList<T>::InsertElem(int position, const T &e) {
    if(position<1||position>length)
        return RANGE_ERROR;
    else {
        Node<T> *p=head,*q;
        for(int i=0;i<position;i++){
            p=p->next;
        }
        q = new Node<T>(e,p->next);
        assert(q);
        p->next = q;
        length++;
        return SUCCESS;
    }
}

template <class T>
Status LinkList<T>::InsertElem(const T &e) {
Node<T> *p,*q;
    q=new Node<T>(e,NULL);
    assert(q);//q指针构造失败则终止运行
    for(p=head;p->next!=NULL;p=p->next);
    p->next=q;
    length++;
    return SUCCESS;
}

template<class T>//复制构造函数
LinkList<T>::LinkList(const LinkList<T> &la) {
    int lalength=la.getLength();
    T e;//存放
    head=new Node<T>;
    assert(head);//头指针构造失败则终止运行
    length=0;
    for(int i=1;i<=lalength;i++){
        la.GetElem(i,e);//取出第i个元素的值放入e中
        InsertElem(e);//将e加到表尾
    }
}

template <class T>
LinkList<T> &LinkList<T>::operator=(const LinkList<T> &la){
    if(&la!=this){
        int lalength=la.getLength();
        T e;
        clear();
        for(int i=1;i<=lalength;i++){
            la.GetElem(i,e);//取出第i个元素的值放入e中
            InsertElem(e);//将e加到表尾
        }
    }
    return *this;
}

不带头结点

#include <iostream>  
using namespace std;  
template<class Type>  
//定义结点  
struct Node  
{  
    Type data;  
    Node<Type> *next;  
};  
//定义链表  
template<class Type>  
class LinkList  
{  
protected:  
    int len;//链表中结点个数  
    Node<Type>* Head; //不使用头结点  
public:  
    LinkList();//默认构造函数  
    LinkList(const LinkList<Type>& otherList);//拷贝构造函数  
    ~LinkList();  
    void createListForward();//头插法  
    void createBackward();//尾插法  
    void initList();//生成头结点,尾部设置为NULL  
    bool isEmptyList();  
    int  length();  
    void destoryList();  
    void getFirstData(Type& firstItem);  
    void getData(int pos,Type& firstItem);  
    void insertFirst(Type newItem);  
    void insertLast(Type newItem);  
    void deleteFirst(Type& data);  
    void deleteLast();  
    void reverse();  
    const LinkList<Type>& operator=(const LinkList<Type>&otherList);  
    friend ostream& operator<< <>(ostream& cout,const LinkList<Type>& list);  
};  

template<class Type>  
LinkList<Type>::LinkList() //初始化时,只有一个头结点,有head指向  
{  
    Head = NULL;  
    len =0;  
}  

template<class Type>  
LinkList<Type>::LinkList(const LinkList<Type>&otherList)  
{  
    Head = NULL;  
    len = otherList.len;  
    Node<Type>* current;//自己链表的尾部元素  
    Node<Type>* otherListCurrent=otherList.Head;//otherListCurrent指向第一个元素  
    while(otherListCurrent!=NULL)//拷贝的目标不为空  
    {  
        for (int i=1;i<=otherList.len;i++)  
        {  
            Node<Type>* NewNode = new Node<Type>;  
            NewNode->data = otherListCurrent->data;  
            NewNode->next = NULL;  
            if (i==1)  
            {  
                Head = NewNode;  
                current = Head;  
            }  
            else  
            {  
                current->next = NewNode;  
                current = current->next;  
            }  
            otherListCurrent = otherListCurrent->next;  
        }  
    }  

}  

template<class Type>  
const LinkList<Type>& LinkList<Type>::operator=(const LinkList<Type>&otherList)//赋值函数  
{  
    Node<Type>* current;//current总是指向要插的位置的前一结点  
    Node<Type>* otherListCurrent=otherList.Head;//otherListCurrent指向第一个元素  
    if (this!=&otherList)//避免自己给自己赋值  
    {  
        if (Head!=NULL)  
        {  
            destoryList();//自己有结点,先销毁  
        }  
        if(otherListCurrent!=NULL)  
        {  
            bool first = true;  
            while(otherListCurrent!=NULL)  
            {  
                Node<Type>* newNode = new Node<Type>;  
                newNode->data = otherListCurrent->data;  
                newNode->next = NULL;  
                if (first)  
                {  
                    Head = newNode;  
                    current = Head;  
                    first = false;  
                }  
                else  
                {  
                    current->next = newNode;  
                    current = current->next;  
                }  
                otherListCurrent = otherListCurrent->next;  
            }     
        }  
    }  
    return *this;//为了连续赋值  
}  

template<class Type>  
LinkList<Type>::~LinkList()  
{  
    destoryList();  
}  

template<class Type>  
void LinkList<Type>::createListForward()//头插法  
{  
    Node<Type>* newNode;  
    cout<<"输入链表长度:"<<endl;  
    cin>>len;  
    for (int i=1;i<=len;i++)  
    {  
        newNode = new Node<Type>;  
        cout<<"输入元素:"<<endl;  
        cin>>newNode->data;  
        newNode->next=Head;  
        Head = newNode; //每插入一个结点,都是要把它放在第一个结点的位置  
    }  
}  

template<class Type>  
void LinkList<Type>::createBackward()//尾插法  
{  
    Node<Type>* newNode;  
    Node<Type>* current;//总是指向最后一个节点  
    cout<<"输入链表长度:"<<endl;  
    cin>>len;  
    for (int i=1;i<=len;i++)  
    {  
        newNode = new Node<Type>;  
        cout<<"输入元素:"<<endl;  
        cin>>newNode->data;  
        newNode->next = NULL;  
        if (i==1)  
        {  
            Head = newNode;  
            current = Head;  
        }  
        else  
        {  
            current->next=newNode;  
            current = current->next;  
        }  

    }  
}  

template<class Type>  
void LinkList<Type>::initList() //所有结点都销毁  
{  
    destoryList();  
    len=0;  
    Head=NULL;  
}  

template<class Type>  
bool LinkList<Type>::isEmptyList()  
{  
    if (Head==NULL)  
    {  
        return true;  
    }  
    else  
    {  
        return false;  
    }  
}  



template<class Type>  
int LinkList<Type>::length()  
{  
    return len;  
}  

template<class Type>  
void LinkList<Type>::destoryList()//销毁包括头结点  
{  
    Node<Type>* current;  
    while(Head!=NULL)  
    {  
        current = Head;  
        Head = current->next;  
        delete current;  
    }  
    Head=NULL;  
    len=0;  
}  

template<class Type>  
void LinkList<Type>::getFirstData(Type& firstItem)  
{  
    if (!isEmptyList())  
    {  
        firstItem = Head->data;  
    }  
    else  
    {  
        cout<<"链表为空!"<<endl;  
    }  
}  


template<class Type>  
void LinkList<Type>::getData(int pos,Type& newItem)  
{  
    if (pos<1 || pos>len)  
    {  
        cout<<"位置不当!"<<endl;  
    }  
    else  
    {  
        Node<Type>* current = Head;  
        for (int i=1;i<pos;i++)  
        {  
            current = current->next;  
        }  
        newItem = current->data;  
    }  
}  

template<class Type>  
void LinkList<Type>::insertFirst(Type newItem)  
{  
    Node<Type> *newNode = new Node<Type>;  
    newNode->data = newItem;  
    newNode->next = Head;  
    Head= newNode;  
    len++;  
}  

template<class Type>  
void LinkList<Type>::insertLast(Type newItem)  
{  
    Node<Type>* current = Head;  
    while(current!=NULL && current->next!=NULL)  
    {  
        current = current->next;  
    }  
    Node<Type> *newNode = new Node<Type>;  
    newNode->data = newItem;  
    if (current==NULL)//链表为空  
    {  
        newNode->next = current;  
        current = newNode;  
    }  
    else  
    {  
        newNode->next = current->next;  
        current->next = newNode;  
    }  
    len++;  
}  


template<class Type>  
void LinkList<Type>::deleteFirst(Type& data)  
{  
    if (!isEmptyList())  
    {  
        data = Head->data;  
        Node<Type>* temp = Head;  
        Head = Head->next;  
        delete temp;  
    }  
    else  
    {  
        cout<<"栈空!"<<endl;  
    }  
    len--;  
}  

template<class Type>  
void LinkList<Type>::deleteLast()  
{  
    Node<Type>* current = Head;  
    if (isEmptyList())  
    {  
        cout<<"链表为空!"<<endl;  
    }  
    else  
    {  
        for (int i=1;i<len-1;i++)  
        {  
            current = current->next;  
        }  
        Node<Type>* nextCurrent = current->next;  
        current->next = nextCurrent->next;  
        delete nextCurrent;  
    }  
    len--;  

}  

template<class Type>  
void LinkList<Type>::reverse()  
{  
    Node<Type>* current = Head;  
    Head=NULL;  
    if (current==NULL)  
    {  
        cout<<"链表为空!"<<endl;  
    }  
    else  
    {  
        while (current!=NULL)  
        {  
            Node<Type>* nextCurrent = current->next;  
            current->next = Head;  
            Head=current;  
            current = nextCurrent;  
        }  
    }  
}  

template<class Type>  
ostream& operator<< <>(ostream& cout,const LinkList<Type>& list)  
{  
    Node<Type>*current=list.Head; //有头结点,这是current指向第一个结点  
    if (current!=NULL)  
    {  
        while (current!=NULL)  
        {  
            cout<<current->data<<endl;  
            current=current->next;  
        }  
    }  
    else  
    {  
        cout<<"链表为空!"<<endl;  
    }  
    return cout;  
}  
  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值