线性表之单链表(C++/C)
1 基本操作
声明部分:
#include <cstdlib>
#include "stdio.h"
#define ElemType int
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
1.//初始化单链表
//不带头结点的单链表
bool InitList(LinkList &L)
//初始化单链表
//***带**头结点的单链表
bool InitListWithHead(LinkList &L)
//后插操作: 在p节点之后插入元素
bool InsertNextNode(LNode*p,ElemType e)
//前插操作 在p节点之前插入e
bool InsertPriorNode(LNode*p,ElemType e)
// 删除节点p的方法1 时间复杂度为O(n)
bool DeleteNode(LNode *p)
//删除节点p的方法2 时间复杂度为O(1) 原理 :你想删除我节点p,我把q节点的东西都拿来了(继承) 你去删q吧 其中 q为p的下一节点
bool DeleteNodePlus(LNode *p)
//按位查找
LNode *GetElem(LinkList L,int i)
//求表长
int ListLength(LinkList L)
//在第i个位置插入元素e 带头结点 尾插法
bool ListInsetWithHead(LinkList &L,int i,ElemType e)
//按位序插入 不带头结点
bool ListInset(LinkList &L,int i,ElemType e)
//按位序删除 带头节点
bool ListDeleteWithHead(LinkList &L,int i,ElemType &e)
//尾插法建立单链表 用户输入
LinkList List_TailInsert(LinkList &L)
//判断单链表是否为空
bool isEmpty(LinkList L)
//头插法 每次都插在头结点之后
//后插操作:在p接待之后 插入元素e
LinkList List_HeadInsert(LinkList &L)
void LinkListShow(LinkList L)
2.特别说明
//前插操作 在p节点之前插入e
bool InsertPriorNode(LNode*p,ElemType e)
在该函数中:特别说明如下:
3.主函数
int main(){
LinkList L;
ElemType e;
InitList(L);
List_HeadInsert(L);
printf("The length of the LinkList is %d\n",ListLength(L));
LinkListShow(L);
if (ListDeleteWithHead(L,3,e))
printf("The Node which was delete is %d\n",e);
else
printf("Fail to delete Node ");
LinkListShow(L);
if(ListInset(L,2,8))
printf("Insert position 2 successfully \n");
else
printf("Fail to insert !\n");
LinkListShow(L);
return 0;
}
4.运行结果
5.源代码
#include <cstdlib>
#include "stdio.h"
#define ElemType int
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//初始化单链表
//不带头结点的单链表
bool InitList(LinkList &L){
L=NULL;
return true;
}
//初始化单链表
//***带**头结点的单链表
bool InitListWithHead(LinkList &L){
L=(LNode*)malloc(sizeof(LNode)); //分配一个头结点
if (L==NULL)
return false;
L->next=NULL;
return true; //头结点之后 暂时还没有节点
}
//后插操作: 在p节点之后插入元素
bool InsertNextNode(LNode*p,ElemType e){
if (p==NULL)
return false;
LNode *s=(LNode*)malloc(sizeof(LNode));
if (s==NULL)
return false;
s->data=e;
s->next=p->next;
p->next=s; //将s节点连接到p之后
return true;
}
//前插操作 在p节点之前插入e
bool InsertPriorNode(LNode*p,ElemType e){
if (p==NULL)
return false;
LNode *s=(LNode*)malloc(sizeof(LNode));
if (s==NULL)
return false;
s->next=p->next; //此处应该这么理解: 1.首先 ‘=’ 既可以理解为赋值 ***也可以理解为 ‘指向’ 原本是p-->下一个节点q 此时虽然称为前插法 但是 但是 我们依旧把s节点放在中间;
//原本你p的next是要指向q的 现在我毕竟插入了一个s 那我就用s的next 指向 p->next 即下一个节点 q;
p->next=s; //注意 我们确实声明 并且给了s节点内存空间 但是 它里面的值 依旧是不确定的 你可以理解为NULL; 既然上一步 你把p->next赋值给了别人 那么我就将s赋值给p->next 就是让p->next你下一次 指向s;
s->data=p->data; //原来即便s.data中有一个不确定的值 那那那 我就把p里面的值 给你s节点 这样 s就把 p节点的所有东西给继承过来了;
p->data=e; //反正 一开始我e就没赋值给过其他人 现在反正你p->data的值都给 s了 那 e就给p节点的data 有感情 --那味了!
//如此看来 是不是 有点像 s 和p 节点互换了位置 此称为前插法
return true;
}
// 删除节点p的方法1 时间复杂度为O(n)
bool DeleteNode(LNode *p){
if (p==NULL)
return false;
// if (p->next==NULL)
// return false;
LNode *q=p->next; //令q指向被删除的节点
p->next=q->next; //将*q节点从链中断开
free(q);
return true;
}
//删除节点p的方法2 时间复杂度为O(1) 原理 :你想删除我节点p,我把q节点的东西都拿来了(继承) 你去删q吧 其中 q为p的下一节点
bool DeleteNodePlus(LNode *p){
if (p==NULL)
return false;
LNode *q=p->next; //令q指向被删除的节点
p->data=p->next->data; //和后继节点交换数据域
p->next=q->next; //将*q节点从链中断开
free(q);
return true;
}
//按位查找
LNode *GetElem(LinkList L,int i){
LNode *p; //指针p指向当前扫描到的节点
int j=0; //当前p指向的是第几个节点
p=L; //L指向头节点 头结点是第0个节点 不存数据
while (p!=NULL&&j<i-1){ //循环找不到第i-1个节点
p=p->next;
j++;
}
return p;
}
//求表长
int ListLength(LinkList L){
int length=0;
LNode *p=L;
while (p->next !=NULL){
p=p->next;
length++;
}
return length;
}
//在第i个位置插入元素e 带头结点 尾插法
bool ListInsetWithHead(LinkList &L,int i,ElemType e){
if (i<1){
return false;
}
LNode *p; //指针p指向当前扫描到的节点
int j=0; //当前p指向的是第几个节点
p=L; //L指向头节点 头结点是第0个节点 不存数据
while (p!=NULL&&j<i-1){ //循环找不到第i-1个节点
p=p->next;
j++;
}
return InsertNextNode(p,e);
}
//按位序插入 不带头结点
bool ListInset(LinkList &L,int i,ElemType e){
if (i<1){
return false;
}
if (i==1){ //插入第一个节点会与其他节点的操作不同
LNode *s=(LNode*)malloc(sizeof(LNode));
s->data=e;
s->next=L;
L=s; //头指针指向 新插入的节点
return true;
}
LNode *p; //指针p指向当前扫描到的节点
int j=0; //当前p指向的是第几个节点
p=L; //L指向头节点 头结点是第0个节点 不存数据
while (p!=NULL&&j<i-1){ //循环找不到第i-1个节点
p=p->next;
j++;
}
return InsertNextNode(p,e);
}
//按位序删除 带头节点
bool ListDeleteWithHead(LinkList &L,int i,ElemType &e){
if (i<1)
return false;
LNode *p;
int j=0;
p=L; //L指向头结点 头结点是第0个节点 不存数据
while (p!=NULL&j<i-1){
p=p->next;
j++;
}
if (p==NULL)
return false;
if (p->next==NULL)
return false;
LNode *q=p->next; //令q指向被删除的节点
e=q->data;
p->next=q->next; //将*q节点从链中断开
free(q);
return true;
}
//尾插法建立单链表 用户输入
LinkList List_TailInsert(LinkList &L){
ElemType x;
L=(LinkList)malloc(sizeof(LNode)); //建立头结点
LNode*s,*r=L; //r为表位指针
scanf("%d",&x);
while (x!='#'){
s=(LNode*)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s; //r指向新的表尾节点 r让其永远指向最后一个节点
scanf("%d",&x);
}
r->next=NULL; //尾节点r指针置空
return L;
}
//判断单链表是否为空
bool isEmpty(LinkList L){
if (L==NULL)
return true;
else
return false;
}
//头插法 每次都插在头结点之后
//后插操作:在p接待之后 插入元素e
LinkList List_HeadInsert(LinkList &L){
ElemType x;
L=(LinkList)malloc(sizeof(LNode)); //建立头结点
LNode*s;
L->next=NULL;
scanf("%d",&x);
while (x!=9999){
s=(LNode*)malloc(sizeof(LNode));
s->data=x;
s->next=L->next;
L->next=s; //将新节点插入表中 L为头指针
scanf("%d",&x);
}
return L;
}
void LinkListShow(LinkList L){
if (!L)
printf("The LinkList is Null !");
else
{
printf("The data of the LinkList are\n");
LNode *p=L->next;
while (p) {
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
}
int main(){
LinkList L;
ElemType e;
InitList(L);
List_HeadInsert(L);
printf("The length of the LinkList is %d\n",ListLength(L));
LinkListShow(L);
if (ListDeleteWithHead(L,3,e))
printf("The Node which was delete is %d\n",e);
else
printf("Fail to delete Node ");
LinkListShow(L);
if(ListInset(L,2,8))
printf("Insert position 2 successfully \n");
else
printf("Fail to insert !\n");
LinkListShow(L);
return 0;
}