快速排序代码问题以及一种改进的应用

一、快排问题:

先上文章,快排代码到处都是,比如:

快速排序 - Code2020 - 博客园 (cnblogs.com)

C语言实现快速排序的方法及优化_C 语言_脚本之家 (jb51.net)

按说应该没有任何问题,但是,任意拷贝一个测试,发现貌似都有一个问题,比如下面最简单版本的代码:

void quickSort(int a[],int left,int right)
{
  int i=left;
  int j=right;
  int temp=a[left];
  if(left>=right)
    return;
  while(i!=j)
  {
    while(i<j&&a[j]>=temp) 
    j--;
    if(j>i)
      a[i]=a[j];//a[i]已经赋值给temp,所以直接将a[j]赋值给a[i],赋值完之后a[j],有空位
    while(i<j&&a[i]<=temp)
    i++;
    if(i<j)
      a[j]=a[i];
  }
  a[i]=temp;//把基准插入,此时i与j已经相等R[low..pivotpos-1].keys≤R[pivotpos].key≤R[pivotpos+1..high].keys
  quickSort(a,left,i-1);/*递归左边*/
  quickSort(a,i+1,right);/*递归右边*/
}

问题出在最后两句,对于有些数据,会出现 i == left 或者 i == right的情况,那么i-1和i+1就会超出数组下标范围,经修改为:

if(i > left)
    quickSort(a, left, i - 1, b);  /*递归左边*/
if(i < right)
    quickSort(a, i + 1, right, b);  /*递归右边*/

就可以了。

二、下面是一种应用问题:

信号按帧处理,做中值滤波,因为每一帧每个信号点都会算中值再用信号点减去中值,而中值,简单可以通过排序后取窗口内中间位置元素得到,所以,用到排序,这里我们用快速排序。

第二,由于逐点滤波时,上一个信号点的窗口数据排序后,在下一个信号点甚至后面很多个信号点的窗口数据排序时,有一定的重复利用价值,特别是对于下一个点的窗口,只是删除了上次窗口中原始索引最小的值,而只增加了下一个点,那么——简单、统一处理可以是,将新增的信号点放在上一个点的窗口原始索引最小的值的位置,再重新排序——即,利用上一个点的窗口内所有数据点都排序好的优点!对于新增的信号点,再对这个新窗口进行排序,理论上计算复杂度就少很多了。

然而——有一个有点棘手的问题是,这里就不仅仅只需要将窗口内信号点值排序,还需要记录下信号点的索引排序后的结果,即信号点值排序后,信号点索引要跟着变,且要存下来,且需要一帧一帧连续实现。

直接给结果吧:将快排函数加一个参数,即是索引参数,同时,上述下一帧将新入信号点放在上一个窗口的原始索引最小位置的值对应的位置,同时将这个值对应的索引值变为窗口内最大,这个操作,需要另行处理。同时,每新来一帧都需要将索引值减1(对应窗口移动状态,同时窗口内位置索引也不会溢出),并且再记录下窗口内原始索引值最小的值的位置。

代码如下:

core_func.h

#pragma once

#include"stdint.h"


extern void quickSort(int16_t a[], uint8_t left, uint8_t right, uint8_t b[]);

core_func.c


#include"stdint.h"

///
// 以下排序并求中位值子函数
// 因为是固定256个数据点的排序,且需要将排序后的原位置变化结果也保存下来
// 因此,设置一个0~255的数组作为位置变量,排序时,对这个数组的元素操作,和对值数组的操作一致即可
///

///
// 最原始版本
 void quickSort(int16_t a[], uint8_t left, uint8_t right, uint8_t b[])
{
	 uint8_t i = left;
	 uint8_t j = right;
	 int16_t temp1 = a[left];
	 uint8_t temp2 = b[left];

	if (left >= right)
		return;
	while (i != j)
	{
		while (i < j && a[j] >= temp1)
			j--;
		if (j > i) {
			a[i] = a[j];  // a[i]已经赋值给temp,所以直接将a[j]赋值给a[i],赋值完之后a[j],有空位
			b[i] = b[j];
		}
		while (i < j && a[i] <= temp1)
			i++;
		if (i < j) {
			a[j] = a[i];
			b[j] = b[i];
		}
	}

	a[i] = temp1;  // 把基准插入,此时i与j已经相等R[low..pivotpos-1].keys≤R[pivotpos].key≤R[pivotpos+1..high].keys
	b[i] = temp2;
	if(i > left)
		quickSort(a, left, i - 1, b);  /*递归左边*/
	if(i < right)
		quickSort(a, i + 1, right, b);  /*递归右边*/
}

Median.h


#pragma once

#include<stdint.h>


extern void Median_zhh_init();
extern uint8_t Median_zhh(int16_t* data_frame, int16_t* data_frame_out, int16_t SampleRate);




Median.c

#include"string.h"

#include"core_func.h"


#define  POINT_FRAME  (256)  // (SAMPLERATE*T_FRAME*T_FRAME)


typedef struct {
	int16_t DataBuf[2 * POINT_FRAME];
	uint64_t FrameCnt;  // 
}MedianPra_t;
static MedianPra_t  MedianPra = { 0 };

