- 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
- 使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。链表可以在多种编程语言中实现。像Lisp和Scheme这样的语言的内建数据类型中就包含了链表的存取和操作。程序语言或面向对象语言,如C,C++和Java依靠易变工具来生成链表。
链表的特点
1> 链表的插入和删除O(1),修改和查找O(n)
2> 方便插入和删除,因为不需要移动大量元素
3> 链表不存在满的情况,适用于与存储数据量较大的情况。
4> 链表适用于元素个数变化较大的情况
5> 链表属于动态申请空
6> 链表不需要提前预估存储空间
7> 链表存储密度小于等于1
8> 链表的存储结构:链式存储【逻辑相邻,物理不一定相邻】
head.h
#ifndef __DD_H__
#define __DD_H__
#include <stdio.h>
#include <stdlib.h>
typedef int datedef;
typedef struct
{
char name[20];
int age;
int score;
} student;
typedef struct Node
{
union // 数据域
{
int len; // 头结点的数据域 (链表长度)
datedef date; // 其他结点的数据域
};
struct Node *next; // 指针域
} *linklist, Linklist;
linklist creat(int flag); // 创建新链表
int indel(linklist L, linklist p); // p后删除 (中删)
int insert(linklist L, linklist p, datedef e); // p后插入 (中插)
void output(linklist L); // 遍历
int h_insert(linklist L, datedef s); // 头插
int h_del(linklist L); // 头删
int r_insert(linklist L, datedef e); // 尾插
int r_del(linklist L); // 尾删
int p_find(linklist L, int n); // 查看位置元素
int p_update(linklist L, int n, datedef e); // 修改位置元素
int p_insert(linklist L, int n, datedef e); // 按位置插入
int p_del(linklist L, int n); // 按位置删除
int e_search(linklist L, datedef e); // 查找元素位置
int e_del(linklist L, datedef e); // 删除e值元素
int e_update(linklist L, datedef e, datedef s); // 修改e值元素
int e_insert(linklist L, datedef e, datedef s); // 给定元素前插入
void rev(linklist L); // 逆置
void bubble(linklist L); // 排序
#endif
fun.c
#include "head.h"
linklist creat(int flag) // 创建链表新结点
{
linklist L = (linklist)malloc(sizeof(Linklist));
if (L == NULL)
{
return NULL;
}
if (flag == 1) // 头结点
{
L->len = 0;
}
else if (flag == 0) // 其他结点
{
L->date = 0;
}
L->next = NULL; // 初始化
return L;
}
int insert(linklist L, linklist p, datedef e) // p后插入 (中插)
{
linklist s = creat(0);
s->date = e;
s->next = p->next;
p->next = s;
L->len++;
return 0;
}
int indel(linklist L, linklist p) // p后删除 (中删)
{
linklist q = p->next;
p->next = q->next;
L->len--;
free(q);
q = NULL;
return 0;
}
int h_insert(linklist L, datedef s) // 头插
{
if (L == NULL)
{
printf("头插失败\n");
return -1;
}
linklist q = creat(0);
if (q == NULL)
{
return -1;
}
q->date = s;
q->next = L->next;
L->next = q;
L->len++;
return 0;
}
void output(linklist L) // 遍历
{
if (L->next == NULL || L == NULL)
{
printf("遍历失败\n");
}
printf("输出的元素是:\n");
linklist p = L;
while (p->next)
{
p = p->next;
printf("%d\t", p->date);
}
puts("");
printf("该链表有%d个元素。\n", L->len);
}
/*
*for(int i=0;i<p->len;i++)
*{
*p=p->next;
*printf("%d\t",p->date);
*}
*puts("");
*/
int r_insert(linklist L, datedef e) // 尾插
{
if (L == NULL)
{
printf("链表不存在\n");
return -1;
}
linklist p = creat(0);
p = L;
while (p->next)
{
p = p->next;
}
linklist s = creat(0);
s->date = e;
p->next = s;
L->len++;
}
int r_del(linklist L) // 尾删
{
if (L == NULL || L->next == NULL)
{
printf("操作失败\n");
return -1;
}
linklist p = L;
while (p->next->next)
{
p = p->next;
}
linklist s = p->next->next;
p->next = NULL;
free(s);
s = NULL;
L->len--;
}
int h_del(linklist L) // 头删
{
if (L->next == NULL || L == NULL)
{
printf("删除失败\n");
return -1;
}
linklist p = L->next;
L->next = p->next;
L->len--;
free(p);
p = NULL;
}
int p_find(linklist L, int n) // 查看位置元素
{
if (L == NULL || n < 1 || n > L->len)
{
printf("位置不合法\n");
return -1;
}
linklist p = L;
for (int i = 0; i < n; i++)
{
p = p->next;
}
printf("你要找的第%d个元素为:%d\n", n, p->date);
return 0;
}
int p_update(linklist L, int n, datedef e) // 修改
{
if (L == NULL || n < 1 || n > L->len)
{
printf("位置不合法\n");
return -1;
}
linklist p = L;
for (int i = 0; i < n; i++)
{
p = p->next;
}
p->date = e;
return 0;
}
int e_search(linklist L, datedef e) // 查找元素位置
{
if (L == NULL || L->next == NULL)
{
return -1;
}
linklist p = L;
int n = 1;
while (p->next != NULL)
{
p = p->next;
if (p->date == e)
{
return n;
}
n++;
}
if (n > L->len)
{
return -1;
}
}
int p_insert(linklist L, int n, datedef e) // 按位置插入
{
if (L == NULL || n < 1 || n > L->len)
{
printf("位置不合法\n");
return -1;
}
linklist p = L;
for (int i = 0; i < n - 1; i++) // 找到第n-1个元素
{
p = p->next;
}
insert(L, p, e); // p后插入 (中插)
return 0;
}
int p_del(linklist L, int n) // 按位置删除
{
if (L == NULL || n < 1 || n > L->len)
{
printf("位置不合法\n");
return -1;
}
if (L->next == NULL)
{
printf("该链表为空");
return -1;
}
linklist p = L;
for (int i = 0; i < n - 1; i++) // 找到第n-1个元素
{
p = p->next;
}
indel(L, p); //(中删)
return 0;
}
int e_del(linklist L, datedef e) // 删除e值元素
{
for (int i = 0; i < L->len; i++)
{
int n = e_search(L, e); // 查找元素位置
if (n == -1)
{
return -1;
}
p_del(L, n); // (中删)
}
}
int e_update(linklist L, datedef e, datedef s) // 修改e值元素
{
int n = e_search(L, e); // 查找元素位置
if (n == -1)
{
printf("该元素不存在\n");
return -1;
}
p_update(L, n, s); // 修改位置元素
}
int e_insert(linklist L, datedef e, datedef s) // 给定元素前插入
{
int n = e_search(L, e); // 查找元素位置
if (n == -1)
{
printf("该元素不存在\n");
return -1;
}
p_insert(L, n, s); // 按位置插入
}
void rev(linklist L) // 逆置
{
if (L == NULL || L->next == NULL)
{
return;
}
if (L->len == 1)
{
printf("只有一个元素,无需逆置\n");
return;
}
linklist p = L->next;
L->next = NULL;
while (p != NULL)
{
linklist t = p;
p = p->next;
t->next = L->next;
L->next = t;
}
}
void bubble(linklist L) // 排序
{
if (L == NULL || L->next == NULL)
{
return;
}
if (L->len == 1)
{
printf("只有一个元素,无需排序\n");
return;
}
for (int i = 1; i < L->len; i++)
{
linklist p = L;
int count = 0;
for (int j = 0; j < ((L->len) - i); j++)
{
if ((p->next->date) > (p->next->next->date))
{
linklist s = p->next;
p->next = s->next;
s->next = s->next->next;
p->next->next = s;
/*
datedef a=p->next->date;
p->next->date=p->next->next->date;
p->next->next->date=a;
*/
count++;
}
p = p->next;
}
if (count == 0)
break;
}
}
main.c
#include "head.h"
int main(int argc, const char *argv)
{
linklist L = creat(1);
int n;
datedef s, e;
/*
printf("你要头插的元素个数:");
scanf("%d",&n);
for(int i=0;i<n;i++)
{
printf("你要头插的元素是:");
scanf("%d",&s);
h_insert(L,s); //头插
}
output(L);
*/
printf("你要尾插的元素个数:");
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
printf("你要尾插的元素是:");
scanf("%d", &s);
r_insert(L, s); // 尾插
}
output(L);
// h_del(L); //头删
// output(L);
// r_del(L); //尾删
// output(L);
//
/*
printf("你要查看第几个元素");
scanf("%d",&n);
p_find(L,n); //查看位置元素
//
//
printf("你要修改第几个元素");
scanf("%d",&n);
printf("你要将该元素改为:");
scanf("%d",&e);
p_update(L,n,e); //修改位置元素
output(L);
*/
//
/*
printf("你要在哪个位置插入元素:");
scanf("%d",&n);
printf("你要插入的元素是:");
scanf("%d",&e);
p_update(L,n,e); //修改位置元素
output(L);
p_insert(L,n,e); //按位置插入
output(L);
*/
/*
printf("你要删除哪个位置的元素:");
scanf("%d",&n);
p_del(L,n); //按位置删除
output(L);
//
//
//
printf("你要查找的元素是:");
scanf("%d",&e);
n=e_search(L,e); //查找元素位置
printf("你要找的元素在第%d个\n",n);
//
//
printf("你要删除的元素是:");
scanf("%d",&e);
e_del(L,e); //删除e值元素
output(L);
//
//
printf("你要修改的元素是:");
scanf("%d",&e);
printf("你要将元素改为:");
scanf("%d",&s);
e_update(L,e,s); //修改e值元素
output(L);
*/
/*
printf("你要在哪个值前插入元素:");
scanf("%d",&e);
printf("你要插入的元素是:");
scanf("%d",&s);
e_insert(L,e,s); //给定元素前插入
output(L);
rev(L); //逆置
output(L);
*/
bubble(L); // 排序
output(L);
free(L);
L = NULL;
}