单链表有两种形式:带头结点的单链表和不带头结点的单链表。
关于单链表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 // 标准串操作
#include // 标准流操作
#include // 极限
#include // 数据函数
#include // 文件输入输出
#include // 字符处理
#include // 日期和时间函数
#include // 标准库
#include // 标准输入输出
#include // 输入输出流格式设置
#include // 支持变长函数参数
#include // 支持断言
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
template T>
struct Node{
//数据元素
T data;
Node<T> *next;//指针域
//构造函数
Node();
Node(T e,Node<T> *next=NULL);
};
//实现部分
template T>
Node<T>::Node() {
next=NULL;
}
templateT>
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 LinkList {
protected:
Node *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 &la);//复制构造函数
LinkList &operator=(const LinkList &la);//赋值运算符
};
#endif
4.单链表的实现LinkList.cpp
//单链表:一个节点由两个域组成,一个存放数据元素data,一个域指向该单链表中的下一个节点的指针
#include "LinkList.h"
template<class T>
LinkList::LinkList() {
head=new Node;
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 *p;
p=head=new Node;
assert(head!=0);
for(int i=0;inext=new Node(v[i],NULL);
p=p->next;
}
length=n;
}
template <class T>
LinkList::~LinkList() {
clear();
delete head;
}
template<class T>
int LinkList::getLength() const {
return length;
}
template<class T>
bool LinkList::isEmpty() const {
return head->next==NULL;
}
template<class T>
bool LinkList::clear(){
Node *p=head->next;
while (p!=NULL){
head->next=p->next;
delete p;
p=head->next;
}
length=0;
}
template<class T>
void LinkList::traverse(void (*vist)(const T &) ) const {
Node*p=head->next;
while(p!=NULL){
(*vist)(p->data);
p=p->next;
}
}
//元素定位函数
template<class T>
int LinkList::LocalElem(const T &e) const {
Node *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::GetElem(int position, T &e) const {
if(position<1||position>length)
return RANGE_ERROR;
else{
Node *p=head->next;
int count;
for(count=1;countnext;
}
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 *p=head->next;
int count;
for(count=1;countnext;
p->data=e;
return SUCCESS;
}
}
template<class T>//删除position处的元素
Status LinkList::DeleteElem(int position, T &e) {
if(position<1||position>length)
return RANGE_ERROR;
else{
Node *p=head,*q;
for(int i=1;inext;
}
q = p->next;
p->next = q->next;//删除结点
e = q->data;
length--;
delete q;//释放被删的节点
return SUCCESS;
}
}
template<class T>//插入元素到指定位置
Status LinkList::InsertElem(int position, const T &e) {
if(position<1||position>length)
return RANGE_ERROR;
else {
Node *p=head,*q;
for(int i=0;inext;
}
q = new Node(e,p->next);
assert(q);
p->next = q;
length++;
return SUCCESS;
}
}
template <class T>
Status LinkList::InsertElem(const T &e) {
Node *p,*q;
q=new Node(e,NULL);
assert(q);//q指针构造失败则终止运行
for(p=head;p->next!=NULL;p=p->next);
p->next=q;
length++;
return SUCCESS;
}
template<class T>//复制构造函数
LinkList::LinkList(const LinkList &la) {
int lalength=la.getLength();
T e;//存放
head=new Node;
assert(head);//头指针构造失败则终止运行
length=0;
for(int i=1;i<=lalength;i++){
la.GetElem(i,e);//取出第i个元素的值放入e中
InsertElem(e);//将e加到表尾
}
}
template <class T>
LinkList &LinkList::operator=(const LinkList &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
using namespace std;
template<class Type>
//定义结点
struct Node
{
Type data;
Node *next;
};
//定义链表
template<class Type>
class LinkList
{
protected:
int len;//链表中结点个数
Node* Head; //不使用头结点
public:
LinkList();//默认构造函数
LinkList(const LinkList& 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& operator=(const LinkList&otherList);
friend ostream& operator<< <>(ostream& cout,const LinkList& list);
};
template<class Type>
LinkList::LinkList() //初始化时,只有一个头结点,有head指向
{
Head = NULL;
len =0;
}
template<class Type>
LinkList::LinkList(const LinkList&otherList)
{
Head = NULL;
len = otherList.len;
Node* current;//自己链表的尾部元素
Node* otherListCurrent=otherList.Head;//otherListCurrent指向第一个元素
while(otherListCurrent!=NULL)//拷贝的目标不为空
{
for (int i=1;i<=otherList.len;i++)
{
Node* NewNode = new Node;
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& LinkList::operator=(const LinkList&otherList)//赋值函数
{
Node* current;//current总是指向要插的位置的前一结点
Node* otherListCurrent=otherList.Head;//otherListCurrent指向第一个元素
if (this!=&otherList)//避免自己给自己赋值
{
if (Head!=NULL)
{
destoryList();//自己有结点,先销毁
}
if(otherListCurrent!=NULL)
{
bool first = true;
while(otherListCurrent!=NULL)
{
Node* newNode = new Node;
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::~LinkList()
{
destoryList();
}
template<class Type>
void LinkList::createListForward()//头插法
{
Node* newNode;
cout<<"输入链表长度:"<cin>>len;
for (int i=1;i<=len;i++)
{
newNode = new Node;
cout<<"输入元素:"<cin>>newNode->data;
newNode->next=Head;
Head = newNode; //每插入一个结点,都是要把它放在第一个结点的位置
}
}
template<class Type>
void LinkList::createBackward()//尾插法
{
Node* newNode;
Node* current;//总是指向最后一个节点
cout<<"输入链表长度:"<cin>>len;
for (int i=1;i<=len;i++)
{
newNode = new Node;
cout<<"输入元素:"<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::initList() //所有结点都销毁
{
destoryList();
len=0;
Head=NULL;
}
template<class Type>
bool LinkList::isEmptyList()
{
if (Head==NULL)
{
return true;
}
else
{
return false;
}
}
template<class Type>
int LinkList::length()
{
return len;
}
template<class Type>
void LinkList::destoryList()//销毁包括头结点
{
Node* current;
while(Head!=NULL)
{
current = Head;
Head = current->next;
delete current;
}
Head=NULL;
len=0;
}
template<class Type>
void LinkList::getFirstData(Type& firstItem)
{
if (!isEmptyList())
{
firstItem = Head->data;
}
else
{
cout<<"链表为空!"<template<class Type>
void LinkList::getData(int pos,Type& newItem)
{
if (pos<1 || pos>len)
{
cout<<"位置不当!"<else
{
Node* current = Head;
for (int i=1;inext;
}
newItem = current->data;
}
}
template<class Type>
void LinkList::insertFirst(Type newItem)
{
Node *newNode = new Node;
newNode->data = newItem;
newNode->next = Head;
Head= newNode;
len++;
}
template<class Type>
void LinkList::insertLast(Type newItem)
{
Node* current = Head;
while(current!=NULL && current->next!=NULL)
{
current = current->next;
}
Node *newNode = new Node;
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::deleteFirst(Type& data)
{
if (!isEmptyList())
{
data = Head->data;
Node* temp = Head;
Head = Head->next;
delete temp;
}
else
{
cout<<"栈空!"<template<class Type>
void LinkList::deleteLast()
{
Node* current = Head;
if (isEmptyList())
{
cout<<"链表为空!"<else
{
for (int i=1;i1;i++)
{
current = current->next;
}
Node* nextCurrent = current->next;
current->next = nextCurrent->next;
delete nextCurrent;
}
len--;
}
template<class Type>
void LinkList::reverse()
{
Node* current = Head;
Head=NULL;
if (current==NULL)
{
cout<<"链表为空!"<else
{
while (current!=NULL)
{
Node* nextCurrent = current->next;
current->next = Head;
Head=current;
current = nextCurrent;
}
}
}
template<class Type>
ostream& operator<< <>(ostream& cout,const LinkList& list)
{
Node*current=list.Head; //有头结点,这是current指向第一个结点
if (current!=NULL)
{
while (current!=NULL)
{
cout<data<next;
}
}
else
{
cout<<"链表为空!"<return cout;
}