1. 线性单链表
1.1 抽象定义
-
类型名
链表。
- 类型属性
存储一些列项,运行时确定大小,支持元素的快速插入和删除。
- 类型操作
读取任意节点元素;
在任意节点位置插入元素;
删除已有节点元素;
清空整个链表。
1.2 代码实现
1.2.1 接口定义
如下,接口定义在linklist.h文件中:
//文件名:Linklist.h
//主要作用:定义链表的数据接口
#ifndef _LINKLIST_H_
#define _LINKLIST_H_
#include <stdbool.h>
#define OK true
#define ERROR false
typedef int ElemType ; //定义数据类型
typedef struct Node{ //定义链表节点
ElemType data;
struct Node* next;
}Node;
typedef struct Node* LinkList;//定义表头节点
bool GetElem(LinkList L, int i, ElemType* e); //用e返回链表中第i个结点的元素值
bool ListInsert(LinkList* L, int i, ElemType* e); //在链表第i个位置之前插入e
bool ListDelete(LinkList* L, int i, ElemType* e); //删除链表的第i个结点,用e返回其值
LinkList CreatListhead(); //创建链表头结点;
bool ListDestory(LinkList* L); //删除整个链表
void ListPrint(LinkList* L); //打印输出整个链表的所有元素
#endif
1.2.2 接口实现
如下,接口实现在linklist.c文件中:
//文件名:linklist.c
//主要作用:链表接口的实现
#include "linklist.h"
#include <stdlib.h>
#include <stdio.h>
//#define OK true
//#define ERROR false
//typedef int ElemType ; //定义数据类型
//
//typedef struct Node{ //定义链表节点
// ElemType data;
// struct Node* next;
//}Node;
//
//typedef struct Node* LinkList;//定义表头节点
//用e返回链表中第i个结点的元素值
bool GetElem(LinkList L, int i, ElemType* e){
if(i<1)return ERROR;
int j=1;
LinkList p;
p=L->next;
for(;j<i;j++){ //寻找第i个节点
p=p->next;
if(!p)return ERROR; //超出链表范围,return ERROR
}
*e=p->data; //输出第i个节点
return OK;
}
//在链表第i个位置之前插入e,1<=i<=Length(L)
bool ListInsert(LinkList* L, int i, ElemType* e){
int j=1;
LinkList p;
p=*L;
for(;j<i;j++){ //寻找第i-1个节点
p=p->next;
if(!p)return ERROR;
}
LinkList tmp=(LinkList)malloc(sizeof(Node));
tmp->data=*e;
tmp->next=p->next;
p->next=tmp;
return OK;
}
//删除链表的第i个结点,用e返回其值
bool ListDelete(LinkList* L, int i, ElemType* e){
int j=1;
LinkList p;
p=(*L);
for(;j<i;j++){ //寻找第i-1个节点
p=p->next;
if(!p)return ERROR;
}
LinkList tmp=p->next; //tmp存放第i个节点
*e=tmp->data; //*e存放第i个节点的值
p->next=tmp->next; //第i-1个节点指向第i+1个节点
free(tmp); //释放第i个节点
return OK;
}
//创建链表头结点
LinkList CreatListhead(){
LinkList head=(LinkList)malloc(sizeof(Node));
head->next=NULL;
return head;
}
//删除整个链表,将L置为空表
bool ListDestory(LinkList* L){
LinkList tmp=(*L)->next;
LinkList p;
while(tmp){
p=tmp;
tmp=tmp->next;
free(p);
}
(*L)->next=NULL;
return OK;
}
//打印输出整个链表的所有元素
void ListPrint(LinkList* L){
LinkList tmp=(*L)->next;
int i=0;
if(!tmp){
printf("The List is empty!\n");
return;
}
while(tmp){
printf("%-5d",tmp->data);
tmp=tmp->next;
}
printf("\n");
}
1.2.3 主函数调用
注释比较详细,生成随机数矩阵,并将这些元素添加到链表中,测试打印、插入链表节点元素、获得链表节点元素,删除链表等操作。
#include <stdio.h>
#include <stdlib.h>
#include "linklist.h"
#include <time.h>
#define MAXLEN 10
#define MAX 1000
#define MIN 0
int* generateArray(int num);
void displayArray(int* arr,int num);
int main(int argc, char *argv[]) {
LinkList List=CreatListhead(); //调用 CreatListhead创建头结点
int* array=generateArray(MAXLEN); //生成随机数数组
displayArray(array,MAXLEN);
int i=0;
for(;i<MAXLEN;i++){ //利用生成的随机数数组,调用ListInsert函数,构造单链表
ListInsert(&List,1,&array[i]);
}
ListPrint(&List); //打印构造出的单链表
//删除头元素,连续5次
for(i=0;i<MAXLEN/2;i++){ //测试 ListDelete函数,打印输出
int tmp;
ListDelete(&List,1,&tmp);
printf("%-5d",tmp);
}
printf("\n");
int tmp;
while(GetElem(List,i--,&tmp)){ //测试 GetElem函数,打印输出
printf("%-5d",tmp);
}
ListDestory(&List); //最后不忘销毁整个链表,释放malloc分配的内存空间
printf("\n");
return 0;
}
//生成MAX和MIN范围内的包含num个元素的数组
int* generateArray(int num){
srand((unsigned)time(NULL));
int* arr=(int*)malloc(sizeof(int)*num);
for(int i=0;i<num;i++)
arr[i]=((MAX-MIN+1)*rand()/(RAND_MAX+1.0)+MIN);
return arr;
}
//打印数组中元素
void displayArray(int* arr,int num){
for(int i=0;i<num;i++)
printf("%-5d",arr[i]);
printf("\n");
}