链表:存储结构的一种,包含两个部分,数据域和指针域,相对于顺序存储结构来说,插入和删除的算法时间复杂度只为O(1).
定义:
//定义
typedef struct Node *LinkList; //linkList,指针指向每一个元素
typedef struct Node{ //每个元素的构成
ElemType data; //数据域
struct Node *next; //指针域
}Node;
注意:假设结点p表示一个结点A,那么p->next表示的下一个结点B,p->next也表示结点A的指针域,故,指针域存放的是指向下一个结点的指针。
以下为简单的C语言实现:
#include "stdio.h"
#include "string.h"
#include "ctype.h"
#include "stdlib.h"
#include "io.h"
#include "math.h"
#include "time.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /* 存储空间初始分配量 */
typedef int Status;
typedef int ElemType;
//定义
typedef struct Node *LinkList; //linkList,指针指向每一个元素
typedef struct Node{ //每个元素的构成
ElemType data; //数据域
struct Node *next; //指针域
}Node;
//初始化
Status InitList(LinkList *L){
*L = (LinkList)malloc(sizeof(Node)); //产生头结点,使得L指向分配到的头结点
if(!(*L)){
//如果分配失败
return ERROR;
}
(*L)->next = NULL;//指针域为空
return OK;
}
//获取第几个元素
Status GetElem(LinkList L,int i,ElemType *e)
{
int j;
LinkList p; /* 声明一结点p */
p = L->next; /* 让p指向链表L的第一个结点 */
j = 1; /* j为计数器 */
while (p && j<i) /* p不为空或者计数器j还没有等于i时,循环继续 */
{
p = p->next; /* 让p指向下一个结点 */
++j;
}
if ( !p || j>i )
return ERROR; /* 第i个元素不存在 */
*e = p->data; /* 取第i个元素的数据 */
printf("第%d元素为%d\n",i,*e);
return OK;
}
//判断是否为空
Status isEmptyList(LinkList L){
if(L->next){
return 1;
}else{
return 0;
}
}
//获取链表的长度
int ListLength(LinkList L){
int i=0;
LinkList p ;
p = L->next;
while(p){
i++;
p = p->next;
}
return i;
}
//遍历链表
Status ListVisit(LinkList L){
LinkList p = L->next;
printf("该链表的元素为:\n");
while(p){
printf("%d ",p->data);
p = p->next;
}
printf("\n");
return OK;
}
//创建表,两种方法,头插法和尾插法
//头插法,在每一个头的开始不段插入,例如我们插入0-9,那么输出的结果就是9-0
void CreateListHead(LinkList *L,int n){
LinkList p;
int i;
srand(time(0));
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL; //先建立一个带头结点的单链表
for(i=0;i<n;i++){
p = (LinkList)malloc(sizeof(Node)); //新结点
p->data = rand()%100+1; //随机生成100以内的数字
p->next = (*L)->next;
(*L)->next = p; //插入到头结点 ,即就是插入操作
}
}
//尾插法 ,最末尾元素后面插入,插入0-9 输出0-9
void CreateListTail(LinkList *L,int n){
LinkList p,r;
int i;
srand(time(0));
*L = (LinkList)malloc(sizeof(Node));
r = *L; //r指向链表
for(i=0;i<n;i++){
p = (Node *)malloc(sizeof(Node));
p->data = rand()%100+1;
r->next = p; /* 将表尾终端结点的指针指向新结点 */
r = p; //将r赋值为新节点,下次指向的时候也就是把r指向了最末尾的结点,那么r也就是最末尾的结点
}
r->next = NULL; //表示当前链表结束
}
//重置表,也就是一个个结点的释放
Status ListClear(LinkList *L){
LinkList p,q;
p = (*L)->next;
while(p){
q = p->next; //每一次指向然后释放
free(p);
p = q; // 释放后 重新赋给其原来的q结点的位置
}
(*L)->next = NULL; //头结点指针域赋值为空
printf("清空完成\n");
return OK;
}
//查找表中元素
int LocateEle(LinkList L,ElemType e){
int i=0;
LinkList p;
p = L->next; //指向链表,也就会指向头结点
while(p){
i++;
if(p->data == e){
printf("元素%d在第%d个位置\n",e,i);
return i;
}
p = p->next;
}
return 0;
}
//插入元素到表
Status ListInsert(LinkList *L,int i,ElemType e){
int j;
LinkList p,s; //创建两个结点p s
p = *L; //指向一个链表
j=1;
//查找到第i个结点
while( p &&j<i){
p = p->next;
++j;
}
if(!p || j>i){
return ERROR;
}
s = (LinkList)malloc(sizeof(Node)); //为新插入的分配一个结点
s->data = e;
s->next = p->next; //将原来p的后继结点赋给s的 后继
p->next = s; //将s赋给p的后继 ,注意以上两条语句的位置不能倒置
return OK;
}
//删除表中元素
Status ListDelete(LinkList *L,int i,ElemType *e){
int j;
LinkList p,q;
p = *L;
j=1;
while(p->next &&j<i){
p = p->next;
++j;
}
if(!(p->next) || j>i){
return ERROR;
}
q = p->next; //先将p的后继赋给一个我们设置为q的结点,这个结点就是我们要删除的
p->next = q->next; //将原来q的后继赋给p的后继
*e = q->data; //将要删除的元素的值赋给*e
printf("删除的元素为%d:\n",*e);
free(q); //记得free
return OK;
}
int main(){
LinkList L;
ElemType e;
Status i;
int j,k;
//初始化链表
i = InitList(&L);
printf("初始化完成后插入的链表为\n");
for(j=1;j<=5;j++){
ListInsert(&L,1,j);
}
ListVisit(L);
//插入单个元素
ListInsert(&L,2,100);
e = 100;
LocateEle(L,e);
ListVisit(L);
//删除元素
ListDelete(&L,2,&e);
ListVisit(L);
//获取第几个元素
GetElem(L,5,&e);
//清空重置
ListClear(&L);
ListVisit(L);
//头插法
CreateListHead(&L,10);
ListVisit(L);
//尾插法
CreateListTail(&L,10);
ListVisit(L);
return 0;
}