主要介绍了单链表的基本概念和相关操作,由于篇幅太长,本文只给出了C++版本的程序,下篇将给出完整的C语言版本的程序,这两个不同版本实现的功能完全相同。
目录
1.单链表的基本概念
(1)单链表:当链表中的每个结点只含有一个指针域时,称为单链表。
(2)头指针:如上图所示,链表中第一个结点的存储位置叫做头指针。
(3)头结点:头结点是放在第一个元素结点之前的结点,头结点不是链表中的必须元素,其数据域一般无意义,(有些情况下会存放链表的长度,或用作监视哨等),本文的头结点存放了链表的长度。有了头结点后,对在第一个元素结点前插入结点和删除第一个结点,其操作与对其它结点的操作统一了。
(4)首元结点:就是第一个元素的结点,它是头结点后边的第一个结点。
2.单链表的基本操作
(1)初始化:给链表添加一个头结点。
(2)逆置链表:将单链表所有元素逆置。
(3)链表遍历:打印出链表的长度,并按顺序打印所有元素。
(4)查找:获取指定位置的元素。
(5)元素插入:在指定位置插入元素。
(6)元素删除:删除指定位置的元素。
(7)删除链表:将链表删除。
(8)头插法创建链表:用头插法插入一系列元素,创建链表。
(9)尾插法创建链表:用尾插法插入一系列元素,创建链表。
这些操作中,链表逆置具有一定的难度,其基本的设计思想是:将以前的旧链表中的每个元素从旧链表中删除,并用头插法插入新的链表中。
3.单链表编程实现----C++
(1)类的头文件 linklist.h
#ifndef LIST_H
#define LIST_H
typedef int ElemType;
struct Node
{
ElemType data;
struct Node *next;
};
class List
{
public:
List();//链表,可以删除所有动态节点
~List();//删除全部节点
void traverseList();//遍历
bool ListInsert(int i,ElemType d);//在第i个节点位置插入元素d
void CreateListHead(int n);//头插法插入
void CreateListEnd(int n);//尾插法插入
void Reverse();//逆置单链表
bool ListDelete(int i,ElemType& e);//删除第i个元素
bool GetElem(int i,ElemType& e);//获取第i个节点位置的元素,并且返回给e
private:
Node *head;//存放头结点
};
#endif // LIST_H
(2)类的源文件linklist.cpp
#include "linklist.h"
#include<iostream>
using namespace std;
List::List()//初始化
{
head=new Node;
head->next=NULL;
head->data=0;//头指针的数据域也不要浪费:用来存放链表长度
}
List::~List()//删除
{
Node* del;
while (head->next!=NULL)
{
del=head;
head=head->next;
delete del;
}
delete head;
}
void List::traverseList()//遍历
{
Node *ph=head;
cout<<"链表总长度为:"<<head->data<<endl;
ph=ph->next;
for(;ph!=NULL;ph=ph->next)
cout<<ph->data<<" ";
cout<<endl;
}
void List::CreateListHead(int n)//头指针插入
//头插法:
//head->NULL;
//head->p1->NULL;
//head->p2->p1->NULL;
{
for(int i=0;i<n;i++)
{
Node* cur=new Node;
cur->data=i;
cur->next=head->next;
head->next=cur;
head->data++;
}
}
bool List::ListInsert(int i,ElemType d)
{
Node *p=head,*cur;
for(int j=1;j<i;j++)
{
p=p->next;
if(p==NULL)
return false;
}
cur=new Node;
cur->data=d;
cur->next=p->next;
p->next=cur;
head->data++;
return true;
}
void List::CreateListEnd(int n)//末尾插入
//尾插法:
//head->NULL;
//head->p1->NULL;
//head->p1->p2->NULL;
{
Node* cur,*end;
end=head;
for(int i=0;i<n;i++)
{
cur=new Node;
cur->data=i;
cur->next=end->next;
end->next=cur;
end=cur;
head->data++;
}
}
bool List::ListDelete(int i,ElemType& e)
{
Node *p=head,*cur;
for(int j=1;j<i;j++)
{
p=p->next;
if(p==NULL)
return false;
}
cur=p->next;//待删除节点
e=cur->data;
p->next=cur->next;//将待删除节点的后一个节点赋给其前一个节点
head->data--;
delete cur;
return true;
}
bool List::GetElem(int i,ElemType& e)
{
Node* p=head;
for(int j=0;j<i;j++)
{
p=p->next;
if(p==NULL)
return false;
}
e=p->data;
return true;
}
/*
*这个程序是原始版本的程序,这个程序的思路更加清晰,下面一个程序是改进的程序,代码更加简洁。
*/
/*
void List::Reverse()//翻转链表
{
Node* cur=head;//头插法
Node* newhead,*tmp;
//初始化新的头结点
newhead=head;
cur=cur->next;//旧链表的头结点被删除(赋给了新的头结点)
newhead->next=NULL;//注意这一句和上一句不能颠倒,不然cur无法向后移
while (cur)
{
tmp=cur;
cur=cur->next;//顺序删旧链表的元素
tmp->next=newhead->next;//被删掉的元素用头插法插入新的头结点
newhead->next=tmp;
}
head= newhead;//这一步是多余的,因为新头和旧头都是指向同一位置,其实newhead是一个多余变量,直接用head也是可以完成任务的。
}
*/
void List::Reverse()//翻转链表
{
Node* cur,* tmp;//头插法
//初始化新的头结点
cur=head;
cur=cur->next;//旧链表的头结点被删除(赋给了新的头结点)
head->next=NULL;//注意这一句和上一句不能颠倒,不然cur无法向后移
while (cur)
{
tmp=cur;
cur=cur->next;//顺序删旧链表的元素
tmp->next=head->next;//被删掉的元素用头插法插入新的头结点
head->next=tmp;
}
}
(3)主程序main.cpp
#include <iostream>
#include"linklist.h"
using namespace std;
int main()
{
List list;
bool success;
cout<<" 初始化"<<endl;
list.traverseList();
List list1;
list1.CreateListEnd(10);
cout<<endl<<endl<<" 尾插法新建单链表 "<<endl;
list1.traverseList();
List list2;
cout<<endl<<endl<<" 头插法新建单链表 "<<endl;
list2.CreateListHead(10);
list2.traverseList();
cout<<endl<<endl<<" 元素插入"<<endl;
list2.ListInsert(5,10);
list2.traverseList();
cout<<endl<<endl<<" 元素删除"<<endl;
ElemType a;
list2.ListDelete(5,a);
cout<<"被删除的元素为:"<<a<<" ";
list2.traverseList();
cout<<endl<<endl<<" 元素查找"<<endl;
list2.traverseList();
success=list2.GetElem(3,a);
if(!success)
cout<<"error"<<endl;
else
cout<<"被查找的元素为:"<<a<<endl;
cout<<endl<<endl<<" 逆置链表"<<endl;
cout<<"原链表"<<endl;
list2.traverseList();
list2.Reverse();
cout<<endl<<"逆置链表"<<endl;
list2.traverseList();
return 0;
}