单链表的基本操作(c++)
文章目录
一、定义
-
单链表是一种链式存取的数据结构,用一组地址任意的储存单元存放线性表中的数据元素。
-
链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) +指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
PS:单链表中可以没有头结点,但是不能没有头指针!数据结构定义:
typedef struct Node { int data; //数据域 struct Node *next; //指针域 } LNode, *LinkList;
二、基本操作。
1、初始化线性表
//初始化线性表
void InitList(LinkList &L)
{
L =(LinkList) malloc(sizeof(LinkList));//创建头结点
L->next = NULL;
}
2、判断线性表是否为空表
//判断线性表是否为空表
bool EmptyList(LinkList &L)
{
return (L->next==NULL);
}
3、销毁线性表
//销毁线性表
void DestoryList(LinkList &L)
{
LNode *pre = L ,*p = L->next;//pre指向p的前驱结点
while (p != NULL)//扫描链表
{
free(pre);//释放前驱结点
//两者同时向后移动
pre = p;
p = p->next;
}//到结尾时,尾指针的值为空,但是前驱结点没有删除。
free(pre);
}
4、求线性表的长度
//求线性表的长度
int ListLength(LinkList &L)
{
int n = 0;
LNode *p = L;
while (p!=NULL)
{
n++;
p = p->next;
}
return n ;
}
5、链表中插入数据
//在第i个位置上插入元素e。
void InsList(LinkList &L, int i, ElemType e)
{
LNode *pre, *s; //pre表示第i-1个结点。
int k = 0;
pre = L; //pre指向表头指针。一般都是要由头结点向后面找。
while (pre != NULL && k < i - 1)
{ //从头结点找到pre结点指向的位置。
pre = pre->next; //往后面移动一个位置。
k = k + 1;
}
if (k != i - 1)
{
printf("插入位置不合理");
return;
}
//创建新的结点。
s = new Node;
s->data = e;
s->next = pre->next;
pre->next = s;
}
6、删除指定位置上的元素
//删除i位置上的元素,并赋值给e
bool ListDelete(LinkList &L,int i ,ElemType &e)
{
int j = 0;LNode *p=L,*q;
if (i<0)
{
return false;
}
while (j<i-1 && p!=NULL)//查找第i-1个结点
{
j++;
p = p->next;
}
if (p==NULL)
{
return false;
}else
{ //找到第i-1个结点
q = p->next;//q指向第i个结点。
if (q==NULL)
{
return false;
}
e = q->data;
p->next = q->next;
free(q);
return true;
}
}
7、按元素值进行查找
//按元素值进行查找
int LocateElem(LinkList &L, ElemType e)
{
int i = 1;
LNode *p= L->next;
while (p!=NULL&&p->data!=e)
{
p = p->next;
i++;
}
if (p==NULL)//遍历完L,但是还是没有找到元素e。
{
return 0 ;
}else
{
return i ;
}
}
8、找元素第一次出现的位置
//按元素值进行查找
int LocateElem(LinkList &L, ElemType e)
{
int i = 1;
LNode *p= L->next;
while (p!=NULL&&p->data!=e)
{
p = p->next;
i++;
}
if (p==NULL)//遍历完L,但是还是没有找到元素e。
{
return 0 ;
}else
{
return i ;
}
}
9、求指定位置上的元素值
//求线性表中第i个位置的数据元素,并赋值给e
bool GetElem(LinkList &L,ElemType i, ElemType &e)
{
int j = 0;
LNode *p= L;//值指向头结点
if (i<0)
{
while (j<i&&p!=NULL)//从头结点往共勉遍历所有的元素。
{
j++;
p = p->next;
}
if (p==NULL)
{
return false;
}
else
{
e = p->data;
return true;
}
}
return true;
}
10、打印单链表
//打印线性表
void DispList(LinkList &L)
{
LNode *p = L->next;
while (p!=NULL)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");//换行
}
11、头插法创建单链表(输出与数组顺序相反)
//头插法建立单链表。
LinkList CreatFromHead(int arr[] , int n)
{
LinkList L; //初始化一张空表
LNode *s; //用来指向新的结点。
int i=0;
//设置头结点
L =(LNode *) malloc(sizeof(LNode));
L->next = NULL; //头结点的指针域为空。
while (i<n)
{
s =(LNode *) malloc(sizeof(LNode)); //新结点
s->data = arr[i]; //赋值给新节点
s->next = L->next; //头结点的指针域赋值给S的指针域。这时s的指针域为空
L->next = s; //头指针的指针域指向s结点。
i++;
}
//返回头结点。
return L;
}
12、尾插法创建单链表(输出与数组顺序相同)
//尾插法创建单链表
LinkList CreatFormEnd(int arr[] , int n)
{
//初始化一张空表
LinkList L;
//创建s结点,用来装新的结点
LNode *s, *r;
int i=0;
//设置头结点
L = new LNode;
L->next = NULL;
r = L;
while (i<n)
{
s = new LNode;
s->data = arr[i];
s->next = r->next;
r->next = s;
//把r变为尾指针
r = s;
i++;
}
//把r的指针域赋值为空
r->next = NULL;
return L;
}
三、常用算法。
1、单链表的排序(采用冒泡排序)
void bubbleSort(LinkList &mylist)
{
if((mylist -> next == NULL) || (mylist -> next -> next == NULL))
{
return;
}
LNode *head, * pre, * cur, *next, * end, * temp;
head = mylist;
end = NULL;
//从链表头开始将较大值往后沉
while(head -> next != end)
{
for(pre = head, cur = pre -> next, next = cur -> next; next != end; pre = pre -> next, cur = cur -> next, next = next -> next)
{
//相邻的节点比较
if(cur ->data > next -> data)
{
cur -> next = next -> next;
pre -> next = next;
next -> next = cur;
temp = next;
next = cur;
cur = temp;
}
}
end = cur;
}
}
2、删除第一个出现的指定元素
//删除带头结点的非空单链表L中第一个值为x的结点
int DelFirstX(LinkList &L ,ElemType x)
{
LNode *p = L->next ,*pre = L;
while (p !=NULL && p->data != x)
{
pre = p;//往后移动。
p = p->next;
}
if (p == NULL)
{
return 0;//遍历完整个链表没有找到x
}
//删除结点
pre->next = p->next;
free(p);
return 1;
}
3、删除最大元素所在结点
//删除最大元素所在结点。
void delMaxNode(LNode *&L)
{
LNode *p = L->next;//p指向当前结点
LNode *pre = L;//p的前驱结点
LNode *max = p;//最大值的结点
LNode *maxpre = pre;//最大值的前驱结点
while (p != NULL) //用p扫描整个单链表
{
if (max->data < p->data)// 若找到一个更大的节点
{
max = p;// 更新max
maxpre = pre;// 更新maxpre
}
//p和pre往后移动一个结点
pre = pre->next;
p = p->next;
}//删除最大值结点
maxpre->next = max->next;
free(max);
}
4、数组左边存负数,右边存正数
void moveInt(LinkList &L)
{
LNode *p= L->next,*pre=L;
while (p!=NULL&&p->data<0)//跳过小于0的结点
{
pre= p;p = pre->next;//两个结点都后移
}
while (p!=NULL)
{
if(p->data<0)//负数存在左边
{
pre->next = p->next;
p->next = L->next;//头插法插入p结点
L->next = p;
p = pre->next;
}
else
{
pre=p;p=p->next;
}
}
}
4、逆转单链表
//采用头插法逆转一个链表
LinkList Reserve(LinkList &L)
{
LNode *p,*q;
//创建一个辅助链表
LinkList T = (LinkList)malloc(sizeof(LNode));
T->next = NULL;
p = L->next;
q = T->next;
while (p!=NULL)
{//创建一个新节点作为中间结点,把L中的值赋给T。
LNode *s =(LNode *) malloc(sizeof(LNode));
s->data = p->data;
s->next = q->next;
q->next = s;
q = q->next;
free(p);
}
return T;
}
5、奇偶顺序问题
void split1(LinkList &A ,LinkList &B)
{
B=(LNode*)malloc(sizeof(LNode));//给B链表申请空间来装奇数点
B->next=NULL;
LNode *r=B;
LNode *p=A;
LNode *q;//作为中间结点
while(p->next!=NULL){
if(p->next->data%2==1){
//把p的下一个结点转移到q上
q=p->next;
p->next=q->next;
q->next=NULL;
r->next=q;//q移动到r上。
r=q;
}else{
p=p->next;
}
}
}
四、主函数
int main()
{
LinkList L = (LinkList)malloc(sizeof(LinkList));
InitList(L);
int arr[10]={1,3,2,2,0,4,7,6,5,8};
L= CreatFromHead(arr,10);
// L = CreatFormEnd(arr,10);
DispList(L);
return 0;
}
4.1全部代码
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct Node
{
int data; //数据域
struct Node *next; //指针域
} LNode, *LinkList;
//采用头插法逆转一个链表
LinkList Reserve(LinkList &L)
{
LNode *p,*q;
//创建一个辅助链表
LinkList T = (LinkList)malloc(sizeof(LNode));
T->next = NULL;
p = L->next;
q = T->next;
while (p!=NULL)
{//创建一个新节点作为中间结点,把L中的值赋给T。
LNode *s =(LNode *) malloc(sizeof(LNode));
s->data = p->data;
s->next = q->next;
q->next = s;
q = q->next;
free(p);
}
return T;
}
//删除最大元素所在结点。
void delMaxNode(LNode *&L)
{
LNode *p = L->next;//p指向当前结点
LNode *pre = L;//p的前驱结点
LNode *max = p;//最大值的结点
LNode *maxpre = pre;//最大值的前驱结点
while (p != NULL) //用p扫描整个单链表
{
if (max->data < p->data)// 若找到一个更大的节点
{
max = p;// 更新max
maxpre = pre;// 更新maxpre
}
//p和pre往后移动一个结点
pre = pre->next;
p = p->next;
}//删除最大值结点
maxpre->next = max->next;
free(max);
}
//按元素值进行查找
int LocateElem(LinkList &L, ElemType e)
{
int i = 1;
LNode *p= L->next;
while (p!=NULL&&p->data!=e)
{
p = p->next;
i++;
}
if (p==NULL)//遍历完L,但是还是没有找到元素e。
{
return 0 ;
}else
{
return i ;
}
}
//单链表中删除元素
void DelList(LinkList &L, int i, ElemType *e)
{
LNode *pre, *r; //R用来储存i位置上的结点
pre = L;
int k = 0;
//找到i结点的前一个结点。
while (pre->next != NULL && k < i - 1)
{ //后移一个位置
pre = pre->next;
k = k + 1;
}
if (k != i - 1)
{
printf("删除的结点的位置i不合理");
return;
}
r = pre->next;
pre->next = pre->next->next;
free(r);
}
//求线性表中第i个位置的数据元素,并赋值给e
bool GetElem(LinkList &L,ElemType i, ElemType &e)
{
int j = 0;
LNode *p= L;//值指向头结点
if (i<0)
{
while (j<i&&p!=NULL)//从头结点往共勉遍历所有的元素。
{
j++;
p = p->next;
}
if (p==NULL)
{
return false;
}
else
{
e = p->data;
return true;
}
}
return true;
}
//打印线性表
void DispList(LinkList &L)
{
LNode *p = L->next;
while (p!=NULL)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");//换行
}
//求线性表的长度
int ListLength(LinkList &L)
{
int n = 0;
LNode *p = L;
while (p!=NULL)
{
n++;
p = p->next;
}
return n ;
}
//判断线性表是否为空表
bool EmptyList(LinkList &L)
{
return (L->next==NULL);
}
//销毁线性表
void DestoryList(LinkList &L)
{
LNode *pre = L ,*p = L->next;//pre指向p的前驱结点
while (p != NULL)//扫描链表
{
free(pre);//释放前驱结点
//两者同时向后移动
pre = p;
p = p->next;
}//到结尾时,尾指针的值为空,但是前驱结点没有删除。
free(pre);
}
//初始化线性表
void InitList(LinkList &L)
{
L =(LinkList) malloc(sizeof(LinkList));//创建头结点
L->next = NULL;
}
//链表中插入数据
void InsList(LinkList &L, int i, ElemType e)
{
LNode *pre, *s; //pre表示第i-1个结点。
int k = 0;
pre = L; //pre指向表头指针。一般都是要由头结点向后面找。
while (pre != NULL && k < i - 1)
{ //从头结点找到pre结点指向的位置。
pre = pre->next; //往后面移动一个位置。
k = k + 1;
}
if (k != i - 1)
{
printf("插入位置不合理");
return;
}
//创建新的结点。
s = new Node;
s->data = e;
s->next = pre->next;
pre->next = s;
}
//删除数据元素x
bool ListDelete(LinkList &L,int i ,ElemType &e)
{
int j = 0;LNode *p=L,*q;
if (i<0)
{
return false;
}
while (j<i-1 && p!=NULL)//查找第i-1个结点
{
j++;
p = p->next;
}
if (p==NULL)
{
return false;
}else
{ //找到第i-1个结点
q = p->next;//q指向第i个结点。
if (q==NULL)
{
return false;
}
e = q->data;
p->next = q->next;
free(q);
return true;
}
}
//插入数据元素,插入第i个元素为e
bool ListInsert(LinkList &L, int i ,ElemType e)
{
int j = 0;
LNode *p = L ,*s;
if (i<0) return false;//插入位置不合理。
while (j<i-1 && p!=NULL)
{
j++;
p = p->next;
}
if (p==NULL)
{
return false;
}else //找到第i-1个结点p,插入新节点
{
s= (LinkList) malloc(sizeof(LinkList));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
}
//尾插法创建单链表
LinkList CreatFormEnd(int arr[] , int n)
{
//初始化一张空表
LinkList L;
//创建s结点,用来装新的结点
LNode *s, *r;
int i=0;
//设置头结点
L = new LNode;
L->next = NULL;
r = L;
while (i<n)
{
s = new LNode;
s->data = arr[i];
s->next = r->next;
r->next = s;
//把r变为尾指针
r = s;
i++;
}
//把r的指针域赋值为空
r->next = NULL;
return L;
}
//删除带头结点的非空单链表L中第一个值为x的结点
int DelFirstX(LinkList &L ,ElemType x)
{
LNode *p = L->next ,*pre = L;
while (p !=NULL && p->data != x)
{
pre = p;//往后移动。
p = p->next;
}
if (p == NULL)
{
return 0;//遍历完整个链表没有找到x
}
//删除结点
pre->next = p->next;
free(p);
return 1;
}
void split1(LinkList &A ,LinkList &B)
{
B=(LNode*)malloc(sizeof(LNode));//给B链表申请空间来装奇数点
B->next=NULL;
LNode *r=B;
LNode *p=A;
LNode *q;//作为中间结点
while(p->next!=NULL){
if(p->next->data%2==1){
//把p的下一个结点转移到q上
q=p->next;
p->next=q->next;
q->next=NULL;
r->next=q;//q移动到r上。
r=q;
}else{
p=p->next;
}
}
}
//头插法建立单链表。
LinkList CreatFromHead(int arr[] , int n)
{
LinkList L; //初始化一张空表
LNode *s; //用来指向新的结点。
int i=0;
//设置头结点
L =(LNode *) malloc(sizeof(LNode));
L->next = NULL; //头结点的指针域为空。
while (i<n)
{
s =(LNode *) malloc(sizeof(LNode)); //新结点
s->data = arr[i]; //赋值给新节点
s->next = L->next; //头结点的指针域赋值给S的指针域。这时s的指针域为空
L->next = s; //头指针的指针域指向s结点。
i++;
}
//返回头结点。
return L;
}
//线性表的排序,采用冒泡排序,直接遍历链表
void sort(int arr[],int n)
{
for (int i = 0; i < n; i++)
for (int j = 0; i < n-i-1; j++)
{
if (arr[j]>arr[j+1])
{
int temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;
}
}
}
void moveInt(LinkList &L)
{
LNode *p= L->next,*pre=L;
while (p!=NULL&&p->data<0)//跳过小于0的结点
{
pre= p;p = pre->next;//两个结点都后移
}
while (p!=NULL)
{
if(p->data<0)
{
pre->next = p->next;
p->next = L->next;//头插法插入p结点
L->next = p;
p = pre->next;
}
else
{
pre=p;p=p->next;
}
}
}
void bubbleSort(LinkList &mylist)
{
if((mylist -> next == NULL) || (mylist -> next -> next == NULL))
{
return;
}
LNode *head, * pre, * cur, *next, * end, * temp;
head = mylist;
end = NULL;
//从链表头开始将较大值往后沉
while(head -> next != end)
{
for(pre = head, cur = pre -> next, next = cur -> next; next != end; pre = pre -> next, cur = cur -> next, next = next -> next)
{
//相邻的节点比较
if(cur ->data > next -> data)
{
cur -> next = next -> next;
pre -> next = next;
next -> next = cur;
temp = next;
next = cur;
cur = temp;
}
}
end = cur;
}
}
int main()
{
LinkList L = (LinkList)malloc(sizeof(LinkList));
InitList(L);
int arr[10]={1,3,2,2,0,4,7,6,5,8};
L= CreatFromHead(arr,10);
// L = CreatFormEnd(arr,10);
DispList(L);
return 0;
}