前言:
链表的排序与顺序表相比是有些不同的。
原因是数据结构不同,
顺序表的实现可以看做是一个大数组,数组的各个元素有且只有数据。
而链表的节点却还有指向其他节点的指针部分。
如此,顺序表的排序只是将数据排序,而链表则也可以排序数据,也可以排序节点。
这里这里有一个实例,如果身边没有链表代码可以使用,可以直接Copy以下代码
(PS:这个链表的头结点是不存放数据的)
#ifndef LINKEDLIST_H_
#define LINKEDLIST_H_
#include "iostream"
using namespace std;
//这是一个简单的链表结构,有几个基础的方法
template <class T>
//节点结构
struct Node{
T data;
Node<T> *next;
};
//链表类
template <class T>
class Linklist{
private:
int len;
Node<T> *head;
public:
Linklist();
void AddItem(T data);
int length();
void showList();
//void SortASC();
};
template <class T>
Linklist<T>::Linklist()
{
head = new Node<T>();
head->data = 0;
head->next = NULL;
len = 0;
}
template <class T>
int Linklist<T>::length()
{
return len;
}
//插入方法------使用尾插的方式
template <class T>
void Linklist<T>::AddItem(T data)
{
Node<T> *temp = new Node<T>();
temp->data = data;
temp->next = NULL;
Node<T> *cursor = head;
while(cursor->next!=NULL){
cursor = cursor->next;
}
cursor->next = temp;
len++;
}
template <class T>
void Linklist<T>::showList()
{
Node<T> *cursor = head->next;
while(cursor!=NULL)
{
std::cout<<cursor->data<<","<<std::endl;
cursor=cursor->next;
}
}
#endif LINKEDLIST_H_
1.顺利的衔接顺序表,排序节点数据
顺序表的排序想必非常的熟悉,
比如冒泡排序,一种典型的稳定排序,是无数人的排序启蒙。
这里如果忘了,可以看一下下面的代码:
int arr[10] = {10,9,8,7,6,5,4,3,2,1};
for(int i = 0;i<10;i++)
{
for(int j = 0;j<9-i;j++)
{
if(arr[j]>arr[j+1])
{
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
for(int i = 0;i<10;i++)
{
cout<<arr[i]<<"|"<<endl;
}
如果选择改变链表的节点的数据部分来实现排序效果
则也可以把链表看做数组,
只不过是寻找节点的方式不同而已。
数组或者说是顺序表是通过下标
而链表是通过next指针
如果冒泡排序对你来说很简单,那链表的排序则也很简单。
照猫画虎可以得到以下代码
template <class T>
void Linklist<T>::SortASC()
{
if(len == 0)
return;
Node<T> *temp = head->next;
for(int i = 0;i<len;i++)
{
for(int j = 0;j<len-1-i;j++)
{
Node<T> *temp2 = head->next;
//找到链表的arr[j],
for(int k = 0;k<j;k++)
temp2 = temp2->next;
//相当于arr[j]>arr[j+1]
if((temp2->data)>(temp2->next->data))
{
T swap = temp2->data;
temp2->data = temp2->next->data;
temp2->next->data = swap;
}
}
}
}
把方法加到类中去,就可以测试一下了。
#include <iostream>
#include "linkedlist.h"
int main() {
Linklist<int> *list = new Linklist<int>();
list->AddItem(8);
list->AddItem(3);
list->AddItem(9);
list->AddItem(1);
list->SortASC();
list->showList();
}

2.通过交换节点的方式进行排序
链表节点的交换需要设计前驱,后驱指针的变换,
通俗一点说就是断开和拼接节点
这里有一点需要注意:
相邻节点的交换和不相邻节点的交换是不同的
相邻节点的交换情况,需要改动三次指针

再看看不相邻的节点交换。

不相邻的节点交换则更加复杂一些。需要修改四次Next指针,涉及的节点则至少5个。
故推荐奖交换节点单独封装为一个方法,稍微减少一些复杂度
故这里先放出怎么交换链表的节点
//交换链表中指定位置的节点,索引未从0开始算起
template <class T>
void Linklist<T>::Swap(int index, int index2)
{
bool isNext = false;
if(index>=len||index2>=len)
return;
else if(index<0||index2<0)
return;
//前驱节点
Node<T> *pre = head->next;
//
Node<T> *swaper = head->next;
Node<T> *swaper2 = head->next;
Node<T> *tail = head->next;
if((index2-index)==1)
isNext = true;
//相邻节点的交换-----
if(isNext)
{
//获取前驱指针
for(int i = 0;i<index-1;i++)
{
pre = pre->next;
}
//如果要交换的是第一个节点,则前驱需为头节点
if(index==0)
pre = head;
//获取要交换的节点的指针
swaper = pre->next;
//获取要交换的节点的指针
swaper2 = swaper->next;
//获取后驱节点
tail = swaper2->next;
//调整指针的指向,相邻节点需要三次
pre->next = swaper2;
swaper2->next = swaper;
swaper->next = tail;
}
else{
//非相邻节点的交换,请对比上面的图,对应相应的节点,
// 这样会比较好理解一点
//寻找前驱节点1的前驱
for(int i = 0;i<index-1;i++)
{
pre = pre->next;
}
//如果要交换的是第一个节点,则前驱需为头节点
if(index==0)
pre = head;
//要交换的节点1
swaper = pre->next;
//节点1的后驱
Node<T> *tail1 = swaper->next;
//获取节点2的前驱
Node<T> *pre2 = head->next;
for(int i = 0;i<index2-1;i++)
{
pre2 = pre2->next;
}
//获取节点2,
swaper2 = pre2->next;
//获取节点2的后驱
Node<T> *tail2 = swaper2->next;
//这里有一点需要注意,节点1的后驱和节点2的前驱可能为同一个节点
//不过并不妨碍
//节点交换的步骤
pre->next = swaper2;
swaper2->next = tail1;
swaper->next = tail2;
pre2->next = swaper;
}
}
先测试一下,交换的效果


成功了,现在我们把它用与排序。
现在就简单多了
template <class T>
void Linklist<T>::SortWithSwap()
{
for(int i =0;i<len;i++)
{
for(int j = 0;j<len-1-i;j++)
{
if(getItem(j)>getItem(j+1))
{
Swap(j,j+1);
}
}
}
}
template <class T>
T Linklist<T>::getItem(int index)
{
Node<T> *temp = head->next;
for(int i = 0;i<index;i++)
{
temp = temp->next;
}
return temp->data;
}
在看一看效果

结论:
链表的排序无非是换数据与换节点的方式。
因此链表也可以适用于不同的排序
本文探讨了链表排序的两种方法:通过交换节点数据和直接交换节点。首先介绍了顺序表排序的常见方式——冒泡排序,并展示了如何将其应用于链表,通过遍历节点并比较数据进行排序。接着,详细阐述了链表节点交换的实现,包括相邻节点和不相邻节点的交换,指出其复杂性并提供了相应的交换方法。最后,将节点交换用于排序,实现了一个链表排序函数`SortWithSwap()`。总结来说,链表排序可以灵活运用数据和节点的交换策略来完成。

2万+

被折叠的 条评论
为什么被折叠?



