⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gqsort.c

📁 嵌入式下基于MiniGUI的Web Browser
💻 C
字号:
/* GLIB - Library of useful routines for C programming * Copyright (C) 1991, 1992, 1996, 1997 Free Software Foundation, Inc. * Copyright (C) 2000 Eazel, Inc. * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. *//* * This file was originally part of the GNU C Library, and was modified to allow * user data to be passed in to the sorting function. * * Written by Douglas C. Schmidt (schmidt@ics.uci.edu). * Modified by Maciej Stachowiak (mjs@eazel.com) * * Modified by the GLib Team and others 1997-2000.  See the AUTHORS * file for a list of people on the GLib Team.  See the ChangeLog * files for a list of changes.  These files are distributed with GLib * at ftp://ftp.gtk.org/pub/gtk/. */#include <string.h>#include "glib.h"/* Byte-wise swap two items of size SIZE. */#define SWAP(a, b, size)						      \  do									      \    {									      \      register size_t __size = (size);					      \      register char *__a = (a), *__b = (b);				      \      do								      \	{								      \	  char __tmp = *__a;						      \	  *__a++ = *__b;						      \	  *__b++ = __tmp;						      \	} while (--__size > 0);						      \    } while (0)/* Discontinue quicksort algorithm when partition gets below this size.   This particular magic number was chosen to work best on a Sun 4/260. */#define MAX_THRESH 4/* Stack node declarations used to store unfulfilled partition obligations. */typedef struct{  char *lo;  char *hi;}stack_node;/* The next 4 #defines implement a very fast in-line stack abstraction. */#define STACK_SIZE	(8 * sizeof(unsigned long int))#define PUSH(low, high)	((void) ((top->lo = (low)), (top->hi = (high)), ++top))#define	POP(low, high)	((void) (--top, (low = top->lo), (high = top->hi)))#define	STACK_NOT_EMPTY	(stack < top)/* Order size using quicksort.  This implementation incorporates * four optimizations discussed in Sedgewick: * * 1. Non-recursive, using an explicit stack of pointer that store the next *    array partition to sort.  To save time, this maximum amount of space *    required to store an array of MAX_INT is allocated on the stack.  Assuming *    a 32-bit integer, this needs only 32 * sizeof(stack_node) == 136 bits. *    Pretty cheap, actually. * * 2. Chose the pivot element using a median-of-three decision tree.  This *    reduces the probability of selecting a bad pivot value and eliminates *    certain * extraneous comparisons. * * 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving insertion *    sort to order the MAX_THRESH items within each partition.  This is a big *    win, since insertion sort is faster for small, mostly sorted array *    segments. * * 4. The larger of the two sub-partitions is always pushed onto the stack *    first, with the algorithm then concentrating on the smaller partition. *    This *guarantees* no more than log (n) stack size is needed (actually O(1) *    in this case)! *//** * g_qsort_with_data: * @pbase: start of array to sort * @total_elems: elements in the array * @size: size of each element * @compare_func: function to compare elements * @user_data: data to pass to @compare_func * * This is just like the standard C qsort() function, but * the comparison routine accepts a user data argument. *  **/voidg_qsort_with_data (gconstpointer    pbase,		   gint             total_elems,		   size_t           size,		   GCompareDataFunc compare_func,		   gpointer         user_data){  register char *base_ptr = (char *) pbase;  /* Allocating SIZE bytes for a pivot buffer facilitates a better   * algorithm below since we can do comparisons directly on the pivot.   */  char *pivot_buffer = (char *) g_alloca (size);  const size_t max_thresh = MAX_THRESH * size;  g_return_if_fail (total_elems >= 0);  g_return_if_fail (pbase != NULL || total_elems == 0);  g_return_if_fail (compare_func != NULL);  if (total_elems == 0)    return;  if (total_elems > MAX_THRESH)    {      char *lo = base_ptr;      char *hi = &lo[size * (total_elems - 1)];      /* Largest size needed for 32-bit int!!! */      stack_node stack[STACK_SIZE];      stack_node *top = stack + 1;      while (STACK_NOT_EMPTY)	{	  char *left_ptr;	  char *right_ptr;	  char *pivot = pivot_buffer;	  /* Select median value from among LO, MID, and HI. Rearrange	   * LO and HI so the three values are sorted. This lowers the	   * probability of picking a pathological pivot value and	   * skips a comparison for both the LEFT_PTR and RIGHT_PTR. */	  char *mid = lo + size * ((hi - lo) / size >> 1);	  if ((*compare_func) ((void *) mid, (void *) lo, user_data) < 0)	    SWAP (mid, lo, size);	  if ((*compare_func) ((void *) hi, (void *) mid, user_data) < 0)	    SWAP (mid, hi, size);	  else	    goto jump_over;	  if ((*compare_func) ((void *) mid, (void *) lo, user_data) < 0)	    SWAP (mid, lo, size);	jump_over:;	  memcpy (pivot, mid, size);	  pivot = pivot_buffer;	  left_ptr = lo + size;	  right_ptr = hi - size;	  /* Here's the famous ``collapse the walls'' section of quicksort.	   * Gotta like those tight inner loops!  They are the main reason	   * that this algorithm runs much faster than others. */	  do	    {	      while ((*compare_func)		     ((void *) left_ptr, (void *) pivot,		      user_data) < 0)		left_ptr += size;	      while ((*compare_func)		     ((void *) pivot, (void *) right_ptr,		      user_data) < 0)		right_ptr -= size;	      if (left_ptr < right_ptr)		{		  SWAP (left_ptr, right_ptr, size);		  left_ptr += size;		  right_ptr -= size;		}	      else if (left_ptr == right_ptr)		{		  left_ptr += size;		  right_ptr -= size;		  break;		}	    }	  while (left_ptr <= right_ptr);	  /* Set up pointers for next iteration.  First determine whether	   * left and right partitions are below the threshold size.  If so,	   * ignore one or both.  Otherwise, push the larger partition's	   * bounds on the stack and continue sorting the smaller one. */	  if ((size_t) (right_ptr - lo) <= max_thresh)	    {	      if ((size_t) (hi - left_ptr) <= max_thresh)		/* Ignore both small partitions. */		POP (lo, hi);	      else		/* Ignore small left partition. */		lo = left_ptr;	    }	  else if ((size_t) (hi - left_ptr) <= max_thresh)				/* Ignore small right partition. */	    hi = right_ptr;	  else if ((right_ptr - lo) > (hi - left_ptr))	    {				/* Push larger left partition indices. */	      PUSH (lo, right_ptr);	      lo = left_ptr;	    }	  else	    {				/* Push larger right partition indices. */	      PUSH (left_ptr, hi);	      hi = right_ptr;	    }	}    }  /* Once the BASE_PTR array is partially sorted by quicksort the rest   * is completely sorted using insertion sort, since this is efficient   * for partitions below MAX_THRESH size. BASE_PTR points to the beginning   * of the array to sort, and END_PTR points at the very last element in   * the array (*not* one beyond it!). */  {    char *const end_ptr = &base_ptr[size * (total_elems - 1)];    char *tmp_ptr = base_ptr;    char *thresh = MIN (end_ptr, base_ptr + max_thresh);    register char *run_ptr;    /* Find smallest element in first threshold and place it at the     * array's beginning.  This is the smallest array element,     * and the operation speeds up insertion sort's inner loop. */    for (run_ptr = tmp_ptr + size; run_ptr <= thresh;	 run_ptr +=	   size) if ((*compare_func) ((void *) run_ptr, (void *) tmp_ptr,				      user_data) < 0)	     tmp_ptr = run_ptr;    if (tmp_ptr != base_ptr)      SWAP (tmp_ptr, base_ptr, size);    /* Insertion sort, running from left-hand-side up to right-hand-side.  */    run_ptr = base_ptr + size;    while ((run_ptr += size) <= end_ptr)      {	tmp_ptr = run_ptr - size;	while ((*compare_func)	       ((void *) run_ptr, (void *) tmp_ptr,		user_data) < 0)	  tmp_ptr -= size;	tmp_ptr += size;	if (tmp_ptr != run_ptr)	  {	    char *trav;	    trav = run_ptr + size;	    while (--trav >= run_ptr)	      {		char c = *trav;		char *hi, *lo;		for (hi = lo = trav;		     (lo -= size) >= tmp_ptr; hi = lo)		  *hi = *lo;		*hi = c;	      }	  }      }  }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -