一、单向链表介绍
单向链表是一种常见的数据结构,它由一系列节点组成,每个节点包含一个数据域和一个指向下一个节点的指针域。
-
结构特点:
- 单向链表的节点通过指针链接在一起,形成一个线性的数据结构。
- 链表的头节点通常是一个特殊的节点,它不存储实际的数据,只用于指向链表的第一个存储数据的节点。
- 每个节点的指针指向下一个节点,最后一个节点的指针为
NULL
,表示链表的结束。
-
优点:
- 动态内存分配:可以根据需要动态地添加和删除节点,不需要预先确定链表的大小。
- 插入和删除操作高效:在链表中间插入或删除节点只需要修改几个指针,时间复杂度为 O ( 1 ) O(1) O(1)(在已知插入或删除位置的情况下)。
-
缺点:
- 随机访问困难:不像数组可以通过下标直接访问元素,在链表中访问特定位置的元素需要从头节点开始遍历,时间复杂度为 O ( n ) O(n) O(n)。
-
常见操作:
- 初始化:创建一个空链表,通常包括创建头节点并将其指针域设置为
NULL
。 - 插入节点:可以在链表的头部、尾部或特定位置插入新节点。
- 删除节点:根据给定的条件删除链表中的节点。
- 查找节点:在链表中查找具有特定值的节点。
- 遍历链表:从头到尾遍历链表,访问每个节点的数据。
- 初始化:创建一个空链表,通常包括创建头节点并将其指针域设置为
二、代码总结
这段 C++代码实现了一个单向链表的多种操作,包括初始化、插入、删除、查找、排序、合并和逆置等功能。
-
功能模块:
- 初始化和销毁:
LinkedListInit
函数用于初始化一个空链表,创建头节点并分配内存。LinkedListDestroy
函数用于销毁链表,释放每个节点的内存空间。LinkedListClear
函数用于置空链表,删除链表中的所有节点,但保留头节点。
- 插入操作:
LinkedListAddHead
函数实现头插法,在链表头部插入新节点。LinkedListAddTail
函数实现尾插法,在链表尾部插入新节点。LinkedListInsert
函数按序号在链表中插入新节点。
- 删除操作:
LinkedListDelete
函数按序号删除链表中的节点。
- 查找操作:
LinkedListFind
函数按值在链表中查找节点。
- 打印操作:
LinkedListPrint
函数用于打印链表中的所有节点。
- 排序操作:
LinkedListSort
函数实现冒泡排序,对链表中的节点进行排序。
- 合并操作:
LinkedListMerge
函数将两个有序链表合并为一个有序链表。
- 逆置操作:
LinkedListReverse
函数实现链表的原地逆置。
- 初始化和销毁:
-
整体流程:
- 在
main
函数中,首先初始化两个链表L1
和L2
,分别通过头插法和尾插法创建链表。 - 然后对
L2
进行插入和删除操作,对L1
进行插入和删除操作。 - 接着对
L1
和L2
进行排序。 - 之后创建一个新的链表
MergeList
,并将L1
和L2
合并到MergeList
中。 - 最后在
MergeList
中查找特定值,并对MergeList
进行原地逆置操作。 - 最后销毁所有链表,释放内存。
- 在
下列是我的代码演示
#include<bits/stdc++.h>
using namespace std;
#define MAXSIZE 100
#define OVERFLOw -2
#define OK 1
#define ERROR 0
typedef int Status;
typedef int eleType;
typedef struct LNode {
eleType data;
struct LNode *next;
} LNode, *LinkList;
/*
初始化一个空链表 OK
链表的置空和销毁 OK
前插法建表、后插法建表 OK
能够在链表中实现元素的查找、插入和删除 OK
能够输出链表的全部元素 OK
链表元素的排序及有序链表的合并(选做) OK
链表的原地逆置(选做) OK
*/
//初始化一个空链表
Status LinkedListInit(LinkList &L){
L = new LNode;
if(!L) exit(OVERFLOw);
L->next = NULL;
return OK;
}
//链表的销毁
Status LinkedListDestroy(LinkList &L){
while(L){
LinkList temp = L;
L = L->next;
delete temp;
}
return OK;
}
//链表的置空
Status LinkedListClear(LinkList &L){
LinkList p = L->next;
while(p){
LinkList temp = p;
p = p->next;
delete temp;
}
L->next = NULL;
return OK;
}
//头 插 法
void LinkedListAddHead(LinkList &L,eleType value){
LNode * newNode = new LNode;
newNode->data = value;
newNode ->next = L->next;
L->next = newNode ;
}
//尾 插 法
void LinkedListAddTail(LinkList &L, eleType value) {
LNode* p = L;
LNode* newNode = new LNode;
newNode->data = value;
while (p->next!= NULL) {
p = p->next;
}
newNode->next = p->next;
p->next = newNode;
}
//按值查找
LNode * LinkedListFind(LinkList &L,eleType value) {
LNode * p = L->next;
int i = 1;
while(p){
if(p->data==value){
cout<<"在链表中找到 "<<value<<",位置在第"<<i<<"个处"<<endl<<endl;
return p;
}
p=p->next;
i++;
}
cout<<"没找到"<<value<<endl<<endl;
return p;
}
//按序号 插 入
Status LinkedListInsert(LinkList &L,int index,eleType value){
LNode * p = L ;
LNode * NewNode = new LNode;
NewNode ->data = value;
int i = 0;
while(i<index-1){
p = p->next;
i++;
}
NewNode->next = p->next;
p->next = NewNode;
cout<<"成功将元素:"<<value<<" 插 在第 "<<index<<" 个元素处"<<endl;
return OK;
}
//元素 删除
Status LinkedListDelete(LinkList &L,int index){
if (index == 0) {
L->next = L->next->next;
cout<<"成功 删除 第"<<index<<"个元素"<<endl;
return OK;
}
int i = 0;
LNode * p = L;
while(i<index-1 && p->next){
p = p->next;
i++;
}
if(!(p->next) || i>index-1) return ERROR;
LNode* temp = p->next;
p->next = p->next->next;
cout<<"成功 删除 第"<<index<<"个元素: "<<temp->data<<endl;
delete temp;
return OK;
}
//打印链表
void LinkedListPrint(LinkList &L){
LNode* p = L->next;
while(p){
cout<<p->data<<"->";
p = p->next;
}
cout<<"NULL"<<endl<<endl;
}
//链表的排序(冒泡排序)
void LinkedListSort(LinkList &L){
if(L==NULL||L->next==NULL) return ;//没有元素或者只有一个元素
bool swapped;//看是否完成交换 当swapped为false时代表排序OK
LNode * ptr ;//游离 遍历 交换
LNode * lptr = NULL;//已经交换过的
do{
//每一次排序把未排序过的最大的放到了最后面
//更新指针为排好序的元素的头一个节点
swapped = false;
ptr = L->next;//从头节点开始
while(ptr->next!=lptr)//不到最后一个未排序的元素
{
if(ptr->data > ptr->next->data){
//交换
eleType temp = ptr->next->data;
ptr->next->data = ptr->data;
ptr->data = temp;
swapped = true;
}
ptr = ptr->next;
}
lptr = ptr;
}while(swapped);
}
// 有序链表的合并
void LinkedListMerge(LinkList L1, LinkList L2, LinkList& result) {
LNode* p1 = L1->next; // 指向 L1 头节点
LNode* p2 = L2->next; // 指向 L2 头节点
while (p1 && p2) {
if (p1->data < p2->data) {
LinkedListAddTail(result,p1->data);
p1=p1->next;
} else if (p2->data < p1->data) {
LinkedListAddTail(result,p2->data);
p2 = p2->next;
} else {
LinkedListAddTail(result,p1->data);
p1 = p1->next;
p2 = p2->next;
}
}
while (p1) {
LinkedListAddTail(result,p1->data);
p1=p1->next;
}
while (p2) {
LinkedListAddTail(result,p2->data);
p2 = p2->next;
}
}
// 首节点↓
//链表的原地逆置(适用于带头节点 即 L->①->②->③->…->NULL)
// 头节点↑
void LinkedListReverse(LinkList &L){
LNode * beg = L->next;//首节点
LNode * end = L->next->next;
while(end!=NULL){
beg->next = end->next;//连 连上后面的 以防调转的目标节点之后节点素丢失
end->next = L->next;//掉 掉转的目标节点的后继指向目前的首节点(目标节点将成为新的首节点)
L->next = end;//接 头节点的后继为新的首节点
end = beg->next;//移 end始终是beg后面一个节点
}
}
int main(){
LinkList L1;
LinkedListInit(L1);
LinkedListAddHead(L1,1);
LinkedListAddHead(L1,2);
LinkedListAddHead(L1,3);
LinkedListAddHead(L1,4);
LinkedListAddHead(L1,5);
cout<<"头 插 法得到L1 :"<<endl;
LinkedListPrint(L1);
LinkList L2;
LinkedListInit(L2);
LinkedListAddTail(L2,7);
LinkedListAddTail(L2,6);
LinkedListAddTail(L2,5);
LinkedListAddTail(L2,4);
LinkedListAddTail(L2,3);
cout<<"尾 插 法得到L2 :"<<endl;
LinkedListPrint(L2);
cout<<"对L2进行操作: ";
LinkedListInsert(L2,1,36);
LinkedListPrint(L2);
cout<<"对L2进行操作: ";
LinkedListDelete(L2,4);
LinkedListPrint(L2);
cout<<"对L1进行操作: ";
LinkedListInsert(L1,3,17);
LinkedListPrint(L1);
cout<<"对L1进行操作: ";
LinkedListDelete(L1,3);
LinkedListPrint(L1);
LinkedListSort(L1);
cout<<"排序后的 L1:";
LinkedListPrint(L1);
LinkedListSort(L2);
cout<<"排序后的 L2:";
LinkedListPrint(L2);
cout<<"L1 L2 合并后 得 MergeList : "<<endl;
LinkList MergeList ;
LinkedListInit(MergeList);
LinkedListMerge(L1,L2,MergeList);
LinkedListPrint(MergeList);
cout<<"对MergeList进行操作: ";
LinkedListFind(MergeList,5);
cout<<"MergeList 原地逆置后"<<endl;
LinkedListReverse(MergeList);
LinkedListPrint(MergeList);
LinkedListDestroy(L1);
LinkedListDestroy(L2);
LinkedListDestroy(MergeList);
return 0;
}
运行结果如下