链表类型
单链表如图:
双链表如图:
循环链表如图:
链表定义
//单链表
struct LinkNode
{
int val;//节点上面存储的元素
LinkNode* next;//指向下一节点的指针
LinkNode(int x):val(x), next(NULL){}//重载构造函数
}
LinkNode* head=new LinkNode(5);//自定义构造函数初始化节点
LinkNode* head=new LinkNode();//使用默认函数初始化节点
head->val=5;
//双链表
struct DLinkNode
(
int val;
DLinkNode *next;//指向下一结点(后继结点)的指针
DLinkNode *prev;//指向上一结点(前驱结点)的指针
DLinkNode(int x):val(x),next(NULL),prev(NULL){}//重载构造函数
)
DLinkNode* dhead=new DLinkNode(5)//自定义构造函数初始化节点
常见的基本操作
1.插入和删除结点:
插入节点:该例子中将结点s插入到p后面(代码执行语句顺序不能颠倒)
s->next=p->next;
p->next=s;
删除节点:该例子中将p结点后面的q结点删除(语句顺序不能颠倒)
q=p->next;//q指向被删结点
p->next=q->next;
delete q;
实战:LeetCode203
2.建立单链表
头插法:(简单,但生成的列表是反序的)
void CreateListF(int a[],int n)
{
for(int i=0;i<n;i++)//循环建立数据结点
{
LinkNode* s=new LinkNode(a[i]);//创建数据结点s,其中a[i]=s->val
s->next=head->next;//将结点s插入到head结点好后面
head->next=s;
}
}
尾插法:
void CreateListR(int a[],int n)
{
LinkNode *s,*r;
r=head;//r始终指向尾结点,开始时指向头结点
for(int i=0;i<n;i++)
{
s=new LinkNode(a[i]);//创建数据结点s
r->next=s;
r=s;
}
r->next=NULL;
}
3.线性表基本运算在单链表中的实现
(1)返回序号为i的结点
//i=-1时返回头结点head
LinkNode* geti(int i)
{
if(i<-1)return NULL;
LinkNode *p=head;
int j=-1;//可以认为头结点序号为-1
while(j<i&&p!=NULL)//注意是while
{
j++;
p=p->next;
}
return p;
}
(2)单链表的初始化和销毁
CreateLinkList()//构造函数,构造一个空单链表
{
head=LinkNode();
}
~CreateLinkList()//析构函数,销毁单链表
{
LinkNode *prev,*p;
prev=head;
p=prev->next;
while(p!=NULL)
{
delete prev;
prev=p;
p=p->next;//prev,p同步后移一个结点
}
delete prev;//p为空时prev指向尾结点,此时释放尾结点
}
(3)将元素x的结点添加到单链表末尾
void Addx(int x)
{
LinkNode *s=new LinkNode(x);//新建结点s,其存放元素x(s->val==x),用来放在末尾
LinkNode *p=head;
while(p->next!=NULL)
{
p=p->next;
}
p->next=s;//在尾结点p的后面插入结点s
}
(4)求单链表的长度
int Getlength()
{
LinkNode *p=head;
int n=0;
while(p->next!=NULL)
{
n++;
p=p->next;
}
}
(5)求单链表中序号为i的结点值
bool GetElemi(int i,int& x)//采用引用的方式
{
if(i<0)return false;
LinkNode *p=geti(i);
if(p!=NULL)
{
x=p->val;
return true;
}
else
return false;
}
(6)给单链表中序号为i的结点赋值x
bool SetElemi(int i,int x)//不采用引用,和(5)区别
{
if(i<0)return false;
LinkNode *p=geti(i);
if(p!=NULL)
{
p->val=x;//与(5)的不同之处
return true;
}
else
return false;
}
(7)求单链表中第一个值为e的结点的序号
int GetNoi(int e)
{
int i=0;
LinkNode *p=head;
while(p!=NULL&&p->val!=e)//循环条件值得注意
{
p=p->next;
}
//处理跳出循环后的情况
if(p==NULL)
{
return -1;//一般默认头结点序号为-1
}
else
return i;
}
(8)在单链表中插入值为e的结点作为第i个结点
bool Insert(int i,int e)
{
if(i<0)return false;
LinkNode *p=geti(i-1);//需要先找到序号为i-1的结点,然后才能在后面建立新结点
if(p!=NULL)
{
LinKNode *s=new LinkNode(e);//建立新结点s,s->val==e
s->next=p->next;
p->next=s;//这两行代码顺序不可以交换
}
else
return false;
}
(9)在单链表中删除序号为i的结点
bool Delete(int i)
{
if(i<0)return false;
LinkNode *p=geti(i-1);
if(p!=NULL)
{
LinkNode *s=p->next;//被删结点s
if(s!=NULL)
{
p->next=s->next;//别漏掉
delete s;
return true;
}
else
return false;
}
else
return false;
}
(10)输出单链表中所有的结点值
void DisplayList
{
LinkNode *p=head->next;//易错:head->next才是序号为0的结点
while(p!=NULL)
{
cout<<p->val<<' ';
p=p->next;
}
cout<<endl;
}
4.线性表基本运算在双链表中的实现
(1)插入结点
//在p结点后面插入s
s->next=p->next;
if(p->next!=NULL)
{
p->next->prev=s;
}
s->prev=p;
p->next=s;
(2)删除结点
p->next->prev=p->prev;
p->prev->next=p->next;
(3)建立双链表
头插法:
void CreateListF(int a[],int n)
{
DLinkNode *p;
for(int i=0;i<n;i++)
{
p=new DLinkNode(a[i]);//创建数据结点p
p->next=dhead->next;
if(dhead->next!=NULL)
{
dhead->next->prev=s;
}
dhead->next=s;
s->prev=dhead;
}
}
尾插法:
void CreateListR(int a[],int n)
{
DLinkNode *p,*s;
s=dhead;//s始终指向尾结点,开始时指向头结点
for(int i=0;i<n;i++)
{
p=new DLinkNode(a[i]);
s->next=p;//将p结点插入到s的后面
p->prev=s;
s=p;//将s结点后移
}
p->next=NULL;//容易漏掉,这里要将尾结点的next域设置为NULL
}
(4)在双链表中序号为i的位置插入值为x的结点
bool Insert(int i,int x)
{
if(i<0)return false;//插入删除是i<0,查找geti是i<-1
DLinkNode *p=geti(i-1);
DLinkNode *s=new DLinkNode(x);//建立新结点s,s->val==x
if(p!=NULL)
{
s->next=p->next;
if(p->next!=NULL)
{
p->next->prev=s;
}
p->next=s;
s->prev=p;
return true;
}
else
return false;
}
(5)在双链表中删除序号为i的位置的结点
bool Delete(int i)
{
if(i<0)return false;
DLinkNode *p=geti(i);
if(p!=NULL)
{
p->prev->next=p->next;
if(p->next!=NULL)
{
p->next->prev=p->prev;
}
delete p;
return true;
}
else return false;
}
5.线性表基本运算在循环链表中的实现
(一)循环单链表
class CLinkList
{
public:
LinkNode *head;
CLinkList()
{
head=new LinkNode();
head->next=head;//构成循环的空链表
}
~CLinkList()
{
LinkNode *prev,*p;
prev=head;p=prev->next;
while(p!=head)//用p遍历结点并释放其前驱结点
{
delete prev;
prev=p;p=p->next;//prev,p同步后移一个结点
}
delete prev;//p==head时prev指向尾结点,此时释放尾结点
}
}
(二)循环双链表
class CDLinkList()
{
public:
DLinkNode *dhead;
CDLinkList()
{
dhead=new DLinkNode();
dhead->next=dhead;//构成循环的空链表
dhead->prev=dhead;//多一行这个
}
~CDLinkList()
{
DLinkNode *prev,*p;
prev=dhead;p=prev->next;
while(p!=dhead)//用p遍历结点并释放其前驱结点
{
delete prev;
prev=p;p=p->next;//prev,p同步后移一个结点
}
delete prev;//p==head时prev指向尾结点,此时释放尾结点
}
}