利用双向链表来做排序(升序或者降序),原理比较简单过程复杂点:两个区域,一个缓存区,来保存原始数据,一个链表,用来保存排好序的节点。

缓存区有两部分,如下图,data部分保存需要排序的数据,p为指针指向该数据所在链表节点,每新进来一个数据就作为一个新的链表节点插入链表中,在插入时候就从表头开始和每个节点对比大小,以升序为例,只要找到节点数据比新数据大就把新数据节点放到该节点前,以此循环。如果缓存区已经存满,就用新数据替换掉缓存中最旧的一个,同时剔除掉该数据所在的链表节点。然后再放入新数据节点。

harmonyos page 多个abilityslice 链表结构 用链表排序多个数据_数据结构


优点:不需要每次都将缓存区里的所有数据进行排序,在需要实时对大量数据进行排序时效率较高

缺点:缓存区较小的时候速度不一定更快,且占用更多内存空间

链表操作只用4个方法:

  • 在指定节点前添加新节点
  • 在指定节点后添加新节点
  • 删除指定节点
  • 获取节点个数

C语言测试代码如下:

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>

//--------------------------------------------------------------------------
// 双向链表节点(非环形)
typedef struct LINKED_NODE{ 
	struct LINKED_NODE *pre; 
	int  data;
	struct LINKED_NODE *next;  	
}LINKED_NODE_T;

/***********************************************************************************************************
函数名称 : LINKED_InsertPre
功    能 : 在指定节点前插入
参    数 : list -- 表头
			node -- 指定节点
			data  -- 数据缓存
返 回 值 : 新节点地址
***********************************************************************************************************/
static LINKED_NODE_T *LINKED_InsertPre(LINKED_NODE_T **list ,LINKED_NODE_T *node, int  data) 
{
	LINKED_NODE_T *newNode = (LINKED_NODE_T *)malloc(sizeof(LINKED_NODE_T));  // 创建一个新的节点
	newNode->data = data;										// 循环节点数据大小
	newNode->pre = NULL;	
	newNode->next = NULL;										

	if(*list==NULL)  							    // 如果没有头节点就在这里创建头节点
	{
		(*list) = newNode;                        // 保存链表头
	}
	else
	{
        LINKED_NODE_T *temp = node->pre;
        if(temp==NULL)                          // 第一个节点
        {
            (*list)->pre = newNode;         	// 保存链表头
            newNode->next = (*list);
            (*list) = newNode;   
        }
        else{
            newNode->next = node;
            newNode->pre = temp;
            node->pre->next = newNode;
            node->pre = newNode;
        }
	}
    return newNode;
}



/***********************************************************************************************************
函数名称 : LINKED_InsertBack
功    能 : 在指定节点后插入
参    数 : list -- 表头
			node -- 指定节点
			data  -- 数据缓存
返 回 值 : 新节点地址
***********************************************************************************************************/
static LINKED_NODE_T *LINKED_InsertBack(LINKED_NODE_T **list ,LINKED_NODE_T *node, int  data) 
{
	LINKED_NODE_T *newNode = (LINKED_NODE_T *)malloc(sizeof(LINKED_NODE_T));  // 创建一个新的节点
	newNode->data = data;										// 循环节点数据大小
	newNode->pre = NULL;	
	newNode->next = NULL;		

	if(*list==NULL)  							// 如果没有头节点就在这里创建头节点
	{
		(*list) = newNode;         				// 保存链表头
	}
	else
	{
		LINKED_NODE_T *next = node->next;
		if(next!=NULL)
		{
			next->pre = newNode;
			node->next = newNode;
			newNode->next = next;
			newNode->pre = node;
		}
		else
		{
            node->next = newNode;
			newNode->pre = node;
		}			
	}
    return newNode;
}

/***********************************************************************************************************
函数名称 : LINKED_NodeFree
功    能 : 释放指定节点
参    数 : head -- 表头
			node -- 需要释放的节点
返 回 值 : 无
***********************************************************************************************************/
static void LINKED_NodeFree(LINKED_NODE_T **list, LINKED_NODE_T *node)
{
	LINKED_NODE_T *p1=NULL,*p2=NULL;
	if(node!=NULL)  		
	{
		p1 = node->pre;
		p2 = node->next;
        if(p1==NULL) // 头部
        {
            *list = p2;
        }
		p1->next = p2;
		p2->pre = p1;
		free(node);   
		node = NULL;
	}
}

