📄 sort.c
字号:
#include "tdestr.h"
#include "common.h"
#include "tdefunc.h"
#include "define.h"
/*
* Name: sort_box_block
* Purpose: sort lines according to text in marked BOX block
* Date: June 5, 1992
* Passed: window: pointer to current window
* Notes: quick sort and insertion sort the lines in the BOX buff according
* to stuff in a box block.
*/
int sort_box_block( WINDOW *window )
{
int prompt_line;
int block_type;
line_list_ptr ll;
register file_infos *file;
WINDOW *sw;
int rc;
char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
/*
* make sure block is marked OK
*/
rc = OK;
prompt_line = window->bottom_line;
entab_linebuff( );
if (un_copy_line( window->ll, window, TRUE ) == ERROR)
return( ERROR );
check_block( );
if (g_status.marked == TRUE) {
file = g_status.marked_file;
block_type = file->block_type;
if (block_type == BOX) {
/*
* sort ascending or descending?
*/
rc = get_sort_order( window );
if (rc != ERROR) {
file->modified = TRUE;
if (mode.do_backups == TRUE) {
sw = g_status.window_list;
for (; ptoul( sw->file_info ) != ptoul( file );)
sw = sw->next;
backup_file( sw );
}
/*
* figure the width of the block.
*/
sort.block_len = file->block_ec + 1 - file->block_bc;
/*
* save the prompt line and print the quicksort message.
*/
save_screen_line( 0, prompt_line, line_buff );
eol_clear( 0, prompt_line, g_display.text_color );
set_prompt( block22a, prompt_line );
/*
* set up the sort structure.
*/
sort.bc = g_status.marked_file->block_bc;
sort.ec = g_status.marked_file->block_ec;
sort.order_array = (mode.search_case == IGNORE) ?
sort_order.ignore : sort_order.match;
/*
* save the previous node for use with insertion sort.
*/
ll = file->block_start->prev;
quick_sort_block( file->block_br, file->block_er,
file->block_start, file->block_end );
/*
* get back previous node and clean up list with insertion
* sort.
*/
if (ll == NULL)
ll = file->line_list;
else
ll = ll->next;
set_prompt( block22b, prompt_line );
insertion_sort_block( file->block_br, file->block_er, ll );
/*
* housekeeping. mark the file as dirty and restore the
* cursors, which are scrambled during the sort.
*/
file->dirty = GLOBAL;
restore_cursors( file );
restore_screen_line( 0, prompt_line, line_buff );
}
} else {
/*
* can only sort box blocks
*/
error( WARNING, prompt_line, block23 );
rc = ERROR;
}
} else {
/*
* box not marked
*/
error( WARNING, prompt_line, block24 );
rc = ERROR;
}
return( rc );
}
/*
* Name: quick_sort_block
* Purpose: sort lines according to text in marked BOX block
* Date: Jaunary 10, 1993
* Passed: low: starting line in box block
* high: ending line in a box block
* low_node: starting node in box block
* high_node: ending node in box block
* Notes: Quicksort lines in the BOX block according to keys in
* a box block.
* because the median of three method is used to find the partion
* node, high - low should be greater than or equal to 2.
* with end recursion removal and sorting the smallest sublist
* first, our stack only needs room for log2 (N+1)/(M+2) nodes.
* a stack size of 24 can reliably handle almost 500 million lines.
*/
void quick_sort_block( long low, long high, line_list_ptr low_node,
line_list_ptr high_node )
{
long low_rline_stack[24];
long high_rline_stack[24];
line_list_ptr low_node_stack[24];
line_list_ptr high_node_stack[24];
long low_count;
long high_count;
long count;
line_list_ptr low_start;
line_list_ptr low_head;
line_list_ptr low_tail;
line_list_ptr high_end;
line_list_ptr high_head;
line_list_ptr high_tail;
line_list_ptr equal_head;
line_list_ptr equal_tail;
line_list_ptr walk_node;
line_list_ptr median_node;
int i;
int stack_pointer;
assert( low_node->len != EOF);
assert( high_node->len != EOF);
stack_pointer = 0;
for (;;) {
/*
* being that a median-of-three is used as the partition algorithm,
* we probably need to have at least 2 nodes in each sublist. I
* chose a minimum of 25 nodes as a SWAG (scientific wild ass guess).
* a simple insertion sort mops the list after quicksort finishes.
*/
while (high - low > 25) {
assert( high >= 1 );
assert( low >= 1 );
assert( low <= high );
/*
* start the walk node at the head of the list and walk to the
* middle of the sublist.
*/
walk_node = low_node;
count = (high - low) / 2;
for (; count > 0; count--)
walk_node = walk_node->next;
/*
* now, find the median of the low, middle, and high node.
*
* being that I am subject to error, let's assert that we really
* did find the median-of-three.
*/
load_pivot( low_node );
if (compare_pivot( walk_node ) < 0) {
low_head = walk_node;
median_node = low_node;
} else {
low_head = low_node;
median_node = walk_node;
}
high_head = high_node;
load_pivot( median_node );
if (compare_pivot( high_node ) < 0) {
high_head = median_node;
median_node = high_node;
}
load_pivot( median_node );
if (compare_pivot( low_head ) > 0) {
low_tail = median_node;
median_node = low_head;
low_head = low_tail;
}
load_pivot( median_node );
assert( compare_pivot( low_head ) <= 0 );
assert( compare_pivot( high_head ) >= 0 );
/*
* now, walk again from the head of the list comparing nodes and
* use the first occurrence of the median node as the partition.
*/
walk_node = low_node;
for (i = 0; ; walk_node = walk_node->next) {
if (compare_pivot( walk_node ) == 0)
break;
i = 1;
}
/*
* initialize pointers and counters for this partition.
*/
low_start = low_node->prev;
high_end = high_node->next;
low_head = low_tail = NULL;
high_head = high_tail = NULL;
low_count = high_count = 0;
/*
* setup the first occurrence of the median node as a "fat pivot"
* sublist. there are two cases to consider 1) the first
* occurrence of the median node is the first element in the
* sublist, i == 0, or 2) the first occurrence of the median node
* is somewhere in the sublist.
*/
if (i == 0)
walk_node = equal_head = equal_tail = low_node;
else {
equal_head = equal_tail = walk_node;
equal_head->next->prev = equal_head->prev;
equal_head->prev->next = equal_head->next;
equal_head->next = low_node;
walk_node = equal_head;
}
load_pivot( equal_head );
/*
* PARTITION:
* put all nodes less than the pivot on the end of the low list.
* put all nodes equal to the pivot on the end of the equal list.
* put all nodes greater than the pivot on the end of the high list.
*/
for (count=low+1; count <= high; count++) {
walk_node = walk_node->next;
i = compare_pivot( walk_node );
if (i > 0) {
if (high_head == NULL)
high_head = high_tail = walk_node;
else {
high_tail->next = walk_node;
walk_node->prev = high_tail;
high_tail = walk_node;
}
/*
* keep a count of the number of nodes in the high list.
*/
++high_count;
} else if (i < 0) {
if (low_head == NULL)
low_head = low_tail = walk_node;
else {
low_tail->next = walk_node;
walk_node->prev = low_tail;
low_tail = walk_node;
}
/*
* keep a count of the number of nodes in the low list
*/
++low_count;
} else {
equal_tail->next = walk_node;
walk_node->prev = equal_tail;
equal_tail = walk_node;
}
}
assert( low_count >= 0 );
assert( low_count < high - low );
assert( high_count >= 0 );
assert( high_count < high - low );
/*
* we just partitioned the sublist into low, equal, and high
* sublists. now, let's put the lists back together.
*/
if (low_count > 0) {
low_head->prev = low_start;
if (low_start != NULL)
low_start->next = low_head;
else
g_status.marked_file->line_list = low_head;
low_tail->next = equal_head;
equal_head->prev = low_tail;
} else {
equal_head->prev = low_start;
if (low_start != NULL)
low_start->next = equal_head;
else
g_status.marked_file->line_list = equal_head;
}
if (high_count > 0) {
high_head->prev = equal_tail;
equal_tail->next = high_head;
high_tail->next = high_end;
high_end->prev = high_tail;
} else {
equal_tail->next = high_end;
high_end->prev = equal_tail;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -