大家好,我是练习编程时长两年半的昆工第一ikun,今天咋们来说一下线性链表和单向循环链表,这个是个很基础的链表,咋们来分成线性链表和单向循环链表来说。
一、线性链表
1.逻辑结构:线性结构
2.存储结构:链式存储,每个元素的地址空间不是连续
优点:链表能够解决顺序表中资源空间浪费的问题以及空间不足的问题
缺点:链表的查找和修改元素效率低
3.链表相关操作算法:
①创建链表的头节
②判断链表是否是空链表
③计算表长
④从表头插入数据
⑤按位置插入数据
⑥按位置删除数据
⑦按数据删除
⑧按位置查找元素
⑨按数据查找元素
⑩清空链表,删除链表
4.链表节点相关结构体
typedef int data_t; typedef struct linklist { data_t data; //数据域 struct linklist *next; //指针域 }LinkList;
5.linklist.h头文件代码
#ifndef _LINKLIST_
#define _LINKLIST_
typedef int data_t;
typedef struct linklist
{
data_t data;
struct linklist *next;
}LinkList;
LinkList *Create_Linklist(); //创建链表的表头
int Linklist_Is_Empty(LinkList *head); //判空
int Linklist_Size(LinkList *head); //计算表长
void Linklist_Insert_Head(LinkList *head, data_t data); //从表头插入数据
void Linklist_Insert_Pos(LinkList *head, int Pos, data_t data); //按位置插入数据
void Linklist_Delete_Pos(LinkList *head, int pos); //按位置删除数据
void Linklist_Delete_Data(LinkList *head, data_t data); //按数据删除
void Linklist_Find__Pos(LinkList *head, int pos); //按位置查找
void Linklist_Find_Data(LinkList *head, data_t data); //按数据查找
void Linklist_Eidt__Pos(LinkList *head, int pos, data_t data); //按位置修改
void Linklst_Empty(LinkList *head); //清空链表
void Linklist_Delete(LinkList **head);//删除链表
void Linklist_Exchange(LinkList *head); //将表逆序
void Linklist_Show(LinkList *head); //打印链表
#endif
6.linklist.c函数内容实现代码
#include <stdio.h>
#include <stdlib.h>
#include "linklist.h"
//*********************创建链表的头节点*****************
LinkList *Create_Linklist()
{
LinkList *head = (LinkList *)malloc(sizeof(LinkList)); //给链表在堆区开辟空间
if(head == NULL){
printf("创建失败!\n");
return NULL;
}
head->data = -1;
head->next = NULL;
return head;
}
//*******************判空*****************
int Linklist_Is_Empty(LinkList *head)
{
if(head->next == NULL){
return 1;
}
else{
return 0;
}
}
//*********************计算表长*****************
int Linklist_Size(LinkList *head)
{
int len = 0;
LinkList *p = head->next;
while(p != NULL){
len++;
p = p->next;
}
return len;
}
//*************************从表头插入数据********************************
void Linklist_Insert_Head(LinkList *head, data_t data)
{
LinkList *new = (LinkList *)malloc(sizeof(LinkList)); //创建新的节点
if(NULL == new){
printf("创建失败!\n");
return;
}
new->data = data; //给新节点赋值
new->next = NULL;
new->next = head->next; //将新节点与头节点链接
head->next = new;
return;
}
//***********************按位置插入数据**************************
void Linklist_Insert_Pos(LinkList *head, int pos, data_t data)
{
if(pos < 0 || pos > Linklist_Size(head)-1){ //判断位置是否合法
printf("位置错误!\n");
}
LinkList *new = (LinkList *)malloc(sizeof(LinkList)); //创建新的节点
if(NULL == new){
printf("创建失败!\n");
return;
}
new->data = data;
new->next = NULL;
LinkList *p = head->next; //找到插入位置的上一个节点的地址
while(pos--){
p = p->next;
}
new->next = p->next;
p->next = new;
return;
}
//**************************按位置删除数据***************************
void Linklist_Delete_Pos(LinkList *head, int pos)
{
if(Linklist_Is_Empty(head) == 1){
printf("该表为空!\n");
return;
}
if(pos < 0 || pos > Linklist_Size(head)-1){ //判断位置是否合法
printf("位置错误!\n");
}
LinkList *p = head; //找到删除位置节点的地址
LinkList *q = NULL;
while(pos--){
p = p->next;
}
q = p->next;
p->next = q->next;
free(q);
q = NULL;
return;
}
//**************************按数据删除***************************
void Linklist_Delete_Data(LinkList *head, data_t data)
{
if(Linklist_Is_Empty(head) == 1){
printf("该表为空!\n");
return;
}
LinkList *w = head; //找到删除位置节点的地址
int ret = Linklist_Size(head), i = 0;
while(i < ret){
w = w->next;
if((w->data) == data){
int pos = i; //确定删除数据的位置
Linklist_Delete_Pos(head, pos);
break;
}
i++;
}
return;
}
//************************按位置查找**************************
void Linklist_Find__Pos(LinkList *head, int pos)
{
if(Linklist_Is_Empty(head) == 1){
printf("该表为空!\n");
return;
}
if(pos < 0 || pos > Linklist_Size(head)-1){ //判断位置是否合法
printf("位置错误!\n");
}
LinkList *p = head;
while(pos--){
p = p->next;
}
printf("该值为:%d\n", p->data);
return;
}
//***************************按数据查找***************************
void Linklist_Find_Data(LinkList *head, data_t data)
{
if(Linklist_Is_Empty(head) == 1){
printf("该表为空!\n");
return;
}
LinkList *p = head;
int ret = Linklist_Size(head), i = 0, pos;
while(i < ret){
p = p->next;
if((p->data) == data){
pos = i; //确定数据的位置
break;
}
i++;
}
printf("该值的位置为:%d\n", pos);
return;
}
//****************************按位置修改*************************
void Linklist_Eidt__Pos(LinkList *head, int pos, data_t data)
{
if(Linklist_Is_Empty(head) == 1){
printf("该表为空!\n");
return;
}
if(pos < 0 || pos > Linklist_Size(head)-1){ //判断位置是否合法
printf("位置错误!\n");
return;
}
LinkList *p = head->next;
while(pos--){
p = p->next;
}
p->data = data;
return;
}
//************************清空链表***********************
void Linklst_Empty(LinkList *head)
{
LinkList *p = head;
LinkList *q = NULL;
int len = Linklist_Size(head);
len--;
while(len--){
q = p->next;
p->next = q->next;
free(q);
q = NULL;
}
q = head->next;
free(q);
q = NULL;
head->next = NULL;
return;
}
//************************删除链表***********************
void Linklist_Delete(LinkList **head)
{
Linklst_Empty(*head);
free(*head);
*head = NULL;
return;
}
//***********************链表逆序************************
void Linklist_Exchange(LinkList *head)
{
LinkList *p = head->next;
LinkList *q = NULL;
head->next = NULL;
while(p != NULL){
q = p->next;
p->next = head->next;
head->next = p;
p = q;
}
return;
}
//************************打印链表***********************
void Linklist_Show(LinkList *head)
{
LinkList *p = head->next;
while(p != NULL){
printf("%d ", p->data);
p = p->next;
}
printf("\n");
return;
}
7.main.c主函数代码
由于坤坤没有太多时间,而且主函数的菜单列表也比较简单,所以坤坤没有写出主菜单,只是把函数功能实现了一遍,希望大家多多包涵。
#include <stdio.h>
#include "linklist.h"
int main(int argc, char *argv[])
{
LinkList *head = Create_Linklist();
int n = 10;
while(n--)
{
Linklist_Insert_Head(head, n);
}
Linklist_Show(head);
int len = Linklist_Size(head);
printf("len = %d\n", len);
Linklist_Insert_Pos(head, 5, 100);
Linklist_Show(head);
Linklist_Delete_Pos(head, 8);
Linklist_Show(head);
Linklist_Delete_Data(head, 3);
Linklist_Show(head);
Linklist_Find__Pos(head, 4);
Linklist_Find_Data(head, 100);
Linklist_Eidt__Pos(head, 8, 999);
Linklist_Show(head);
/* Linklst_Empty(head);
Linklist_Show(head);
Linklist_Delete(&head);
Linklist_Show(head); */
Linklist_Exchange(head);
Linklist_Show(head);
return 0;
}
现在,有一部分练习时长超过两年半的ikun就要问了,线性链表不能从结尾遍历回来,我心里不舒服,用着也不好用,那么下面我就来给大家介绍单向循环链表。
二、单向循环链表
单向循环链表与线性链表大体相同,只是把首尾连接了起来,请看代码。
1.clinklist.h头文件代码
#ifndef _LINKLIST_
#define _LINKLIST_
typedef int data_t;
typedef struct clinklist
{
data_t data;
struct clinklist *next;
}ClinkList;
ClinkList *Create_Clinklist(); //创建链表
void Clinklist_Insert_Head(ClinkList *head, data_t data); //头插法插入链表
void Clinklist_Ab_A(ClinkList *A, ClinkList *B); //将单向循环链表AB合成一个链表A
void Clinklist_Show(ClinkList *head); //打印链表
void Clinklist_Delete_Pos(ClinkList *head, int pos); //任意位置删除数据
void Clinklist_Insert_Pos(ClinkList *head, int pos, data_t data); //从任意位置插入数据
int Clinklist_Size(ClinkList *head); //判断链表长度
#endif
2.clinklist.c函数功能实现代码
#include <stdio.h>
#include <stdlib.h>
#include "clinklist.h"
//*********************创建链表的头节点*****************
ClinkList *Create_Clinklist()
{
ClinkList *head = (ClinkList *)malloc(sizeof(ClinkList)); //给链表在堆区开辟空间
if(head == NULL){
printf("创建失败!\n");
return NULL;
}
head->data = -1;
head->next = head;
return head;
}
//*************************判断链表长度***************************
int Clinklist_Size(ClinkList *head)
{
ClinkList *p = head;
int len = 0;
while(p->next != head){
p = p->next;
len++;
}
return len;
}
//*************************从表头插入数据********************************
void Clinklist_Insert_Head(ClinkList *head, data_t data)
{
ClinkList *new = (ClinkList *)malloc(sizeof(ClinkList)); //创建新的节点
if(NULL == new){
printf("创建失败!\n");
return;
}
new->data = data; //给新节点赋值
new->next = NULL;
new->next = head->next; //将新节点与头节点链接
head->next = new;
return;
}
//************************从任意位置插入数据*************************
void Clinklist_Insert_Pos(ClinkList *head, int pos, data_t data)
{
if(pos < 0 || pos > Clinklist_Size(head)-1){ //判断输入的位置是否合法
printf("该位置不存在!!!\n");
return;
}
ClinkList *new = (ClinkList *)malloc(sizeof(ClinkList)); //创建新的节点
if(NULL == new){
printf("创建失败!\n");
return;
}
new->data = data; //给新节点赋值
new->next = NULL;
ClinkList *p = head->next;
while(pos--){
p = p->next;
}
new->next = p->next;
p->next = new;
return;
}
//*********************按任意位置删除链表**********************
void Clinklist_Delete_Pos(ClinkList *head, int pos)
{
if(pos < 0 || pos > Clinklist_Size(head)-1){ //判断输入的位置是否合法
printf("该位置不存在!!!\n");
return;
}
ClinkList *p = head;
ClinkList *q = NULL;
while(pos--){
p = p->next;
}
q = p->next;
p->next = q->next;
free(q);
q = NULL;
return;
}
//************************将两个单向循环链表组合成一个********************
void Clinklist_Ab_A(ClinkList *A, ClinkList *B)
{
ClinkList *p = A->next;
ClinkList *q = B->next;
while(p->next != A){
p = p->next;
}
while(q->next != B){
q = q->next;
}
p->next = q->next->next;
q->next = A;
B = NULL;
return;
}
//************************打印链表*******************************
void Clinklist_Show(ClinkList *head)
{
ClinkList *p = head->next;
while(p != head){
printf("%d ", p->data);
p = p->next;
}
printf("\n");
return;
}
3.main.c主函数代码
#include <stdio.h>
#include "clinklist.h"
int main(int argc, char *argv[])
{
ClinkList *A = Create_Clinklist();
int n = 10;
while(n--)
{
Clinklist_Insert_Head(A, n);
}
Clinklist_Show(A);
ClinkList *B = Create_Clinklist();
n = 10;
while(n--)
{
Clinklist_Insert_Head(B, n);
}
Clinklist_Show(B);
Clinklist_Ab_A(A, B);
Clinklist_Show(A);
Clinklist_Delete_Pos(A, 5); //任意位置删除数据
Clinklist_Show(A);
Clinklist_Insert_Pos(A, 2, 999); //从任意位置插入数据
Clinklist_Show(A);
int len = Clinklist_Size(A); //判断链表长度
printf("%d\n", len);
return 0;
}
好了,今天的分享结束了,今天的链表是单向奔赴,那有没有双向奔赴的链表呢?当然有,坤坤明天就告诉你,我是练习编程时长两年半的个人练习生昆工第一ikun,我们明天见。