/***********************************************************************************************************
函数名称 : LINKED_Free
功    能 : 释放整个链表
参    数 : head -- 表头
返 回 值 : 无
***********************************************************************************************************/
static void LINKED_Free(LINKED_NODE_T **head)
{
	LINKED_NODE_T *p1=NULL,*p2=NULL;
	if(head!=NULL)  		
	{
		p1 = (*head);
		while(1)
		{
			p2 = p1->next;
			free(p1);   
			p1 = NULL;
			p1 = p2;
			if(p2==NULL)  break;   // 表示已经没有节点了
		}
		*head = NULL;
	}
}



/***********************************************************************************************************
函数名称 : LINKED_GetSize
功    能 : 获取链表节点数
参    数 : head -- 表头
返 回 值 : 节点个数
***********************************************************************************************************/
static uint16_t LINKED_GetSize(LINKED_NODE_T **head)
{
	uint16_t size=0;
	LINKED_NODE_T *p;
	p = *head;
	while(1)
	{
		if(p==NULL)
		{
			return size;
		}
		else 
		{
			size++;
			p = p->next;
		}
	}
}



//------------------------------------------------------------------------------------------------
#define BUF_SIZE    20      // 缓存区大小,同时限制了链表个数
typedef struct
{
    int data;
    LINKED_NODE_T *node;  	
}ITEM_T;

ITEM_T sourceData[BUF_SIZE]={0};             // 缓存区数据(未排序)
LINKED_NODE_T *sortList=NULL;                // 排序链表头

/***********************************************************************************************************
函数名称 : my_sort
功    能 : 排序方法
参    数 : data-- 新数据
返 回 值 : 无
***********************************************************************************************************/
void my_sort(int data)
{
    static int dataIndex=0;        // 新数据在存放在源buf中的序号
    static bool fullFlag = false;  // 缓存区是否存满
    // 更新源数据
    sourceData[dataIndex].data = data;

    // 根据链表长度判断是否需要删除节点
    uint16_t listSize = LINKED_GetSize(&sortList);
    if(fullFlag == true)
    {
        LINKED_NodeFree(&sortList, sourceData[dataIndex].node);
    }
   
    // 往排序队列里更新数据
    LINKED_NODE_T *p = sortList; 
    if(listSize==0)
    {
       sourceData[dataIndex].node = LINKED_InsertPre(&sortList, p, data);
    }
    else
    {
        for(int i=0;i<listSize;i++)
        {
            if(p->data>=data)   // 升序>=     降序<=
            {
                sourceData[dataIndex].node = LINKED_InsertPre(&sortList, p, data);
                break;
            }
            if(i==listSize-1)  // 到最后一个节点都没满足条件就直接放到最后
            {
                sourceData[dataIndex].node = LINKED_InsertBack(&sortList, p, data);
                break;
            }
            p = p->next;
        }
    }
    // 循环放入原始缓存区
    if(++dataIndex>=BUF_SIZE)
    {
        fullFlag = true;
        dataIndex = 0;
    }
}

// --------------------------------------------------------------------------------------
int main(void)
{
    uint8_t data;
    srand((unsigned int)time(NULL)); // 随机数源

    for (int k = 0; k < 50; k++)
    {
        data = rand()%100;  // 随机数
        my_sort(data);		// 排序

        printf("\r\n----------------------------updata source:----------------------------\r\n");
        for (int i = 0; i < BUF_SIZE; i++)
        {
            printf("%d  ",sourceData[i].data);
        }

        printf("\r\n-----------------------------updata sort:----------------------------\r\n");
        LINKED_NODE_T *p=sortList; 
        uint16_t listSize = LINKED_GetSize(&sortList);
        for(int i=0;i<listSize;i++)
        {
            printf("%d  ",p->data);
            p = p->next;
        }
        printf("\r\n=====================================================================\r\n");
    }
    return 0;
}