重要操作:
p=L;//p指向头结点
p=L->next;//p指向首元结点
p=p->next;//p指向下一个结点
插入操作示意图:插入操作的关键是i-1
删除操作:删除操作的关键是 i-1 和 i+1
尾插法:
1.生成头结点
2.头结点指针域置空
3.尾指针r指向头结点
进入循环:
4.生成新结点,p指向新结点
5.输入p的数据
6.p的指针域置空,r的指针域指向p
7.r指向新的尾结点p(此时r成为了p结点)
具体代码如下:
#include <iostream>
using namespace std;
#include <stdlib.h>
#define OK 1
#define ERROR -1
typedef int Status;
typedef int Elemtype;
typedef struct LNode{//结点的两个属性
Elemtype data;//数据域
struct LNode *next; //指向下一个结点的指针(指针变量名叫next) //嵌套定义—因为next指针指向的下一个结点还是有这两个属性,所以用嵌套定义
}LNode,*LinkList;//将结构体类型struct LNode重命名为LNode//将struct LNode *重命名为LinkList
int length=0;//为了方便后面判断元素在表长的什么位置
//初始化链表
Status InitList(LinkList &L){//要改变表的都要用&
L=new LNode; //生成新结点(开辟一个空间)作为头结点,用 头指针L 指向头结点
L->next=NULL; //头结点的指针域置空(next是结构体指针L的属性,C++用L.next表示)
return OK;
}
//前插法
void CreateList_former(LinkList &L,int n){
cout<<"请输入"<<n<<"个"<<"元素到链表中:"<<endl;
L=new LNode;//先生成头结点
L->next=NULL;//头结点的指针域置空
for(int i=0;i<n;i++){
LinkList p=new LNode;//生成新结点p
cin>>p->data;//输入元素值赋给新结点p的数据域
p->next=L->next; L->next=p; //将新结点插入头结点之后
length++; //方便判断表长
}
}
//后插法
void CreateList_latter(LinkList &L,int n){
cout<<"请输入"<<n<<"个"<<"元素到链表中:"<<endl;
L=new LNode;//先生成头结点
L->next=NULL;//头结点的指针域置空
LinkList r=L;//定义一个尾指针r指向头结点
for(int i=0;i<n;i++){
LinkList p=new LNode;//生成新结点
cin>>p->data;
p->next=NULL; r->next=p;//将新结点*p插入尾结点*r之后
r=p;//r指向新的尾结点*p
length++; //方便判断表长
}
}
//插入
Status ListInsert(LinkList &L,int i,Elemtype e){
cout<<"在第"<<i<<"个位置插入元素"<<e<<"后:"<<endl;
//查找操作
LinkList p=L; int j=0;//p指向头结点
while( p && (j<i-1) ){//j等于i-1时跳出循环 (画图好理解)
p=p->next; ++j;//查找第i-1个结点,p指向该结点
}
if(!p||j>i-1)return ERROR;//i大于表长+1或者小于1,插入位置非法
//插入操作
LinkList s=new LNode;//生成新结点
s->data=e;//将结点s的数据域置为e
s->next=p->next;//将p的指针域赋给s的指针域 //先后顺序不能反,否则s会指向自己
p->next=s;//结点p的指针域指向结点s
return OK;
}
//删除
Status ListDelete(LinkList &L,int i){
cout<<"删除第"<<i<<"个元素后:"<<endl;
//查找操作
LinkList p=L; int j=0;//p指向头结点
while( (p->next) && (j<i-1) ){//寻找第i个结点,此时p指向其前驱结点
p=p->next; ++j;
}
if( !(p->next) || (j>i-1) )return ERROR;
//赋值操作
LinkList q=p->next;//临时保存被删除结点的地址到指针q里以备释放
p->next=q->next;//改变删除结点 前驱结点的指针域(跳过删除的结点直接指向下一个)
delete q;//释放删除结点的空间
return OK;
}
//查找
Status SeekElem(LinkList L,Elemtype e){ //指针函数(LNode *) 返回的是地址
LinkList p=L->next;//初始化,p指向首元结点,即p变成首元结点
int cnt=1;
while(p&&p->data!=e){//当指针p不为空,且结点值与目标值不同时进入循环
cnt++;
p=p->next;//p指向下一个结点,即p变成下一个结点
}
if(cnt>length){
cout<<"该元素不在此表内"<<endl;
}
else
{cout<<e<<"在第"<<cnt<<"个位置"<<endl;}//查找成功返回e的结点地址,查找失败p为NULL
}
//取值
Status GetElem(LinkList L,int i,Elemtype &e){
//查找操作
LinkList p=L->next; int j=1;//p指向首元结点
while(p&&j<i){//当j=i时,跳出循环
p=p->next;//p指向下一个结点,即p变成下一个结点
++j;
}
if(!p||j>i) return ERROR;//如果 i<1 或 p指针指向的结点为空 跳出循环
//赋值操作
e=p->data;
cout<<"该表中第"<<i<<"个元素是"<<e<<endl;
return OK;
}
//输出
Status printList(LinkList &L){
if(L==NULL) return ERROR;
LinkList p=L;//L的地址赋值给p,指针p指向L(L此时为头结点)
p=p->next;//p现在为首元结点了
while(p){//不知道循环次数的用while
cout<<p->data<<" ";
p=p->next;//p指向下一个结点,即p变成下一个结点
}
cout<<endl;
}
//销毁:从头指针开始,依次释放所有结点
Status DestroyList(LinkList &L){
while(L){//循环条件为 L非空,即当前所指的结点不是空结点就反复执行
LinkList p=L;//将L的地址赋值给p,p就指向了头结点
L=L->next;//L指向下一个结点的地址,L变成了下一个结点
delete p;//删除p所指的结点
}
return OK;
}
/*
清空链表:依次释放所有结点,并将头结点指针域设置为空
(注意清空操作链表还存在,但链表中无元素,成为空链表(头指针和头结点还在),而销毁操作是清空所有内存)
*/
Status ClearList(LinkList &L){
LinkList p,q;
p=L->next;//p指向首元结点
while(p){//判断是否到表尾
q=p->next;
delete p;
p=q;
}
L->next=NULL;//头结点指针域为空
return OK;
}
//问:在单链表L的两个数据元素a和b间插入x,写出插入x的算法实现,并写程序进行验证
//假设链表L是:1 2 a b 3
Status test(LinkList&L,Elemtype a,Elemtype b,Elemtype x){
LinkList p = L;
p = p->next;//指针p指向下一个结点,即p变成下一个结点
while(p){
if(p->data == a) {
break;
}
else { p = p->next; };
}
LinkList q = p->next;//指针q指向p下一个结点,即q变成p的下一个结点
if(p==NULL || q==NULL) return ERROR;
else{
LinkList s= new LNode;//创建新结点,数据域为x
s->data = x;
s->next = p->next;
p->next = s;
}
return OK;
}
int main(){
LinkList L;//指向头结点的指针就代表了整个链表
InitList (L);
CreateList_former(L,5);
// CreateList_latter(L,6);
cout<<"链表元素依次是:";
printList(L);
//插入
ListInsert(L,1,99);
printList(L);
//删除
ListDelete(L,3);
printList(L);
//查找
SeekElem(L,2);
//销毁
DestroyList(L);
cout<<"销毁链表后:"<<endl;
printList(L);
return 0;
}