单链表
单链表
1. 基本概念
将线性表\(L=(a_0,...a_{i-1},a_i,a_{i+1}...a_{n-1})\)中的各元素分布在存储器的不同存储块,称每个元素为节点,通过地址或指针建立元素之间的联系。节点数据结构定义如下:
typedef struct node
{
data_t data; // 节点的数据域
struct node *next; // 节点的后继指针
}listnode,*linklist;
节点的data域存放数据元素\(a_i\),而next域是一个指针,指向\(a_i\)的直接后继\(a_{i+1}\)所在的节点。
优缺点:
1.优点,链表的存储结构不需要联系的地址空间,节点的插入和删除不需要成片移动;
2.缺点,不支持随机存储,因为空间不连续;
2. 实现

linklist.h
typedef int data_t; // 节点数据类型
typedef struct node
{
data_t data; // 节点数据域
struct node * next; // 节点指针域
}listnode, * linklist;
linklist list_create(); // 创建链表,返回值为头结点指针
int list_empty(linklist H); // 判断链表是否为空,返回值 0非空表,-1空表
int list_tail_insert(linklist H, data_t value); // 链表尾部插入函数, 返回值 0插入成功,-1插入失败
int list_head_insert(linklist H, data_t value); // 链表头部插入函数, 返回值 0插入成功,-1插入失败
int list_show(linklist H); // 遍历链表,返回值 0遍历成功,-1遍历失败
int list_length(linklist H); // 获取链表长度,返回值 链表长度,-1则链表不存在
linklist list_get(linklist H, int pos); // 获取链表第pos个节点,返回值 链表第pos个节点地址,NULL则链表不存在
int list_insert(linklist H, int pos, data_t value); // 链表插入函数,返回值 0插入成功,-1插入失败
int list_delete(linklist H, int pos); // 链表删除函数,返回值 0删除成功,-1删除失败
void list_free(linklist *H); // 释放链表函数
int list_reverse(linklist H); // 链表反转函数,返回值 0反转成功,-1反转失败
linklist list_adjmax(linklist H,int *max); // 链表相邻最大值函数,返回值 链表头结点指针,NULL则链表不存在
linklist list_merge(linklist H1, linklist H2); // 链表合并函数(两个有序链表),返回值 合并后新链表头结点指针,NULL则链表不存在
linklist.c
#include "linklist.h"
#include <stdlib.h> // malloc()函数头文件
#include <stdio.h>
/**
* @name list_create()
* @brief 创建链表函数
* @param 无
* @retval 表地址
*/
linklist list_create()
{
linklist H;
// 1. 申请头结点内存
H = (linklist)malloc(sizeof(listnode));
if (H == NULL)
{
printf("malloc fail\n");
return H;
}
// 2. 赋初值
H->data = 0;
H->next = NULL;
return H;
}
/**
* @name int list_empty(linklist H)
* @brief 链表尾部插入函数
* @param H 表地址,value 插入的值
* @retval 0-链表不是空表,-1-链表为空表
*/
int list_empty(linklist H)
{
if (H == NULL)
{
printf("list is not exist\n");
return -1;
}
else if (H->next == NULL)
{
return -1;
}
else
{
return 0;
}
}
/**
* @name list_tail_insert()
* @brief 链表尾部插入函数
* @param H 表地址,value 插入的值
* @retval 0-成功插入,-1-插入失败
*/
int list_tail_insert(linklist H, data_t value)
{
linklist NewNode; // 新节点
linklist tem; // 临时节点,记录遍历过程节点地址
// 1. 判断链表H是否存在
if (H == NULL)
{
printf("list is not exist\n");
return -1;
}
// 2. 创建一个新节点p,赋初值
if ((NewNode = (linklist)malloc(sizeof(listnode))) == NULL)
{
printf("malloc fail\n");
return -1;
}
NewNode->data = value;
NewNode->next = NULL;
// 3. 查找链表的尾结点q,将尾节点q的next指向新节点p
tem = H;
while (tem->next != NULL)
{
tem = tem->next;
}
tem->next = NewNode;
return 0;
}
/**
* @name list_head_insert(linklist H, data_t value)
* @brief 链表头部插入函数
* @param H 表地址,value 插入的值
* @retval 0-成功插入,-1-插入失败
*/
int list_head_insert(linklist H, data_t value)
{
linklist NewNode; // 新节点
// 1. 判断链表H是否存在
if (H == NULL)
{
printf("list is not exist\n");
return -1;
}
// 2. 创建一个新节点p,赋初值
if ((NewNode = (linklist)malloc(sizeof(listnode))) == NULL)
{
printf("malloc fail\n");
return -1;
}
NewNode->data = value;
NewNode->next = NULL;
// 3. 将头节点q的next指向新节点p
NewNode->next = H->next;
H->next = NewNode;
return 0;
}
/**
* @name list_show()
* @brief 链表遍历函数
* @param H 表地址
* @retval 0-成功遍历,-1-遍历失败
*/
int list_show(linklist H)
{
linklist tem; // 临时节点,记录遍历过程节点地址
// 1. 判断链表H是否存在
if (H == NULL)
{
printf("list is not exist\n");
return -1;
}
// 2. 遍历链表,打印出所有节点的值
tem = H->next;
while (tem != NULL)
{
printf("%d ", tem->data);
tem = tem->next;
}
puts("");
return 0;
}
/**
* @name list_length()
* @brief 获取链表长度函数
* @param H 表地址
* @retval 链表长度,-1则链表不存在
*/
int list_length(linklist H)
{
linklist tem; // 临时节点,记录遍历过程节点地址
int i;
// 1. 判断链表H是否存在
if (H == NULL)
{
printf("list is not exist\n");
return -1;
}
// 2. 遍历链表,统计链表长度
tem = H;
i = 0;
while (tem->next != NULL)
{
i++;
tem = tem->next;
}
return i;
}
/**
* @name list_get()
* @brief 获取链表第pos个节点
* @param H 表地址
* @retval 要获取的节点地址
*/
linklist list_get(linklist H, int pos)
{
linklist tem; // 临时节点,存放pos节点地址
int i;
// 1. 判断链表H是否存在,以及pos是否合法
if (H == NULL)
{
printf("list is not exist\n");
return H;
}
if (pos < -1 || pos >= list_length(H)) // pos不合法
{
printf("pos is invalid\n");
return NULL;
}
// 2. 遍历链表,找到第pos个节点
tem = H;
for (i = -1; i < pos; i++)
{
tem = tem->next;
}
return tem;
}
/**
* @name list_insert()
* @brief 链表插入函数
* @param H 表地址,pos 插入的位置,value 插入的值
* @retval 0-成功插入,-1-插入失败
*/
int list_insert(linklist H, int pos, data_t value)
{
linklist NewNode;
linklist tem; // 临时节点,存放pos-1个节点
// 1. 创建一个新节点q,赋初值
if ((NewNode = (linklist)malloc(sizeof(listnode))) == NULL)
{
printf("malloc fail\n");
return -1;
}
NewNode->data = value;
NewNode->next = NULL;
// 2. 查找链表的第pos-1个节点,并将其next给到新节点q,其自身next改为q节点地址
tem = list_get(H, pos-1);
if (tem == NULL)
{
return -1;
}
NewNode->next = tem->next;
tem->next = NewNode;
return 0;
}
/**
* @name list_delete()
* @brief 链表删除函数
* @param H 表地址,pos 删除的链表位置
* @retval 0-成功删除,-1-删除失败
*/
int list_delete(linklist H, int pos)
{
linklist tem1; // 临时节点tem1,存放pos-1的节点
linklist tem2; // 临时节点tem1,存放pos的节点
// 1. 判断链表H是否存在,以及pos是否合法
if (H == NULL)
{
printf("list is not exist\n");
return -1;
}
if (pos < 0 || pos > list_length(H)) // pos不合法
{
printf("pos is invalid\n");
return -1;
}
// 2. 遍历链表,找到第pos个节点的前一个节点,并删除该节点
tem1 = list_get(H, pos-1); // 找到第pos-1个节点
tem2 = tem1->next; // 找到第pos个节点
//printf("delete %d\n", tem2->data);
tem1->next = tem1->next->next; // 将第pos-1个节点的next指向第pos+1个节点
free(tem2); // 释放第pos个节点的内存
tem2 = NULL;
return 0;
}
/**
* @name list_free()
* @brief 链表销毁函数,使用时注意将返回值赋值给链表
* @param H 表地址
* @retval NULL
*/
void list_free(linklist *H)
{
linklist tem; // 临时节点,记录遍历过程节点地址
// 1. 判断链表H是否存在
if (*H == NULL)
{
printf("list is not exist\n");
return;
}
// 2.遍历链表,释放所有节点
while (*H != NULL)
{
tem = (*H)->next;
// printf("free %d\n", tem->data);
free(*H);
*H = tem;
}
*H = NULL;
}
/**
* @name list_reverse(linklist H)
* @brief 链表反转函数
* @param H 表地址
* @retval 0-成功反转,-1-反转失败
*/
int list_reverse(linklist H)
{
int length = list_length(H);
// 1. 判断链表H是否存在
if (H == NULL)
{
printf("list is not exist\n");
return -1;
}
// 2. 创建新链表,并遍历链表,将链表反转
printf("length:%d\n",length);
while (length)
{
list_insert(H, length--,H->next->data);
list_delete(H, 0);
}
return 0;
}
/**
* @name linklist list_adjmax(linklist H)
* @brief 查找链表相邻两节点最大值函数
* @param H 表地址
* @retval 两节点中的前一节点地址
*/
linklist list_adjmax(linklist H,int *max)
{
linklist tem;
int temp;
// 1. 判断链表H是否存在,以及链表H内元素是否大于2
if (H == NULL || H->next == NULL || H->next->next == NULL)
{
printf("list is invalid\n");
return NULL;
}
while (H->next->next != NULL)
{
temp = H->next->data + H->next->next->data;
if (*max < temp)
{
// printf("a1:%d\n", *max);
*max = temp;
// printf("a2:%d\n", max);
tem = H->next;
// printf("bb:%p\n", tem);
}
H = H->next;
// printf("***%d**\n",H->data);
}
// printf("***llll**\n");
return tem;
}
/**
* @name list_merge(linklist H)
* @brief 链表合并函数(两个有序链表)
* @param H1 表1地址,H2 表2地址
* @retval 合并后新链表头结点指针,NULL则链表不存在
*/
linklist list_merge(linklist H1, linklist H2)
{
linklist tem1, tem2, H3;
tem1 = H1->next;
tem2 = H2->next;
// 1. 判断链表H1和H2是否存在
while (H1 == NULL || H2 == NULL)
{
printf("list is invalid\n");
return NULL;
}
// // 2. 创建新链表H3,并遍历链表,将链表合并
H3 = list_create();
while (tem1 != NULL && tem2 != NULL)
{
// printf("tem1:%d\n", tem1->data);
// printf("tem2:%d\n", tem2->data);
// scanf("%d",&i);
if (tem1->data < tem2->data)
{
list_tail_insert(H3, tem1->data);
tem1 = tem1->next;
}
else
{
list_tail_insert(H3, tem2->data);
tem2 = tem2->next;
}
// printf("tem3:%d\n", tem3->data);
}
if (tem1 == NULL)
{
while (tem2 != NULL)
{
list_tail_insert(H3, tem2->data);
tem2 = tem2->next;
}
}
else
{
while (tem1 != NULL)
{
list_tail_insert(H3, tem1->data);
tem1 = tem1->next;
}
}
return H3;
// 该方法会影响链表H1和H2,通过改变每个节点的next地址生成H3
// while (tem1 != NULL && tem2 != NULL)
// {
// // printf("tem1:%d\n", tem1->data);
// // printf("tem2:%d\n", tem2->data);
// // scanf("%d",&i);
// if (tem1->data < tem2->data)
// {
// tem3->next = tem1;
// tem1 = tem1->next;
// }
// else
// {
// tem3->next = tem2;
// tem2 = tem2->next;
// }
// tem3 = tem3->next;
// // printf("tem3:%d\n", tem3->data);
// }
// if (tem1 == NULL)
// {
// tem3->next = tem2;
// }
// else
// {
// tem3->next = tem1;
// }
// return H3;
}
main.c
#include <stdio.h>
#include "linklist.h"
#include <stdlib.h>
#include <time.h>
void test_create();
void test_delete();
void test_reverse();
void test_adjmax();
void test_merge();
int main(int argc, const char *argv[])
{
// test_create();
// test_delete();
// test_reverse();
// test_adjmax();
// test_merge();
return 0;
}
void test_create()
{
linklist H;
int value;
int pos,length;
H = (linklist)list_create();
printf("**********test_create*******\n");
printf("list_tail_insert:\n");
while (1)
{
printf("input:");
scanf("%d", &value);
if (value == -1)
{
break;
}
list_tail_insert(H, value);
}
printf("list_insert:\n");
while (1)
{
printf("input:[pos],[value]\n");
scanf("%d,%d", &pos, &value);
if (pos == -1)
{
break;
}
list_insert(H, pos, value);
}
printf("**********lsit_show*******\n");
list_show(H);
length = list_length(H);
printf("length:%d\n",length);
printf("get pos:");
scanf("%d", &pos);
printf("**********test_get*******\n");
if (list_get(H, pos) == NULL)
{
return;
}
printf("value:%d\n",list_get(H, pos)->data);
list_free(&H);
return;
}
void test_delete(void)
{
linklist H;
int value, pos;
int length=5;
H = (linklist)list_create();
printf("**********test_delete*******\n");
srand((unsigned)time(NULL));
while (length)
{
value = rand()%100+1;
list_tail_insert(H, value);
length--;
}
printf("******before_delete******\n");
list_show(H);
printf("delete pos:");
scanf("%d", &pos);
list_delete(H, pos);
printf("******after_delete******\n");
list_show(H);
list_free(&H);
printf("*****after_free*******\n");
list_show(H);
return;
}
void test_reverse()
{
linklist H;
int value;
int length = 7;
H = (linklist)list_create();
printf("**********test_reverse*******\n");
srand((unsigned)time(NULL));
while (length)
{
value = rand()%100+1;
list_tail_insert(H, value);
length--;
}
printf("******before_reverse******\n");
list_show(H);
printf("******after_reverse******\n");
list_reverse(H);
list_show(H);
return;
}
void test_adjmax()
{
linklist H;
linklist p;
int value;
int *max = malloc(sizeof(int));
int length;
H = (linklist)list_create();
printf("**********test_adjmax*******\n");
printf("input length:");
scanf("%d", &length);
srand((unsigned)time(NULL));
while (length)
{
value = rand()%100+1;
list_tail_insert(H, value);
length--;
}
printf("******before_adjmax******\n");
list_show(H);
printf("******after_adjmax******\n");
p = list_adjmax(H, max);
printf("value:%d\n",p->data);
printf("max:%d\n", *max);
list_free(&H);
list_show(H);
return;
}
void test_merge()
{
linklist H1, H2, H3;
int a[] = {1, 3, 5, 9, 17};
int b[] = {2, 6, 8, 13, 19};
H1 = (linklist)list_create();
H2 = (linklist)list_create();
printf("**********test_merge*******\n");
printf("befor_merge:\n");
for (int i = 0; i < sizeof(a)/sizeof(int); i++)
{
list_tail_insert(H1, a[i]);
}
for (int j = 0; j < sizeof(b)/sizeof(int); j++)
{
list_tail_insert(H2, b[j]);
}
list_show(H1);
list_show(H2);
H3 = list_merge(H1, H2);
printf("after_merge:\n");
list_show(H3);
list_show(H1);
list_show(H2);
list_free(&H1);
list_free(&H2);
list_free(&H3);
list_show(H1);
list_show(H2);
list_show(H3);
return;
}

浙公网安备 33010602011771号