大家吼我又来了,今天我给大家带来的是单向链表和双向链表的基本操作(基本上挺全的。。。)
数据结构这门课程是学计算机的学生们感觉很重要很困难的学科。而链表也基本上算是数据结构刚入门时所写的了吧。
我把自己学习数据结构的历程分享到自己的博客里,供大家学习也供我自己查阅自己的学习历程。若是感觉还不错或者有任何问题的话,欢迎加我的qq:790567648来跟我进一步的交流。hhh
话不多说,我先上代码为敬,(基本上操作内我都写上注释了,再有什么看不懂的地方可以私信我聊)
单向链表的基本操作实现
-------老规矩,头文件,宏定义以及ADT和基本数据操作的声明
#include<stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct Node
{
ElemType data;
struct Node *next;
}Node, *List;
List InitList();//带头结点的链表的建立
int Listlength(List L);//求链表的长度
void ListInsert(List L, int i, ElemType e);//在L中第i个位置之后插入一个结点的数值为e
void ListDelete(List L, int i);//链表第i个结点的删除
int GetElemtype(List L, int i);// 返回L中第i个位置的数据元素的值
void GetElem(List L, ElemType e);//查找在链表中是否有e这个元素,有的话返回它在链表中的位置,没有的话显示无
void ListCleaner(List L);//链表的清除
void print(List L);//链表的输出
List InitList()//带头结点的链表的建立(需要参数和不需要参数同理)
{
Node *last;//p为插入结点,last始终指向末节点;
List L;
L = (Node *)malloc(sizeof(Node));
L->next == NULL;
last = L;
ElemType elem;
printf("已为您创建链表,请输入每个元素的值(以空格隔开并且以-1为结尾且不计入链表之中)\n");
while (scanf("%d", &elem) && elem != -1)
{
Node *p;
p = (Node *)malloc(sizeof(Node));
p->data = elem;
last->next = p;
last = p;
}
last->next = NULL;
printf("链表以创建成功!\n");
return L;
}
int Listlength(L)//求链表的长度
{
Node *p;
p = L;
int temp = 0;
while (p->next != NULL)
{
temp++;
p = p->next;
}
return temp;
}
void ListInsert(List L, int i, ElemType e)//在L中第i个位置之后插入一个结点的数值为e
{
int j = 0;
Node *p, *temp;
p = L;
while (j<i)
{
p = p->next;
j++;
}
temp = (Node *)malloc(sizeof(Node));//新建一个结点
temp->data = e;
temp->next = p->next;
p->next = temp;
}
void print(List L)//链表的输出
{
List tempList;
tempList = L->next;
while (tempList)
{
printf("%d ", tempList->data);
tempList = tempList->next;
}
}
void ListDelete(List L, int i)//链表第i个结点的删除
{
if (i<1 || i>Listlength(L) + 1)
{
exit(0);
}
int j = 0;
Node *p;
p = L;
while (p&&j < i - 1)//找到第i个位置前的结点
{
p = p->next;
j++;
}
p->next = p->next->next;
}
int GetElemtype(List L, int Position)// 返回L中第i个数据元素的值
{
Node *p;
p = L;
for (int j = 0; j < Position; j++)
{
p = p->next;
}
return p->data;
}
void ListCleaner(List L)//链表的清除
{
List p = NULL, q = NULL;//让p指向当前要删除的结点,q指向p之后的结点,等p释放空间后再重复上述操作
p = L->next;
while (p)
{
q = p->next;
free(p);
p = q;
}
L->next = NULL;
printf("链表已经清除!\n");
}
void GetElem(List L, ElemType e)//查找在链表中是否有e这个元素,有的话返回它在链表中的位置
{
Node *p;
int temp = 0;
p = L->next;
while (p)
{
temp++;
if (p->data == e)
{
printf("结果:该元素在第%d个位置\n", temp);
exit(0);
}
p = p->next;
}
printf("结果:未找到相关元素!\n");
}
自己写的main函数,大家看看就好,,,,不必当真(QAQ我知道看到这里大佬要开始吐槽我了,手下留情)
int main(void)
{
int n, i, e;
List L;
L = InitList();
printf("链表的长度为:%d\n", Listlength(L));
printf("此时,链表的元素为:");
print(L);
printf("\n");
printf("请输入需要插入的位置以及元素:");
scanf("%d %d", &i, &e);
ListInsert(L, i, e);
printf("此时,链表的元素为:");
print(L);
printf("\n");
printf("此时链表的长度为:%d\n", Listlength(L));
int deletenum;
printf("请输入要删除的元素的位置为:");
scanf("%d", &deletenum);
ListDelete(L, deletenum);
printf("此时,链表的元素为:");
print(L);
printf("\n");
printf("此时,链表的长度为:%d\n", Listlength(L));
int test;
printf("请输入要查询第几个位置的元素:");
scanf("%d", &test);
printf("该位置的元素为:%d\n", GetElemtype(L, test));
int temp;
printf("请输入此元素来查询该链表中是否有该元素:");
scanf("%d", &temp);
GetElem(L, temp);
printf("正在进行清空操作,请稍候。。。\n");
ListCleaner(L);
printf("此时,链表的长度为:%d\n", Listlength(L));
printf("恭喜您以完成全部操作!\n");
return 0;
}
双向链表的基本操作实现
#include<stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct DuLNode {
ElemType data;
struct DuLNode *prior;
struct DuLNode *next;
}DuLNode,*DuLinkList;
DuLinkList InitList();//带头结点的链表的建立
int Listlength(DuLinkList L);//求链表的长度
void ListInsert(DuLinkList L, int i, ElemType e);//在L中第i个位置之后插入一个结点的数值为e
void ListDelete(DuLinkList L, int i);//链表第i个结点的删除
int GetElemtype(DuLinkList L, int i);// 返回L中第i个位置的数据元素的值
void GetElem(DuLinkList L, ElemType e);//查找在链表中是否有e这个元素,有的话返回它在链表中的位置,没有的话显示无
void ListCleaner(DuLinkList L);//链表的清除
void print(DuLinkList L);//链表的输出
DuLinkList InitList()
{
DuLinkList L,Last;
L = (DuLinkList)malloc(sizeof(DuLinkList));
L->prior = NULL;
L->next = NULL;
Last = L;//last一直指向链表的最后一个元素,便于循环内部的初始化链表的值
int data;
printf("请输入双向链表的值:(以空格为间隔,结尾为-1且不算在链表中)");
while (scanf("%d",&data)&&data!=-1)//出现-1则跳出循环,-1不在链表之内
{
DuLNode *p = (DuLNode *)malloc(sizeof(DuLNode));
p->data = data;
Last->next=p;
p->prior = Last;
p->next = NULL;
Last = p;
}
Last->next = NULL;//最后last指向最后一个有效的结点p,使其的next指向NULL
return L;
}
int Listlength(DuLinkList L)
{
DuLinkList p;
p = L;
int length = 0;
while (p->next)//若p->next不空,则temp++,temp即为链表的长度
{
p = p->next;
length++;
}
return length;
}
int GetElemtype(DuLinkList L, int i)
{
DuLinkList p = L;
int j = 0;
if (L=NULL)
{
return;
}
else {
while (p->next&&j < i)//找到第i个元素所在的位置
{
p = p->next;
j++;
}//跳出循环时p当前的位置即为第i个元素所在的位置(判断并输出的条件是j==i)
if (j==i)
{
return p->data;
}
}
}
void GetElem(DuLinkList L, ElemType e)
{
DuLinkList p = L;
int temp = 0;
while (p->next)//p->next若不空,则继续进行遍历,知道找到p
{
p = p->next;
temp++;
if (p->data==e)
{
printf("存在该元素,且它的位置在链表的第%d个位置上\n", temp);
temp = -1;//若元素在最后一个位置上,则下面的话也会输出,所以改变temp的值,使其跳出循环时不会被下面的判断句所接收
}
}
if (temp>0)
{
printf("该链表中不存在该元素!\n");
}
}
void ListCleaner(DuLinkList L)
{
DuLinkList p;
p = L->next;//L为头结点,所以p要指向链表中第一个有效的结点即头结点的next
while (p)
{
L->next = p->next;//将L->next指向p->next,便于删除p时影响链表的结构
free(p);
p = L->next;
}
printf("链表已清除完毕!\n");
}
void print(DuLinkList L)
{
int i = 1;
DuLinkList p = L->next;
while (p)
{
printf("链表的第%d个元素为:%d\n", i, p->data);
i++;
p = p->next;
}
}
void ListInsert(DuLinkList L, int i, ElemType e)
{
DuLinkList p = L->next;
int j = 0;
if (i<0||i>Listlength(L))
{
printf("所插入的位置不存在!\n");
}
else {
while (p&&j < i - 1)//找到p为所要插入的位置(即i之后的位置)
{
p = p->next;
j++;
}
if (i==0)//想在头结点之后插入元素时
{
DuLinkList inserted;
inserted = (DuLinkList)malloc(sizeof(DuLinkList));
//四步走,把四个线连起来
inserted->data = e;
L->next = inserted;
inserted->prior = L;
inserted->next = p;
p->prior = inserted;
}
else if (p->next)//i>0&&p之后还有结点时
{
DuLinkList inserted;
inserted = (DuLinkList)malloc(sizeof(DuLinkList));
inserted->data = e;
//四步走,把四个线连起来
inserted->next = p->next;
p->next->prior = inserted;
p->next = inserted;
inserted->prior = p;
printf("插入成功!\n");
}
else {//i>0&&p为链表最后一个结点时
DuLinkList inserted;
inserted = (DuLinkList)malloc(sizeof(DuLinkList));
inserted->data = e;
//三步走
p->next = inserted;
inserted->prior = p;
inserted->next = NULL;
}
}
}
void ListDelete(DuLinkList L, int i)
{
if (i<0||i>Listlength(L))
{
printf("位置不存在!\n");
}
else {
int j = 0;
DuLinkList p = L->next;//L为头结点,所以p要指向链表中第一个有效的结点即头结点的next
//先找到被删除结点的位置
while (p&&j < i - 1)
{
p = p->next;
j++;
}
if (p->next)//p的next后还有结点时
{//两步走
p->next->prior = p->prior;
p->prior->next = p->next;
}
else {//p为链表最后一个元素
p->prior->next = NULL;
}
}
}
int main(void)
{
//双向链表的定义及初始化
DuLinkList L;
L = InitList();
//求链表的长度
printf("该链表的长度为;%d\n", Listlength(L));
求链表的第i个位置上的元素
int temp;
printf("请输入想要知道的第几个位置:");
scanf("%d", &temp);
printf("该位置上的数为:%d\n", GetElemtype(L, temp));
//求链表是否存在元素的某个值
printf("请输入想知道链表中是否存在该元素的值:");
scanf("%d", &temp);
GetElem(L, temp);
//遍历输出链表的元素
print(L);
//在链表中指定位置后插入元素
printf("输入你想在第几个位置之后插入元素:");
int yuansu, weizhi;
scanf("%d", &weizhi);
printf("输入你想插入元素的值:");
scanf("%d", &yuansu);
ListInsert(L, weizhi, yuansu);
//遍历
print(L);
//在链表中指定位置删除元素
printf("输入你想删除的结点在链表中的位置:");
scanf("%d", &weizhi);
ListDelete(L, weizhi);
//遍历
print(L);
//选择是否进行摧毁链表操作
printf("是否选择进行摧毁链表操作,1是确定,2是不进行:");
int boolean;
scanf("%d", &boolean);
if (boolean==1)
{
printf("链表正在删除当中。。。\n");
ListCleaner(L);
printf("该链表的长度为:%d\n", Listlength(L));
}
else{
printf("恭喜你完成双向链表的全部基本操作!\n");
}
return 0;
}
双向链表代码里面的基本内容也都是参照单向链表里面写的,只不过更进一步而已。而循环链表我没再写是因为只要把最后last-next从指向NULL改为指向头结点即可。具体操作跟单向链表几乎一模一样(当然你也可以从双向链表的基础上做也就是双向循环链表hhh)
*PS:*emmmm…我写的两个基本操作集里面的链表都是带头结点的,而且Ctrl A+Crtl C+Ctrl V是可以直接使用C语言编译器通过的。。。刚想起来补充上,还有一些可能想不起来了想起来的时候会更新哦!
大家也要加油鸭!