带头结点与不带头结点的单链表-LinkList
2017-05-04 21:10
274 查看
单链表有两种形式:带头结点的单链表和不带头结点的单链表。
关于单链表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
2.节点声明Node.h
3.单链表类的声明LinkList.h
4.单链表的实现LinkList.cpp
不带头结点
关于单链表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; }
相关文章推荐
- 编写算法函数linklist delallx(linklist head, int x),删除带头结点单链表head中所有值为x的结点。
- LinkList_withHeadNode(带头结点的单链表)
- 归并两个带头结点的递增单链表 结果为递减链表
- bo2-9.cpp 不带头结点的单链表(存储结构由c2-2.h定义)的部分基本操作(2个)
- 链表的创建,插入,删除,查询,合并,清空,销毁(带头结点)
- 双向循环链表的建立,插入,删除(不带头结点)
- 带头结点的单链表的12个基本操作
- 带头结点双循环链表
- 给一个不带头结点的单链表,写出将链表倒置的算法
- 不带头结点的单链表的常规操作
- 带头结点的单链表就地逆置
- 数据结构(四)——单链表 、带头结点的单链表、循环链表 及其实现
- 不带头结点的单链表的插入,删除,原地转置,判断空,清空,统计节点数目等操作
- 带头结点的单链表和不带头结点的单链表的倒数第K个节点
- C语言实现单链表节点的删除(带头结点)
- 带头结点和不带头结点的单链表的尾插法以及各种操作
- 不带头结点的单链表
- 数据结构——带头结点的单链表
- 数据结构:不带头结点的单链表
- 不带头结点的单链表——数据结构课堂作业