关于链表的排序

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

前言:
链表的排序与顺序表相比是有些不同的。
原因是数据结构不同,
顺序表的实现可以看做是一个大数组,数组的各个元素有且只有数据。
而链表的节点却还有指向其他节点的指针部分。

如此,顺序表的排序只是将数据排序,而链表则也可以排序数据,也可以排序节点。

这里这里有一个实例,如果身边没有链表代码可以使用,可以直接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;
}

在看一看效果
请添加图片描述
结论:
链表的排序无非是换数据与换节点的方式。
因此链表也可以适用于不同的排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗马苏丹默罕默德

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值