嗯,上一篇写的太过于臃肿了,在后续的文章中我就不将所有代码注释和函数一次性都写出来。避免大家阅读困难!
单链表的定义:
单链表的链式存储结构和前面所讲的的线性表的顺序存储结构相比较它最大的特点就是单链表的的每一个元素
在内存中是不连续的,这导致了假如我们想要访问表中第i个位置的元素,就必须得到第i-1个元素的地址。我们访问单链表
中的元素都是通过头指针中指针域保存的地址来访问表中的元素,并且不能越级访问。因为每一个结点有且仅有一个保存下一个
结点的地址的指针域,我觉得这是它不方便的一个地方,因为每一次我们想要查找或者删除表中的元素时,我们必须从头指针开始遍历!尽管如此,但是单链表的插入和删除效率比之线性表还是高了去多(单链表在确定插入或删除结点的上一个结点的信息后,插入和删除时间仅为O(1),而线性表位O(n),这是因为线性表的插入和删除需要移动结点后面的所有元素);
单链表的结构体定义的成员有两个,一个是用来存储数据的数据域,另外一个是用来保存指向下一个结点地址的指针域。
#include<stdio.h>
#include<iostream>
typedef struct _LinkList{
int date; //数据域
struct _LinkList *next; //指针域
}LinkList,LinkNode;
//初始化一个空的单链表
int main(void){
LinkList* L=NULL;
LinkNode* S=NULL;
system("pause");
return 0;
}
单链表的初始化:
因为我们初始化的是一个空链表,只有一个头结点后面没有结点。所以我将头结点的指针域置为空(NULL)
#include<stdio.h>
#include<iostream>
typedef struct _LinkList{
int date; //数据域
struct _LinkList *next; //指针域
}LinkList,LinkNode;
//初始化一个空的单链表
bool Init_LinkList(LinkList* &L){
L=new LinkNode;
if(!L){
printf("内存分配失败!");
return false;
}
L->next=NULL;
L->date=-1; //一般来讲,头指针的数据域不进行赋值
return true;
}
int main(void){
LinkList* L=NULL;
LinkNode* S=NULL;
//初始化一个空的单链表
if(Init_LinkList(L)){
printf("初始化一个空的单链表成功!");
}else{
printf("初始化一个空的单链表失败!");
}
system("pause");
return 0;
}
使用前前添加法来增加元素(后输入的元素在前面)
#include<stdio.h>
#include<iostream>
typedef struct _LinkList{
int date; //数据域
struct _LinkList *next; //指针域
}LinkList,LinkNode;
//使用前前添加元素(后输入的元素在前面)
bool insertFront__LinkList(LinkList* &L,LinkNode* &node){
node->next=L->next;
L->next=node;
return true;
}
//单链表的遍历(这个函数的功能是打印表中每一元素的值(头结点不打印,在后面我就不写了!))
void Printf_LinkList(LinkList* &L){
if(!L){
printf("单链表为空!");
return ;
}
LinkNode* p=NULL;
p=L->next;
while(p){
printf("%d\t",p->date);
p=p->next;
}
}
int main(void){
LinkList* L=NULL;
LinkNode* S=NULL;
int n,v;
//使用前插法来增加元素
printf("请输入要插入元素的个数n:");
scanf("%d",&n);
while(n){
S=new LinkNode;
printf("请输入要插入元素值v:");
scanf("%d",&v);
S->date=v;
insertFront__LinkList(L,S);
n--;
}
Printf_LinkList(L);
system("pause");
return 0;
}
使用尾尾添加法来添加元素
#include<stdio.h>
#include<iostream>
typedef struct _LinkList{
int date; //数据域
struct _LinkList *next; //指针域
}LinkList,LinkNode;
//使用尾插法来添加元素
bool insertBack__LinkList(LinkList* &L,LinkNode* &node){
LinkList* temp=NULL; //创建一个LinkList*类型的空链表
temp=L; //将我们要进行添加元素的链表(L)赋值给这个空链表
/*利用这个while循环使每一次
循环结束后temp为单链表L的最后一个结点*/
while(temp->next){
temp=temp->next;
}
//此时temp已经为单链表L的最后一个结点
//将temp结点的指针域中保存的地址改为指向新生成的结点
temp->next=node;
//然后将新生成的结点的指针域中保存的地址置为空(NULL)
node->next=NULL;
//添加成功,返回true;
return true;
}
int main(void){
LinkList* L=NULL;
LinkNode* S=NULL;
int n,v;
//使用尾插法来增加元素
printf("请输入要插入元素的个数n:");
scanf("%d",&n);
while(n){
//生成要添加的结点
S=new LinkNode;
printf("请输入要插入元素值v:");
scanf("%d",&v);
//赋值我就直接在main函数中赋了
S->date=v;
insertBack__LinkList(L,S);
n--;
}
Printf_LinkList(L);
system("pause");
return 0;
}
在任意位置插入元素
#include<stdio.h>
#include<iostream>
typedef struct _LinkList{
int date; //数据域
struct _LinkList *next; //指针域
}LinkList,LinkNode;
//在单链表的任意位置插入元素
bool insertShuiYi__LinkList(LinkList* &L,int &e,int n){
//定义一个变量j,用于退出后面的while循环
int j;
/*因为我们要找到插入位置的前一个结点,并且不能直接通过链表L来遍历,否则会破环
链表L的原有结构,所以我定义了两个LinkList*类型的指针*/
LinkList *p,*s;
//将L赋值给P
p=L;
j=0;
while(p&&j<n-1){
/*这里第一次循环的时候,y因为P=L所以p->next指向的是链表L的第一个节点
第二次循环的时候则指向第二个节点,以此类推。此处觉得难理解的朋友可以画张图模拟一下*/
p=p->next;
j++;
}
/*那么经过上面的while循环之后,p就是单链表L中我们要插入结点的上一个结点了,
但是假如我们输入的位置不合法呢,是不是应该检查一下我们的输入不合法,所以我用下面的if语句
来进行合法性检查*/
if(!p||j>n-1){
return false;
}
/*到此处就说明我们的输入是合法的,并且要插入结点的上一个结点我们也得到了(就是P),接下来 我给s分配了LinkNode类型大小的内存(s就是我们要插入的节点)*/
s=new LinkNode;
//给要插入的结点赋值
s->date=e;
//让新生成的结点的指针域保存的是要插入结点的上一个结点的指针域保存的地址
s->next=p->next;
//让我们要插入结点的上一个节点的指针域保存的是指向我们要插入结点的地址
p->next=s;
//插入成功,返回!
return true;
}
int main(void){
LinkList* L=NULL;
LinkNode* S=NULL;
int n,v,n1,v1;
//在单链表的任意位置插入元素
printf("请输入要插入要插入的值v1和位置n1[用空隔开]:");
scanf("%d\t%d",&v1,&n1);
S=new LinkNode;
S->date=v1;
if(insertShuiYi__LinkList(L,S->date,n1)){
printf("插入成功!");
}else{
printf("插入失败!");
}
Printf_LinkList(L);
system("pause");
return 0;
}
删除指定位置的元素
#include<stdio.h>
#include<iostream>
typedef struct _LinkList{
int date; //数据域
struct _LinkList *next; //指针域
}LinkList,LinkNode;
bool delete__LinkList(LinkList* &L,int n){
LinkList * p,*q;
p=L;
int index=0;
if(!L||!L->next){
return false;
}
/*通过while循环来找到要删除的结点的上一个结点*/
while((p->next)&&(index<n-1)){
p=p->next;
index++;
}
/*检查我们要删除结点是否存在*/
if(!p->next||(index>n-1)){
return false;
}
/*到此处就说明要删除节点是存在的,并且通过上面的while循环我们呢已经找到了要删除的节点的上一个结点p*/
/*现在我们就可以进行删除操作了,
首先我们用q来保存我们即将要删除的结点;p是我们要删除的节点的上一个节点,那么p->next就是指向下一个节点,也就是我们要删除的节点*/
q=p->next;
/*现在我们就将我们要删除的上一个结点的指针域中保存的地址改为我们要删除节点的下一个节点的 地址*/
p->next=q->next;
/"将我们要删除结点占用的内存释放掉!"/
delete q;
/"删除操作成功!返回!"/
return true;
}
int main(void){
LinkList* L=NULL;
LinkNode* S=NULL;
int n,v,n1,v1,n2;
//删除指定位置的元素
printf("请输入要删除的元素位置n2:");
scanf("%d",&n2);
delete__LinkList(L,n2);
Printf_LinkList(L);
system("pause");
return 0;
}
单链表的查找(这个大家就领悟一下咯!原理和上面的一样的!)
#include<stdio.h>
#include<iostream>
typedef struct _LinkList{
int date; //数据域
struct _LinkList *next; //指针域
}LinkList,LinkNode;
//查找元素(按值查找)
bool findValue__LinkList(LinkList* &L,int v3){
if(!L) return false;
LinkList* temp=NULL;
temp=L;
int i=0,j=0;
while(temp){
if(temp->date==v3){
printf("元素出现在第:\t%d个位置\n",i);
j++;
}
temp=temp->next;
i++;
}
if(j==0){
printf("你查找的元素不存在!\n");
}
return true;
}
int main(void){
LinkList* L=NULL;
LinkNode* S=NULL;
int n,v,n1,v1,n2,v3;
//单链表的查找,结果要返回元素的位置(按值查找)
printf("请输入要查找元素的值的v3:");
scanf("%d",&v3);
if(findValue__LinkList(L,v3)){
printf("查找操作成功!");
}else{
printf("查找操作失败!");
}
system("pause");
return 0;
}
单链表的销毁(这个大家就领悟一下咯!原理和上面的一样的!)
#include<stdio.h>
#include<iostream>
typedef struct _LinkList{
int date; //数据域
struct _LinkList *next; //指针域
}LinkList,LinkNode;
//单链表的销毁
bool destory__LinkList(LinkList* &L){
if(!L) return false;
LinkList* temp=L;
while(temp){
L=L->next;
delete temp;
temp=L;
}
return true;
}
int main(void){
//单链表的销毁
destory__LinkList(L);
Printf_LinkList(L);
system("pause");
return 0;
}