用任意储存空间存放线性表中的元素。储存空间可以是连续,也可以是非连续的。
节点:数据域,指针域。数据域:节点本身的信息。指针域:指向直接后继元素的地址。
节点的逻辑顺序和物理顺序不一定相同
链表:(线性表中的)数据元素按照逻辑顺序链接在一起。单链表(线性链表):指针域只有一个。
头结点:在首节点(第一个节点)之前的节点。(在第一个节点之前插入节点和删除第一个节点)
空链表:只带头结点的链表,头结点的指针域为NULL。
头指针:指向链表中第一个节点的指针,一般是链表的名字(具有标识作用)
注意:
1.节点的地址存放在其直接前驱节点的指针域中。
由于第一个节点没有直接前驱节点,所以用头节点的指针指向第一个节点。(头结点的数据域一般存放线性表的长度)
由于最后一个节点没有直接后继节点,所以将最后一个节点的指针域置为空NULL。
2.存取链表必须从头指针开始,头指针指向链表中的第一个节点,通过头结点可以访问链表中的每一个元素。
3.一般情况下,只关心链表中节点的逻辑顺序,并不关心它的实际存储位置。
4.节点的逻辑顺序和物理顺序不一定相同。
1.链表的定义:
#include <iostream>
#include <cstdlib>
//#include<bits/stdc++.h>
using namespace std;
#define MAXSIZE 100
//const int MAXSIZE=(100);
typedef struct node {
int data;
node *next;
}Listnode,*Linklist; //Listnode链表的节点类型 Linklist指向链表节点的指针类型
//Linklist l=Linknode *l; l指向单链表的指针类型
//Linklist类型head单链表的头指针
//Listnode *p指向某一节点的指针p
//p->data / (*p).data 数据域
//p->naxt / (*p).next 指针域
2.初始化链表:
//初始化链表
void Initlist(Linklisk &head) {
//为头结点开辟储存空间,并将头结点的指针域置为NULL
if(!(*head=new node)
//if(!(*head=(Linklist)malloc(sizeof(Listnode))))
//new不能追加储存空间,malloc可以
exit (-2);
(*head)->next=NULL;
}
3.链表的创建:创建链表有两种方法:头插法(倒序输入),尾插法(正序输入)
//创建链表有两种方法:头插法(倒序输入),尾插法(正序输入)
//创建链表(对p:头结点的直接后继:头插法;尾节点的直接后继:尾插法)
//头插法:
//建立头结点,头结点的next域置为NULL;
//建立新节点p,将头结点head的直接后继置为p
//情况例如:
//head-p3-p2-p1
//head-p4-p3-p2-p1
//head-p5-p4-p3-p2-p1
//新插入的数在头结点的后面,在前一个插入节点的前面
Linklist Create() {
int ch;
Linklist head,p;
head=new node;
head->next=NULL;
while((ch=getchar())!='\n') {
p=new node;
p->data=ch;
p->next=head->next;
head->next=p;
}
return head;
}
//尾插法
//建立头结点,并将头结点的next置为NULL
//建立新节点p,t,新节点t始终指向最后一个元素
//将节点t的直接后继指向p,最后t指向p
//情况例如:
//head-p1-p2-p3
//head-p1-p2-p3-p4
//head-p1-p2-p3-p4-p5
Linklist Create() {
int ch;
//Linklist head,p,t;
Linklist head=new node;
head->next=NULL;
Linklist t=head;
while((ch=getchar())!='\n') {
Linklist p=new node;
p->data=ch;
p->next=NULL;
t->next=p;
t=p;
}
return head;
}
4.判断链表是否为空
//判断链表是否为空
bool Isempty(Linklist head) {
//head->next==NULL 头指针的next域为NULL
if(head->next==NULL) return false;
else return true;
}
5.找出链表中第i个节点的元素
//找出链表中第i个节点的元素
Listnode *Geteleme(Linklisk head,int i) {
//判断i是否合法
//判断链表是否为空
if(i<1) exit (-2);
else if(head->next==NULL) exit (-2);
else {
Listnode *p=head->next;
int j=1;
while(p && j<i) {
p=p->next;
j++;
}
if(j==i) return p; //成功后返回对应节点的指针
else return NULL;
}
}
6.找出元素值为e的节点
//找出元素值为e的节点
Listnode *Locateelem(Linklist head,int e) {
//新建立的节点的数据域元素等于e
Listnode *p=head->next;
while(p) {
if(p->data==e) break;
else p=p->next;
}
return p; //成功后返回对应节点的指针
}<pre name="code" class="cpp">//删除链表中的第i个节点元素值e
int Deleteelem(Linklist head,int i,int e) {
//1.找到第i个节点的直接前驱节点pre
//2.新生成的节点p指向pre节点的直接后继节点p=pre->next,即第i个节点;
//3.将e的值赋值给p的数据域p->data;
//4.删除第i个节点,即pre->next=p->next;
Listnode *pre=head;
int j=0;
//pre->next->next就是判断是最后一个节点,pre=pre->next; p=pre->next->next;p指针指向的不是NULL指针域
while(pre->next && j<i-1 && pre->next->next) { //找到前驱节点
pre=pre->next;
j++;
}
Listnode *p=new Listnode;
if(!p) return 0;
else {
e=p->data;
//删除节点操作
p=pre->next;
pre->next=p->next;
//释放p指向的节点的空间
delete []p;
return 1;
}
}
7.找出元素值为e的节点的序号
//找出元素值为e的节点的序号
Listnode *Locatedpos(Linklist head,int e) {
//新建立的节点的数据域元素等于e
//判断链表是否为空
Listnode *p=head->next;
int j=1;
while(p) {
if(p->data==i) return i;
else {
p=p->next;
i++;
}
}
if(!p) exit (-2);
}
8.在第i个位置插入元素e
//在第i个位置插入元素e
int Insertelem(Linklist head,int i,int e) {
//储存e的节点为p,则要将p指向的节点插入到pre和pre->next之间
//语句为:p->next=pre->next;pre->next=p;
//算法思路:
//1.找到第i个节点的直接前驱节点,然后生成一个新节点p
//2.将e的值赋给p的数据域p->data
//3.将新节点p插入到原链表中
Listnode *pre=head;
int j=0;
while(pre->next && j<i-1) { //找到前驱节点
pre=pre->next;
j++;
}
Listnode *p=new Listnode;
if(!p) return 0;
else {
p->data=e;
//插入节点操作
p->next=pre->next;
pre->next=p;
return 1;
}
}
9.删除链表中的第i个节点元素值e
//删除链表中的第i个节点元素值e
int Deleteelem(Linklist head,int i,int e) {
//1.找到第i个节点的直接前驱节点pre
//2.新生成的节点p指向pre节点的直接后继节点p=pre->next,即第i个节点;
//3.将e的值赋值给p的数据域p->data;
//4.删除第i个节点,即pre->next=p->next;
Listnode *pre=head;
int j=0;
//pre->next->next就是判断是最后一个节点,pre=pre->next; p=pre->next->next;p指针指向的不是NULL指针域
while(pre->next && j<i-1 && pre->next->next) { //找到前驱节点
pre=pre->next;
j++;
}
Listnode *p=new Listnode;
if(!p) return 0;
else {
e=p->data;
//删除节点操作
p=pre->next;
pre->next=p->next;
//释放p指向的节点的空间
delete []p;
return 1;
}
}
10.链表的遍历
//链表的遍历
void Print(Linklist head) {
//输出p->data
Listnode *p=head->next;
while(p) {
cout<<p->data<<" ";
p=p->next;
}
cout<<endl;
}
11.求链表的长度
//求链表的长度
int Length(Linklist head) {
//单链表元素的个数
Listnode *p=head->next;
int i=0;
while(p) {
i++;
p=p->next;
}
return i;
}
12.销毁链表
//销毁链表
void Clean(Linklist head) {
//删除每一个元素,并释放节点空间
Listnode *p=head->next;
while(p) {
Listnode *q=p;
free(q);
p=p->next;
}
}
13.主函数
//主函数
int main () {
Linklist head;
Initlist(head);
head=Create();
Isempty(head);
Length(head);
Print(head);
Clean(head);
rteurn 0;
}