利用双向链表来做排序(升序或者降序),原理比较简单过程复杂点:两个区域,一个缓存区,来保存原始数据,一个链表,用来保存排好序的节点。
缓存区有两部分,如下图,data部分保存需要排序的数据,p为指针指向该数据所在链表节点,每新进来一个数据就作为一个新的链表节点插入链表中,在插入时候就从表头开始和每个节点对比大小,以升序为例,只要找到节点数据比新数据大就把新数据节点放到该节点前,以此循环。如果缓存区已经存满,就用新数据替换掉缓存中最旧的一个,同时剔除掉该数据所在的链表节点。然后再放入新数据节点。
优点:不需要每次都将缓存区里的所有数据进行排序,在需要实时对大量数据进行排序时效率较高
缺点:缓存区较小的时候速度不一定更快,且占用更多内存空间
链表操作只用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;
}