// 求和临时变量存储相关封装
typedef struct {  //
	int16_t  DataArry[POINT_FRAME];
	int16_t  Median;  // 中值
	uint8_t  FirstElePos;  // 排序后原来第一个元素的位置
}MedianTmp_t;
static MedianTmp_t MedianTmp = { 0 };



typedef struct {  
	uint8_t  IndOri[POINT_FRAME];
	uint8_t  Ind[POINT_FRAME];  
}IndTmp_t;
static IndTmp_t IndTmp = {
	{ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
	32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
	64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,
	96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
	128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
	160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
	192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
	224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 },
	{ 0 } 
};



void Median_zhh_init() {
	memset( MedianPra.DataBuf, 0, sizeof(MedianPra.DataBuf) );
	MedianPra.FrameCnt = 0;

	memcpy( &IndTmp.Ind[0], &IndTmp.IndOri[0], POINT_FRAME * sizeof(IndTmp.IndOri[0]) );
	//MedianTmp.FirstElePos = 0;

}



// 数据按帧传入,同时要传入帧号
uint8_t Median_zhh(int16_t* data_frame, int16_t* data_frame_out, int16_t SampleRate)
{
  int16_t i, j;

  // 限制采样率必须是256
  if (SampleRate != 256){
      //printf("SampleRate error!\n");
      return 1;
  }

  MedianPra.FrameCnt++;  // 函数里面帧号从1开始计数

  if (MedianPra.FrameCnt == 1) {
	  memcpy(&MedianPra.DataBuf[POINT_FRAME], data_frame, POINT_FRAME * sizeof(MedianPra.DataBuf[0]));  // 为从第二帧开始统一做移位处理,放在后半段
	  memcpy( &IndTmp.Ind[0], &IndTmp.IndOri[0], POINT_FRAME * sizeof(IndTmp.IndOri[0]) );  // 第一帧初始化索引
	  memcpy( MedianTmp.DataArry, data_frame, POINT_FRAME * sizeof(data_frame[0]) );
	  quickSort(&MedianTmp.DataArry[0], 0, POINT_FRAME - 1, &IndTmp.Ind[0]);
	  MedianTmp.Median = MedianTmp.DataArry[POINT_FRAME >> 1];
	  for (i = 0; i < POINT_FRAME;i++) {
		  if (IndTmp.Ind[i] == 0) {
			  MedianTmp.FirstElePos = i;
			  break;
		  }
	  }
  }
  else{
	  memcpy(&MedianPra.DataBuf[0], &MedianPra.DataBuf[POINT_FRAME], POINT_FRAME * sizeof(MedianPra.DataBuf[0]));  // 左移
	  memcpy(&MedianPra.DataBuf[POINT_FRAME], data_frame, POINT_FRAME * sizeof(MedianPra.DataBuf[0]));

	  for (i = 0; i < POINT_FRAME; i++) {
		  MedianTmp.DataArry[MedianTmp.FirstElePos] = data_frame[i];
		  IndTmp.Ind[MedianTmp.FirstElePos] = POINT_FRAME;
		  for (j = 0; j < POINT_FRAME; j++) {
			  IndTmp.Ind[j]--;
		  }
		  quickSort(&MedianTmp.DataArry[0], 0, POINT_FRAME - 1, &IndTmp.Ind[0]);
		  MedianTmp.Median = MedianTmp.DataArry[POINT_FRAME >> 1];
		  for (j = 0; j < POINT_FRAME; j++) {
			  if (IndTmp.Ind[j] == 0) {
				  MedianTmp.FirstElePos = j;
				  break;
			  }
		  }

		  data_frame_out[i] = MedianPra.DataBuf[i + (POINT_FRAME >> 1)] - MedianTmp.Median;
	  }
  }  // if (sensoringCtrlPra.rCnt > 1)

  return  0;
}

主函数,也就是测试函数,也带下:

main.c


#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#include"Median.h"


#define TOTAL_FRAME (20)

// 读matlab转换采样率为256后的txt数据文件
int16_t data_in[TOTAL_FRAME * 256] = { 0 };
int16_t data_out[TOTAL_FRAME * 256] = { 0 };


int8_t main()
{
    int16_t i, ret;
    int16_t SampleRate = 256;
    int16_t data_size = TOTAL_FRAME * 256;
    int16_t read_data_size = 0;
    FILE* fp;


    fp = fopen("Sign_input.txt", "r");
    if (fp == NULL)
    {
        return 0;
    }
    for (i = 0; i < data_size; i++)
    {
        ret = fscanf(fp, "%d", data_in + i); // 1:读文件成功,则返回成功读取的项数;2:读文件失败,则返回EOF。
        if(ret==1)
            read_data_size++;
    }
    fclose(fp);

    if ((fp = fopen("data_in.txt", "w")) == NULL)
    {
        printf("Cannot open the file...");
        exit(1);
    }
    for (int16_t i = 0; i < TOTAL_FRAME * 256; i++)
    {
        fprintf(fp, "%d\n", data_in[i]);
    }
    fclose(fp);


    for (i = 0; i < TOTAL_FRAME; i++) {        
        ret = Median_zhh(data_in + i * SampleRate, data_out + i * SampleRate - (SampleRate >>1), SampleRate);
        if (ret) {
            return 1;
        }
    }

    if ((fp = fopen("data_out.txt", "w")) == NULL)
    {
        printf("Cannot open the file...");
        exit(1);
    }
    for (int16_t i = 0; i < TOTAL_FRAME * 256; i++)
    {
        fprintf(fp, "%d\n", data_out[i]);
    }
    fclose(fp);


    return 0;
}
 

