顺序表与链表的区别
顺序表可以随机存取表中任一个元素,但是插入和删除的时候需要移动大量的元素,这会使得算法的时间复杂度增加。而链式存储线性表时,不需要使用地址连续的存储单元,并不是逻辑上相邻的元素物理上也相邻,通过“链”连接元素之间的逻辑关系,不需要大量移动元素。
实现步骤
存储定义和函数声明
定义链表的结构体指针,数据域与指针域;函数的声明主要包括:链表的初始化(带头结点) 空表的判断、头插法建立单链表、头插结点增加链表结点个数、尾插结点增加链表结点个数、在第len个位置后面插入e的结点、链表的逆置等
/*
* @Author: 没有神的过往 2840562464@qq.com
* @Date: 2024-05-15 22:34:13
* @LastEditTime: 2024-05-17 22:41:31
* @FilePath: \code\C\LinkList\head.h
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#define ElemType int
#define Status int
using namespace std;
typedef struct LNode // 定义单链表结点类型
{
ElemType data; // 每一个结点存放一个数据元素
int length;
struct LNode *next; // 指针指向下一个结点
} LNode, *Linklist; // LNode *L (强调这是一个结点)与 Linklist L(强调这是一个单链表) 都是表明声明一个指向单链表第一个结点的指针;
bool InitList(Linklist &L); // 初始化单链表
bool EmptyList(Linklist &L); // 判断链表是否为空
Linklist HeadInsert(Linklist &L); // 头插法建立单链表
bool HeadInsert_node(Linklist &L, ElemType e); // 头插结点
bool EndInsert_node(Linklist &L, ElemType e); // 尾插结点
bool DeleteList(Linklist &L); // 链表的删除,即删除所有的结点;
bool IncreaseList(Linklist &L, int len, ElemType e); // 在第len个元素后面插入数值为e的结点
bool ChangeList(Linklist &L, int len, ElemType e); // 把第len个元素的值改为e
Linklist InvertedList(Linklist &L); // 链表的逆置
void printfList(Linklist &L); // 打印链表
void menu(); // 打印菜单;
定义操作函数
使用头插法建立单链表HeadInsert,然后主要功能有插入和逆置,具体代码看下面吧
bool InitList(Linklist &L)
{
L = (LNode *)malloc(sizeof(LNode)); // 分配一个头结点
if (L == NULL) // 如果为空表示分配失败
{
return false;
}
L->next = NULL;
return true;
}
bool DeleteList(Linklist &L)
{
LNode *p;
p = L;
while (L->next != NULL)
{
L = L->next;
p->next = L->next;
free(L);
L = p;
}
if (L->next == NULL)
{
printf("删除成功!");
printfList(L);
return true;
}
return false;
}
bool EmptyList(Linklist &L)
{
if (L->next == NULL)
{
return false;
}
return true;
}
bool IncreaseList(Linklist &L, int len, ElemType e)
{
if (len < 1) // 在第len个位置插入e,时间复杂度为O(n);
{
return false;
}
int number = 0; // 当前的p指向的是第几个结点
LNode *p = L;
while (p != NULL && number < len - 1)
{
p = p->next;
number++;
}
if (p == NULL)
{
return false;
}
LNode *s = (LNode *)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
L->length++;
return true;
}
Linklist HeadInsert(Linklist &L)
{
int value;
if (InitList(L))
{
printf("现在使用头插法建立单链表,请输入你要插入的数字,以9999结束:");
scanf("%d", &value);
while (value != 9999) // 头插法建立单链表,数值以9999结束;
{
LNode *p;
p = (LNode *)malloc(sizeof(LNode));
p->data = value;
p->next = L->next;
L->next = p;
L->length++;
scanf("%d", &value);
}
return L;
}
}
bool HeadInsert_node(Linklist &L, ElemType e)
{
LNode *p;
p = (LNode *)malloc(sizeof(LNode));
p->data = e;
p->next = L->next;
L->next = p;
L->length++;
return true;
}
bool EndInsert_node(Linklist &L, ElemType e)
{
LNode *p;
LNode *s = L;
p = (LNode *)malloc(sizeof(LNode));
p->data = e;
if (EmptyList(L))
{
while (s->next != NULL)
{
s = s->next;
}
p->next = s->next;
s->next = p;
L->length++;
return true;
}
return false;
}
bool ChangeList(Linklist &L, int len, ElemType e)
{
LNode *p = L;
int number = 0;
if (len < 1)
{
printf("输入的数据不合法!");
return false;
}
while (p->next != NULL && number < len)
{
p = p->next;
number++;
}
p->data = e;
printfList(L);
return true;
}
Linklist InvertedList(Linklist &L)
{
LNode *temp = NULL, *PHead = NULL;
if (L->next == NULL || L->next->next == NULL)
{
return L;
}
Linklist p = L->next;
while (p != NULL)
{
temp = p;
p = p->next;
temp->next = PHead;
PHead = temp;
}
L->next = PHead;
return L;
}
void printfList(Linklist &L)
{
LNode *p = L;
printf("链表的顺序为:");
while (p->next != NULL)
{
p = p->next;
printf("%d->", p->data);
}
if (p->next == NULL)
{
printf("链表的长度是%d", L->length);
}
printf("\n");
}
定义菜单
定义菜单之后,可以更方便的对链表进行基本操作,而且也会使代码更简洁,美观。
void menu()
{
printf("****************菜 单*******************\n");
printf("1.头插法创建链表 2.在位置后面插值\n");
printf("3.链表数据的修改 4.链表的逆置 \n");
printf("5.头插元素 6.尾插元素 \n");
printf("7.打印链表 \n");
printf("******************************************\n");
}
完整代码
上面的头文件和下面这段代码,添加到一个工程中就可以运行啦!
/*
* @Author: 没有神的过往 2840562464@qq.com
* @Date: 2024-05-16 13:14:35
* @LastEditTime: 2024-05-17 22:10:09
* @FilePath: \code\C\LinkList\main.cpp
*/
#include "head.h"
int main()
{
Linklist L;
int chance = 0;
int len = 0;
ElemType e;
do
{
menu();
printf("请输入你的选择:");
scanf("%d", &chance);
switch (chance)
{
case 1:
HeadInsert(L);
printfList(L);
break;
case 2:
printf("请输入你要插入的位置和元素:");
scanf("%d %d", &len, &e);
IncreaseList(L, len, e);
printfList(L);
break;
case 3:
printf("请输入你要修改的位置和元素:");
scanf("%d%d", &len, &e);
ChangeList(L, len, e);
break;
case 4:
Linklist p = InvertedList(L);
printfList(p);
break;
case 5:
printf("请输入你要头插的元素:");
scanf("%d", &e);
HeadInsert_node(L, e);
printfList(L);
break;
case 6:
printf("请输入你要尾插的元素:");
scanf("%d", &e);
EndInsert_node(L, e);
printfList(L);
break;
// default:
// break;
}
} while (chance >= 1 && chance <= 7);
getchar();
return 0;
}
void menu()
{
printf("****************菜 单*******************\n");
printf("1.头插法创建链表 2.在位置后面插值\n");
printf("3.链表数据的修改 4.链表的逆置 \n");
printf("5.头插元素 6.尾插元素 \n");
printf("7.打印链表 \n");
printf("******************************************\n");
}
bool InitList(Linklist &L)
{
L = (LNode *)malloc(sizeof(LNode)); // 分配一个头结点
if (L == NULL) // 如果为空表示分配失败
{
return false;
}
L->next = NULL;
return true;
}
bool DeleteList(Linklist &L)
{
LNode *p;
p = L;
while (L->next != NULL)
{
L = L->next;
p->next = L->next;
free(L);
L = p;
}
if (L->next == NULL)
{
printf("删除成功!");
printfList(L);
return true;
}
return false;
}
bool EmptyList(Linklist &L)
{
if (L->next == NULL)
{
return false;
}
return true;
}
bool IncreaseList(Linklist &L, int len, ElemType e)
{
if (len < 1) // 在第len个位置插入e,时间复杂度为O(n);
{
return false;
}
int number = 0; // 当前的p指向的是第几个结点
LNode *p = L;
while (p != NULL && number < len - 1)
{
p = p->next;
number++;
}
if (p == NULL)
{
return false;
}
LNode *s = (LNode *)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
L->length++;
return true;
}
Linklist HeadInsert(Linklist &L)
{
int value;
if (InitList(L))
{
printf("现在使用头插法建立单链表,请输入你要插入的数字,以9999结束:");
scanf("%d", &value);
while (value != 9999) // 头插法建立单链表,数值以9999结束;
{
LNode *p;
p = (LNode *)malloc(sizeof(LNode));
p->data = value;
p->next = L->next;
L->next = p;
L->length++;
scanf("%d", &value);
}
return L;
}
}
bool HeadInsert_node(Linklist &L, ElemType e)
{
LNode *p;
p = (LNode *)malloc(sizeof(LNode));
p->data = e;
p->next = L->next;
L->next = p;
L->length++;
return true;
}
bool EndInsert_node(Linklist &L, ElemType e)
{
LNode *p;
LNode *s = L;
p = (LNode *)malloc(sizeof(LNode));
p->data = e;
if (EmptyList(L))
{
while (s->next != NULL)
{
s = s->next;
}
p->next = s->next;
s->next = p;
L->length++;
return true;
}
return false;
}
bool ChangeList(Linklist &L, int len, ElemType e)
{
LNode *p = L;
int number = 0;
if (len < 1)
{
printf("输入的数据不合法!");
return false;
}
while (p->next != NULL && number < len)
{
p = p->next;
number++;
}
p->data = e;
printfList(L);
return true;
}
Linklist InvertedList(Linklist &L)
{
LNode *temp = NULL, *PHead = NULL;
if (L->next == NULL || L->next->next == NULL)
{
return L;
}
Linklist p = L->next;
while (p != NULL)
{
temp = p;
p = p->next;
temp->next = PHead;
PHead = temp;
}
L->next = PHead;
return L;
}
void printfList(Linklist &L)
{
LNode *p = L;
printf("链表的顺序为:");
while (p->next != NULL)
{
p = p->next;
printf("%d->", p->data);
}
if (p->next == NULL)
{
printf("链表的长度是%d", L->length);
}
printf("\n");
}
运行结果
运行结果如下: