一、单链表的结构特征
1、采用指针链接一些列的存储单元来存储数据
2、动态分配存储空间
3、插入或删除元素效率高
4、查找元素效率低下
单链表常见结构:
2、文件组织方式
3、linkList.h单链表函数声明文件
#ifndef _YE_LELE_01
#define _YE_LELE_01
typedef int ElemType;
typedef int Status;
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode, *LinkList;
//初始化一个线性的链表结构
Status Init_L(LinkList &L);
//销毁链表
Status Destory_L(LinkList &L);
//重置链表
Status ClearList_L(LinkList &L);
//判断链表中是否为空
Status Is_Emtpy(LinkList L);
//获取链表中元素的个数
Status L_Length(LinkList L);
//从链表中获取一个元素的值返回给元素e
Status GetElem_L(LinkList L, int i, ElemType &e);
//找到链表中的元素与指定元素匹配的位置
Status LocalElem_L(LinkList L, int e, ElemType(*compare)(ElemType, ElemType));
//插入一个元素到链表中指定的位置
Status ListInsert_L(LinkList &L, int i, ElemType e);
//从链表中删除指定的元素,并且将该元素的值返回给e
Status ListDelete_L(LinkList &L, int i, ElemType &e);
//遍历链表中的元素
Status ListTraverse_L(LinkList L);
//逆位序创建线性链表,创建的链表长度为n
void CreateList_F(LinkList &L, int n);
//顺序创建线性链表,创建的链表长度为n
void CreateList_B(LinkList &L, int n);
//对链表中的元素进行排序
void InserSortList(LinkList &L);
//合并两个链表
void MergeList_L(LinkList &La, LinkList &Lb, LinkList &Lc);
#endif
4、linkList.cpp单链表函数实现文件
#include<stdio.h>
#include<stdlib.h>
//排除VS2015当中的警告错误
#pragma warning (disable:4996)
#define ERROR -2
#define OVERFLOW -3
#define OK 1
#define TRUE 1
#define FALSE 0
typedef int ElemType;
typedef int Status;
//定义单链表的节点
typedef struct LNode
{
ElemType data; //数据元素
struct LNode *next;//指向下一个节点的指针
}LNode, *LinkList; //LinkList才作为表的节点,LNode表示节点的别名(表示节点类型)
Status Init_L(LinkList &L)
{
L = (LinkList)malloc(sizeof(LNode));
if (!L)
{
exit(OVERFLOW);//如果节点申请内存失败,程序溢出
}
L->next = NULL;//创建一个头结点
return OK;
}
Status Destory_L(LinkList &L)
{
if (!L)
{
exit(ERROR);//链表不存在的时候返回错误
}
free(L);//直接释放链表的头指针
return OK;
}
Status ClearList_L(LinkList &L)
{
if (!L)
{
exit(ERROR);//链表不存在的时候返回错误
}
free(L->next);//将链表的头结点以后的内容全部清除
return OK;
}
Status Is_Emtpy(LinkList L)
{
if (!L)
{
exit(ERROR);//链表不存在的时候返回错误
}
if (L->next == NULL)//如果链表为空,返回真
{
return TRUE;
}
else//否则返回假
{
return FALSE;
}
}
Status L_Length(LinkList L)
{
LinkList p = L->next;
int count = 0;
if (!L)
{
exit(ERROR);//链表不存在的时候返回错误
}
while (p)
{
count++;
p = p->next;//此处不能写p++,p只是指向当前节点,不一定指向连续空间;
}
return count;
}
Status GetElem_L(LinkList L, int i, ElemType &e)
{
int j = 1;
LinkList p = L->next;
if (!L)
{
exit(ERROR);//链表不存在的时候返回错误
}
while (p&&j<i)
{
p = p->next;//p指针后移
j++;
}
if (!p || j>i)//表示该元素不存在
{
return ERROR;
}
e = p->data;
return OK;
}
Status ListInsert_L(LinkList &L, int i, ElemType e)
{
int j = 1;
LinkList p = L;//p指向链表的头结点
LinkList s;//新定义一个表节点
while (p&&j <= i - 1)//寻找第i-1个节点,也就是需要插入位置的前一个节点
{
p = p->next;
j++;
}
if (!p)//插入位置非法
{
return ERROR;
}
s = (LinkList)malloc(sizeof(LNode));//每一个节点都作为一个指针指向的对象
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
Status ListTraverse_L(LinkList L)
{
int j = 1;
LinkList p = L->next;
while (p)
{
printf("%d\n", p->data);
p = p->next;
}
return OK;
}
Status ListDelete_L(LinkList &L, int i, ElemType &e)
{
int j = 1;
LinkList p = L, q;
while (p&&j <= i - 1)//寻找第i-1个节点,也就是需要删除位置的前一个节点
{
p = p->next;
j++;
}
if (!p->next)//删除的位置不合理
{
return ERROR;
}
q = p->next;
e = q->data;//将删除的数据放入到e中
p->next = q->next;
free(q);//释放内存
return OK;
}
//在链表头插入节点
void CreateList_F(LinkList &L, int n)
{
int i;
LinkList p;
for (i = n; i >0; i--)
{
p = (LinkList)malloc(sizeof(LNode));
printf("输入链表中的节点数据:");
scanf("%d", &p->data);
p->next = L->next;
L->next = p;
}
}
//在链表尾部插入节点
void CreateList_B(LinkList &L, int n)
{
int i;
LinkList p = L;
while (p->next != NULL)//找到链表末尾
{
p = p->next;
}
for (i = n; i >0; i--)
{
LinkList p1 = (LinkList)malloc(sizeof(LNode));//新申请一个节点
p1->next = NULL;//给新节点的链接节点置空
printf("输入链表中的节点数据:");
scanf("%d", &p1->data);//为新节点赋值数据
p->next = p1;//链接节点
p = p->next;//节点后移
}
}
//L 里面的data没有存储元素
void InserSortList(LinkList &L)
{
LNode *p1, *p2, *temp, *prep1, *prep2;
//在只有一个头结点+一个元素节点的情况下,无需排序
if (L->next->next == NULL)
{
exit(0);
}
for (p1 = L->next->next, prep1 = L->next; p1 != NULL; p1 = p1->next, prep1 = prep1->next)
{
temp = p1; /*保存待插入节点*/
for (p2 = L->next, prep2 = L; p2 != p1; p2 = p2->next, prep2 = prep2->next)
{
if (p2->data > p1->data)
{
p1 = p1->next;
prep1->next = temp->next; /*删除待插入节点*/
prep2->next = temp; /*将其插入对应位置*/
}
}
temp->next = p2;
}
}
void MergeList_L(LinkList &La, LinkList &Lb, LinkList &Lc)
{
LNode *pa, *pb, *pc;
pa = La->next; pb = Lb->next;
Lc = pc = La;
while (pa&&pb)
{
if (pa->data<pb->data)
{
pc->next = pa; pc = pa; pa = pa->next;
}
else
{
pc->next = pb; pc = pb; pb = pb->next;
}
}
pc->next = pa ? pa : pb;
free(Lb);
}
5、主函数调用文件main.cpp
#include<stdio.h>
#include<stdlib.h>
#include"linkList.h"
ElemType e = 0;
LinkList L, La, Lb, Lc;
//通过插入元素创建链表
void init()
{
printf("***********线性表的链式操作实验***********\n");
printf("线性表的初始化插入操作\n");
Init_L(L);//调用初始化过程
Init_L(La);
Init_L(Lb);
Init_L(Lc);
printf("初始化完成\n");
}
void test1()
{
ListInsert_L(L, 1, 2);//插入元素2
ListInsert_L(L, 1, 3);//插入元素3
ListInsert_L(L, 2, 8);//插入元素8
ListInsert_L(L, 3, 6);//插入元素6
ListInsert_L(L, 4, -1);//插入元素-1
ListInsert_L(L, 5, 7);//插入元素7
ListTraverse_L(L);
}
//获取链表元素
void test2()
{
printf("线性表的获取元素操作\n");
GetElem_L(L, 2, e);
printf("%d\n", e);
}
//判断链表中是否为空
void test3()
{
printf("线性表判断链表中是否为空\n");
e = Is_Emtpy(L);
if (e)
{
printf("空\n");
}
else
{
printf("非空\n");
}
}
//链表中元素的个数
void test4()
{
printf("链表中元素的个数\n");
printf("%d\n", L_Length(L));
}
//获取一个元素
void test5()
{
printf("链表中获取一个元素的值返回给元素e\n");
GetElem_L(L, 5, e);
printf("%d\n", e);
}
//链表中删除指定的元素
void test6()
{
printf("链表中删除指定的元素\n");
ListDelete_L(L, 3, e);
ListTraverse_L(L);
}
//逆位序创建线性链表
void test7()
{
printf("逆位序创建线性链表\n");
CreateList_F(La, 3);
ListTraverse_L(La);
CreateList_F(Lb, 3);
ListTraverse_L(Lb);
}
//链表合并
void test8()
{
MergeList_L(La, Lb, Lc);
ListTraverse_L(Lc);
}
void test9()
{
printf("顺序创建线性链表\n");
CreateList_B(La, 3);
ListTraverse_L(La);
CreateList_B(Lb, 3);
ListTraverse_L(Lb);
}
int main()
{
init();
//test7();
test9();
test8();
return 0;
}