三、提供对数据的matlab代码:

仿照C语言的快排函数(注意matlab要把修改的输入参数作为输出参数,才会起到和C一样修改输入实参的作用,嵌套调用时,还是不能忘记加输出参数):

quickSort.m

%% 快速排序函数,仿照C语言快速排序函数
% C快速排序函数
% // 最原始版本
%  void quickSort(int16_t a[], uint8_t left, uint8_t right, uint8_t b[])
% {
% 	 uint8_t i = left;
% 	 uint8_t j = right;
% 	 int16_t temp1 = a[left];
% 	 uint8_t temp2 = b[left];
% 
% 	if (left >= right)
% 		return;
% 	while (i != j)
% 	{
% 		while (i < j && a[j] >= temp1)
% 			j--;
% 		if (j > i) {
% 			a[i] = a[j];  // a[i]已经赋值给temp,所以直接将a[j]赋值给a[i],赋值完之后a[j],有空位
% 			b[i] = b[j];
% 		}
% 		while (i < j && a[i] <= temp1)
% 			i++;
% 		if (i < j) {
% 			a[j] = a[i];
% 			b[j] = b[i];
% 		}
% 	}
% 
% 	a[i] = temp1;  // 把基准插入,此时i与j已经相等R[low..pivotpos-1].keys≤R[pivotpos].key≤R[pivotpos+1..high].keys
% 	b[i] = temp2;
% 
% 	if(i > left)
% 		quickSort(a, left, i - 1, b);  /*递归左边*/
% 	if(i < right)
% 		quickSort(a, i + 1, right, b);  /*递归右边*/
% }
%  

function [data_arry, ind_arry] = quickSort(data_arry, left, right, ind_arry)

i = left;
j = right;
temp1 = data_arry(left);
temp2 = ind_arry(left);

if (left >= right)
    return;
end

while (i ~= j)
    while (i < j && data_arry(j) >= temp1)
        j=j-1;
    end
    if (j > i)
        data_arry(i)= data_arry(j); % data_arry(i]已经赋值给temp,所以直接将a(j]赋值给a(i],赋值完之后a(j],有空位
        ind_arry(i)= ind_arry(j);
    end
    while (i < j && data_arry(i)<= temp1)
        i=i+1;
    end
    if (i < j)
        data_arry(j)= data_arry(i);
        ind_arry(j)= ind_arry(i);
    end
end

data_arry(i)= temp1;   % 把基准插入,此时i与j已经相等R(low..pivotpos-1].keys≤R(pivotpos].key≤R(pivotpos+1..high].keys
ind_arry(i) = temp2;

if(i > left)
     [data_arry, ind_arry] = quickSort(data_arry, left, i - 1, ind_arry);  % /*递归左边*/
end
if(i < right)
     [data_arry, ind_arry] = quickSort(data_arry, i + 1, right, ind_arry);  % /*递归右边*/
end

end

主代码:

median_zhh.m

close all,clear,clc

load('data_in.txt');
load('data_out.txt');  % 加载vs的结果可画图比较

buf = zeros(512,1);

len = length(data_in);
data_out2 = zeros(len,1);

data_frame = zeros(256,1);
data_frame_sort = zeros(256,1);
ind = 1:1:256;

% 模拟VS中值滤波
for i=1:20
    data_frame = data_in((i-1)*256+1:i*256);
    if(i==1)
        buf(257:512) = data_frame;
        [data_frame, ind] = quickSort(data_frame, 1, 256, ind);
        data_frame_sort = data_frame;
        first_ele_pos = find(ind==1);
    else
        buf(1:256) = buf(257:512);
        buf(257:512) = data_frame;
        for j=1:256
            data_frame_sort(first_ele_pos) = data_frame(j);
            ind(first_ele_pos) = 257;
            ind = ind - 1;
            [data_frame_sort, ind] = quickSort(data_frame_sort, 1, 256, ind);
            median_tmp = data_frame_sort(129);
            first_ele_pos = find(ind==1);
%             data_out2((i-1)*256+j) = buf(j+128) - data_frame_sort(129);
            data_out2((i-1)*256+j-128) = buf(j+128) - median_tmp;
        end
    end
end

% 写txt数据和vs对数据
filename = 'data_out2.txt';
fid = fopen(filename, 'w');
for i=1:length(data_out2)
    if(i<length(data_out2))
        fprintf(fid, '%d\n', data_out2(i));
    else
        fprintf(fid, '%d', data_out2(i));
    end
end
fclose(fid);

zhh = 1;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值