链式存储是最常用的动态存储方法。为了克服顺序表的缺点,可以采用链式方式存储线性表。通常将采用链式存储结构的线性表称为线性链表。
单链表:
链表是用一组任意的存储单元来存放线性表的结点,这组存储单元可以是连续的,也可以是不连续的,甚至是零散分布在内存的任何位置上。因此,链表中结点的逻辑顺序和物理顺序不一定相同。为了正确地表示结点间的逻辑关系,必须在存储线性表的每个数据元素值的同时,存储指示其后继结点的地址(或位置)信息,这两部分信息组成的存储映像称为结点(Node)。如下图所示。
结点包括两个域:数据域用来存储结点的值,指针域用来存储数据元素的直接后继的地址(或位置)。由于此线性表的每个结点只有一个next域,故称为单链表。
单链表的逻辑状态(H为头指针)
单链表的存储结构描述如下:
#include<bits/stdc++.h>
#define OK 1
#define ERROR 0
using namespace std;
typedef char ElemType;
typedef struct Node{
ElemType data;
struct Node* next;
}Node, *LinkList;
LinkList与Node*同为结构指针类型,这两种类型是等价的。通常习惯上用LinkList说明指针变量,强调它是某个单链表的头指针变量。用Node* 来定义指向单链表中结点的指针。
初始化单链表:
void InitList(LinkList *L){
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL;
}
建立单链表:
1.用头插法建立单链表:
void CreatFromHead(LinkList L){
Node *s;
char ch;
int flag = 1;
while(flag){/*flag初值为1,当输入"$"时,置flag为0,建表结束*/
ch = getchar();
getchar();
if(ch!='$'){
s = (Node*)malloc(sizeof(Node));/*建立新结点*/
s->data = ch;
s->next = L->next;/*将s结点插入表头*/
L->next = s;
}
else{
flag = 0;
}
}
}
2.用尾插法建立单链表:
void CreatFromTail(LinkList L){
Node *r, *s;
int flag = 1;
char ch;
r = L;/*r指针动态指向链表的当前表尾,以便于做尾插入,初值指向头结点*/
while(flag){
ch = getchar();
getchar();
if(ch!='$'){
s = (Node*)malloc(sizeof(Node));
s->data = ch;
r->next = s;
r = s;
}
else{
flag = 0;
r->next = NULL;/*最后一个结点的next域置空,表示链表的结束*/
}
}
}
查找:
1.按序号查找:
Node* Get(LinkList L, int i){
int j;
Node *p;
if(i <= 0)
return NULL;
p = L;
j = 0;/*从头开始扫描*/
while((p->next!=NULL) && (j < i)){
p = p->next;
j++;/*计数器*/
}
if(i == j)/*找到了第i个结点*/
return p;
else
return NULL;
}
2.按值查找:
在单链表L中查找值为key的结点
Node* Locate(LinkList L, ElemType key){
Node *p;
p = L->next;/*从表中第一个结点开始*/
while(p != NULL){
if(p->data != key)
p = p->next;
else/*找到key时退出*/
break;
}
return p;
}
求单链表的长度:
int ListLength(LinkList L){
Node *p;
p = L->next;
int len = 0;/*存放长度*/
while(p != NULL){
p = p->next;
len++;
}
return len;
}
单链表插入操作:
int InsList(LinkList L, int i, ElemType e){
Node *pre, *s;
int k = 0;
if(i <= 0)
return ERROR;
pre = L;
while(pre != NULL && k < i-1){
pre = pre->next;
k++;
}
if(pre == NULL){
cout<<"插入位置不合理"<<endl;
return ERROR;
}
s = (Node*)malloc(sizeof(Node));/*申请新结点*/
s->data = e;
s->next = pre->next;/*修改指针,完成插入操作*/
pre->next = s;
return OK;
}
单链表删除操作:
int DelList(LinkList L, int i, ElemType *e){
Node *pre, *r;
int k = 0;
pre = L;
while(pre->next != NULL && k < i-1){
pre = pre->next;
k++;
}
if(pre->next == NULL){
cout<<"删除结点的位置i不合理"<<endl;
return ERROR;
}
r = pre->next;
pre->next = r->next;/*修改指针,删除结点*/
*e = r->data;
free(r);/*释放被删除的结点所占的内存空间*/
return OK;
}