定义:线性表的链式存储,非随机存储的存储结构。
存储单元由两部分组成,数据源和指针,数据源放数据,指针指向下个存储单元
头指针和头结点的区分:通常用头指针来标识一个单链表,且始终指向链表的第一个结点;而头结点是带头结点的链表的第一个结点。
图片转载至:数据结构单链表
单链表基本操作的实现:
1.头插法建立单链表
2.尾插法建立单链表
3.求表长
4.插入结点(尾插和前插):若根据i-1个元素查找,时间复杂度O(n),若给定元素则为时间 复杂度O(1);
5.查找结点(按位查找和按值查找):时间复杂度均为O(n);
6.删除结点 :顺序查找第i个元素,时间复杂度为O(n);删除结点*p,时间复杂度为O(1);
源代码:
注意事项:
1 结构指针,这是链表中很重要的一个部分。这里面LinkList就是一个结构指针类型,一定要注意LinkList的实际含义。
2 typedef LNode *LinkList 是typedef使用方式之一,这是指LInkList替换为LNode指针类型。LinkList和LNode *是等价的。
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef int ElemType;
//定义单链表结构
typedef struct LNode
{
ElemType data;//数据域
struct LNode *next;//指针域,指向下一节点
} LNode,* LinkList;//此处LNode和LinkList是等价的
//创建单链表头插法
LinkList List_headinsert(LinkList &L)
{
LNode *s;
int x;
L = (LinkList)malloc(sizeof(LNode));//创建头结点
L->next=NULL;//初始化表为空链表,这一步很重要。
scanf("%d",&x);//输入结点的值
while(x!=1111){//1111相当于一个退出条件
s = (LNode*) malloc(sizeof(LNode));//创建s新结点,这一步的作用是:由系统生成一个LNode型的结点,同时将该结点的起始位置赋值给指针变量s。
s->data=x;//s结点里面的数据为x
s->next=L->next;
L->next=s;//将新结点插入表中,L为头指针
scanf("%d",&x); //重复操作直到1111输入
}
return L;
//因为是头插法,输出结果每一步都是往头节点之后插入, 所以结果链表数据为逆序
//时间复杂度为:O(n)
}
//创建单链表尾插法
LinkList List_tailinsert(LinkList &L){
int x;
L = (LinkList)malloc(sizeof(LNode));//创建头结点
L->next=NULL;
LNode *s,*r=L;//r:表尾指针指向头结点
scanf("%d",&x);
while(x!=1111){
s = (LNode*) malloc(sizeof(LNode));
s->data = x;
r->next = s;
r = s;//r又指向新的表尾结点
scanf("%d",&x);
}
r->next = NULL;
return L;
//尾插法是从头结点开始,将新的结点插在尾指针所指后面next,每一次建立新的结点尾指针就会指向该结点
//时间复杂度为:O(n)
}
//求表的长度
int Length(LinkList &L){
int len = 0;
LNode * p;
p = L;
while(p->next != NULL){
len++;
p = p->next;
}
return len;
}
//将元素插入指定位置(后插操作)(insert the e = i)
bool tail_Listinsert(LinkList &L,int i,ElemType e){//i:location,e:data
if(i<1){
return false;
}
LNode *p;//指针p指向当前扫描到的结点
int j = 0;//指针p指向的第几个结点
p = L;//L指向第0个结点,不存放数据,不显示
while (p!=NULL && j<i-1){//w为什么i-1:因为我们是找到i的前一个数对其操作,让新的s结点变成i位置
p = p->next;
j++;
}
if(p == NULL){
return false;
}
LNode *s = (LNode *)malloc(sizeof(LNode)); //初始化一个新的s
s->data = e;
s->next = p->next;
p->next = s;//这一步就是将s放在p的后面
return true;
}
// 将元素插入指定位置(前插操作)
bool head_Listinsert(LinkList &L,int i,ElemType e){//i:location,e:data
if(i<1){
return false;
}
LNode *p;//指针p指向当前扫描到的结点
int j = 0;//指针p指向的第几个结点
p = L;//L指向第0个结点,不存放数据,不显示
while (p!=NULL && j<i){//因为是尾插,直接找第i个元素就行
p = p->next;
j++;
}
if(p == NULL){
return false;
}
LNode *s = (LNode *)malloc(sizeof(LNode));
s->next = p->next;
p->next = s;//这一步就是将s放在p的后面
s->data = p->data;//将p中的元素复制到s中
p->data = e;//e覆盖原来s的位置
return true;
}
//指定位置查找元素
int GetElem(LinkList &L,int i,ElemType e){
int j=1;
LNode *p;//指针p指向当前扫描到的结点
p=L->next;//指向第一个结点
while(p&&j<i){
p=p->next;//循环一直后移
j++;
}
if(!p||j>i){
return '0';
}
e=p->data;
return e;
}
//查找指定元素,返回指定元素位序
int seachLinkList(LinkList &L, ElemType e)
{
int pos = 1;//位序从1开始、下标从零开始
LNode *p;//指针p指向当前扫描到的结点
p=L->next;//指向第一个元素
while(p)
{
if(p->data == e) //判定
return pos;//找到指定元素,返回位序
p = p->next;//尾指针后移
pos ++;
}
while(!p)
printf("NOT FOUND 404!");
//遍历完成仍未找到返回-1
}
//删除指定结点
bool Node_delete(LinkList &L,int i){
int j=1;
LNode *q;
LNode *p;//指针p指向当前扫描到的结点
p=L->next;//指向第一个结点
while(p&&j<i){
p=p->next;//循环一直后移
j++;
}
q = p->next;//令q指向*p的后继结点
p->data = p->next->data;//用后继结点的数据覆盖原来的数据
p->next = q->next;//将q指针指向的结点从链中断开
free(q);//释放后继结点的存储空间
return true;
}
//打印结果列表
void printLinkList(LinkList &L)
{
LNode *p;
p = L->next;
while(p)
{
printf("%d ",p->data);
p = p->next;
}
}
//主函数
int main()
{
LNode *L;
LNode *p;
ElemType e;
int x,i;
printf("创建单链表");
printf("1:使用头插法 2:使用尾插法\n");
printf("输入1111结束插入\n");
printf("选择插入方法:");
scanf("%d",&i);
switch(i){
case 1:
printf("使用头插法\n");
printf("输入插入元素:\n");
List_headinsert(L);
break;
case 2:
printf("使用尾插法\n");
printf("输入插入元素:\n");
List_tailinsert(L);
break;
default:
printf("错误!!");
return 0;
}
printf("链表创建成功,当前链表所有元素:\n");
printLinkList(L);
printf("\n表的长度为:%d\n",Length(L));
printf("删除第i个结点:\n");
scanf("%d",&i);
Node_delete(L,i);
printLinkList(L);
printf("\n插入方式\n");
printf("1:前插 2:尾插\n");
printf("选择插入方法:");
scanf("%d",&i);
switch(i){
case 1:
printf("\n插入位置和插入值(中间用空格隔开):");
scanf("%d%d",&i, &e);
tail_Listinsert(L, i, e);
printf("\n插入元素后链表所有元素:");
printLinkList(L);
break;
case 2:
printf("\n插入位置和插入值(中间用空格隔开):");
scanf("%d%d",&i, &e);
head_Listinsert(L,i,e);
printf("\n插入元素后链表所有元素:");
printLinkList(L);
break;
default:
printf("错误!!");
return 0;
}
printf("\n查找方式\n");
printf("1:按位查找 2:按数值查找\n");
printf("选择查找方法:");
scanf("%d",&i);
switch(i){
case 1:
printf("\n按位序查找元素,输入位序:");
scanf("%d",&i);
if(i<=Length(L))
{
printf("\n第%d位的元素是:%d",i,GetElem(L,i,e));
}
else
printf("查找失败,超过位序");
break;
case 2:
printf("\n请输入查找元素:");
scanf("%d",&e);
if(seachLinkList(L, e))
{
printf("\n查找元素%d位于:第%d位",e, seachLinkList(L, e));
}
else
printf("\n%d未找到",e);
break;
default:
printf("错误!!");
return 0;
}
return 0;
}