//RadixSort.h
#ifndef _RADIXSORT_H_
#define _RADIXSORT_H_
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "List\List.h"
#define SIZE 15
typedef int Element;
typedef Element ListType[SIZE];
void CreateRandom(ListType L, int n);
void print(ListType L, int n);
//基数排序
void RadixSort(ListType L, int n);
#endif //_RADIXSORT_H_
//RadixSort.c
#include "RadixSort.h"
void CreateRandom(ListType L, int n)
{
int i = 0;
srand((unsigned)time(NULL));
for (i = 0; i < n; ++i)
{
L[i] = rand() % 0x7F;
}
}
void print(ListType L, int n)
{
int i = 0;
for (i = 0; i < n; ++i)
{
printf("%d\t", L[i]);
}
printf("\n");
}
/******************************************************
基数排序不需要无序序列直接进行关键字间的比较,而是根据每个关
键字的的信息再借助桶(桶间有序)对各序列中的元素按照一定的关系
进行分配(类似哈希表),分配到桶上再收集(由于桶间本身有序,且分
配的关系一定,必然分配到桶上的序列按照一定的方式去查看也是有
序的)时必然也是按一定的方式有序,对每个关键字重复分配收集过程
后排序完成。
分配后的收集时,注意先入先出以保证稳定性
为保证可扩展性,应使用链式存储结构作为桶
******************************************************/
static int GetKey(Element L, int p) //求某个位置p上的关键字
{
int val = 0;
while (p >= 0)
{
val = L % 10;
L /= 10;
p--;
}
return val;
}
static void Distribute(ListType L, List list[10], int p, int n)
{
int i = 0, pos = 0;
for(i = 0; i < n; ++i) //对所有元素按照关键字进行分配
{
pos = GetKey(L[i], p);
push_back(&list[pos], L[i]);
}
}
static void Collect(ListType L, List list[10])
{
int i = 0, j = 0, len = 0, k = 0;
List *p = NULL;
for (i = 0; i < 10; ++i) //按桶的顺序收集元素,收集完成后,无序序列对关键字有序
{
p = &list[i];
len = length(*p);
for (k = 0; k < len; ++k)
pop_front(p, &L[j++]);
}
}
void RadixSort(ListType L, int n)
{
int i = 0, j = 0, m = 0;
Element Temp;
List list[10]; //由于是10进制的数字,每个位上只可能是0~9, 所以采用10个链表作为桶
for(i = 0; i < 10; ++i )
{
init(&list[i]); //初始化
}
for(i = 0; i < n; ++i) //在序列中查找最大元素
{
if( L[j] < L[i] )
j = i;
}
Temp = L[j];
while (Temp > 0) //计算最大数的最高位,以得到关键字个数
{
Temp /= 10;
m++;
}
for(j = 0; j < m; ++j) //LSD 最低位优先
{
Distribute(L, list, j, n); //按照关键字对序列中每个元素进行分配
Collect(L, list); //依照通的顺序收集元素
}
}
//main.c
#include "RadixSort.h"
int main(int argc, char **argv)
{
ListType List ={ 0 };
int n = sizeof(List) / sizeof(Element);
CreateRandom(List, n);
printf("排序前\n");
print(List, n);
RadixSort(List, n);
printf("排序后\n");
print(List, n);
system("pause");
return 0;
}
//List.h
/*****************************************
头插 尾插 显示 头删 尾删
按值插入 按位置插入 查找 长度
逆序 清除 摧毁 初始化 排序
按位置删除 按值删除
****************************************/
#ifndef LIST_H_
#define LIST_H_
#include <stdio.h>
#include <stdbool.h>
typedef int ElementType;
typedef struct Node
{
ElementType data;
struct Node *next;
}Node, *pNode;
typedef struct List
{
Node *first; //指向头结点
Node *last; //指向最后一个节点,用于在某些时候避免不必要的遍历
int size; //链表除头结点的个数
}List, *pList;
bool init(List *mylist);
bool push_front(List *mylist, ElementType e);
bool push_back(List *mylist, ElementType e);
bool show(List mylist);
bool pop_front(List* mylist, ElementType *e);
bool pop_back(List* mylist, ElementType *e);
bool insert_val(List *mylist, ElementType e);
bool insert_pos(List *mylist, int i, ElementType e);
Node *find(List mylist, ElementType e, bool precursor);
int length(List mylist);
bool reverse(List *mylist);
bool clear(List *mylist);
bool destroy(List *mylist);
bool sort(List *mylist);
bool delete_pos(List *mylist, int i, ElementType *e);
bool delete_val(List *mylist, ElementType e);
#endif //LIST_H_
//List.c
#include "List.h"
#include "stdlib.h"
/*************************
在操作线性表时,注意每个结构体成员的值
注意边界条件,如涉及删除操作,必然先判断链表成员情况
按位插入时考虑位置、等
另外注意不同线性表各自的不同特性对操作的影响
稍加修改便可实现泛型数据结构
代码中有很多重复的代码片段,可以将它们单独封装成内联函数并在需要时调用。。。。。
**************************/
bool init(List *mylist)
{
mylist->last = mylist->first = (Node *)malloc(sizeof(Node));
if( NULL == mylist->first )
{
return false;
}
mylist->first->next = NULL; //注意新节点的指针域
mylist->first->data = -1;
mylist->size = 0;
return true;
}
bool push_front(List *mylist, ElementType e)
{
Node *p = (Node *)malloc(sizeof(Node));
if( NULL == p )
return false;
p->next = NULL;
p->data = e;
p->next = mylist->first->next;
mylist->first->next = p;
if( 0 == mylist->size )
mylist->last = p; //链表为空时,新节点也是尾节点
mylist->size++;
return true;
}
bool push_back(List *mylist, ElementType e)
{
Node *s = NULL;
Node *p = (Node *)malloc(sizeof(Node));
if( NULL == p )
return false;
p->data = e;
p->next = NULL;
mylist->last->next = p;
mylist->last = p; //注意更改尾指针
mylist->size++;
return true;
}
bool show(List mylist)
{
Node *p = mylist.first->next;
while(NULL != p)
{
printf("%d->", p->data);
p = p->next;
}
printf("NULL\n");
printf("尾节点的值为%d\n", *mylist.last);
return true;
}
bool pop_front(List* mylist, ElementType *e)
{
if( 0 == mylist->size) //避免删除空表
{
return false;
}
Node *p = mylist->first->next;
mylist->first->next = p->next;
*e = p->data;
free(p);
if( 1== mylist->size ) //亦可通过比较p与last指针判断
mylist->last = mylist->first; //处理尾指针
mylist->size--;
return true;
}
bool pop_back(List* mylist, ElementType *e)
{
if( 0 == mylist->size ) //避免删除空表
{
printf("链表为空\n");
return false;
}
Node *p = mylist->first;
while(p->next != mylist->last)
p = p->next; //寻找尾节点前驱节点
*e = mylist->last->data;
free(mylist->last);
mylist->last = p;
p->next = NULL;
mylist->size--;
return true;
}
bool insert_val(List *mylist, ElementType e) //此函数的先决条件:链表中已存在节点值必须有序
{
if( 0 == mylist->size )
return push_back(mylist, e);
Node *v = (Node *)malloc(sizeof(Node));
if( NULL == v )
return false;
v->next = NULL;
v->data = e;
Node *p = mylist->first;
while(NULL != p->next && p->next->data < e)
p = p->next;
if( NULL == p->next )
mylist->last = p; //尾指针
v->next = p->next;
p->next = v;
mylist->size++;
return true;
}
//指定头结点为第0个位置,在第1个位置插入,则插入完成后的第1个位置即为新节点
bool insert_pos(List *mylist, int i, ElementType e)
{
if( i < 1 )
{
printf("输入位置小于1, 已插入为第一个节点\n");
return push_front(mylist, e);
}
if( i > mylist->size )
{
printf("输入的位置大于链表范围,已插入为尾节点\n");
return push_back(mylist, e);
}
Node *v = (Node *)malloc(sizeof(Node));
if( NULL == v )
return false;
v->data = e;
v->next = NULL;
Node *p = mylist->first;
for(int j = 1; j < i; j++)
{
p = p->next; //寻找合适的位置
}
v->next = p->next;
p->next = v;
mylist->size++;
return true;
}
Node *find(List mylist, ElementType e, bool precursor) //precursor为真时返回e节点的前驱节点指针值
{
if( 0 == mylist.size )
return NULL;
Node *p = mylist.first;
while(NULL != p->next && p->next->data != e)
p = p->next;
if( NULL == p->next )
return NULL;
else
return precursor ? p : p->next;
}
int length(List mylist)
{
return mylist.size;
}
//将链表分成两个链表(链表1有头结点与1节点,链表2为剩余节点的链表)后,将链表2的节点逐个头插入链表1
bool reverse(List *mylist)
{
if( 0 == mylist->size || 1 == mylist->size )
return true;
Node *p = mylist->first->next;
Node *q = p->next;
p->next = NULL; //拆分链表
mylist->last = p; //处理尾指针
while(NULL != q)
{
p = q;
q = q->next;
p->next = mylist->first->next;
mylist->first->next = p;
}
return true;
}
bool clear(List *mylist)
{
if( 0 == mylist->size )
return true;
Node *p = mylist->first->next;
mylist->last = mylist->first; //尾指针
while( NULL != p)
{
mylist->first->next = p->next;
free(p);
p = mylist->first->next;
}
mylist->size = 0; //!!!
return true;
}
bool destroy(List *mylist)
{
clear(mylist);
free(mylist->first);
mylist->first = mylist->last = NULL;
return true;
}
//拆分后按序插入
bool sort(List *mylist)
{
if( 0 == mylist->size || 1 == mylist->size )
return true;
Node *p = mylist->first->next;
Node *q = p->next;
mylist->last = p; //尾指针
p->next = NULL; //拆分链表
Node *s = mylist->first; //s指向含头结点链表
while(NULL != q) //q指向不含头结点链表
{
while(NULL != s->next && s->next->data < q->data)
{
s = s->next;
}
if( NULL == s->next )
mylist->last = q; //处理尾指针
p = q;
q = q->next;
p->next = s->next;
s->next = p;
s = mylist->first; //!!!!!!!!!!!!!!!!!!!!
}
return true;
}
bool delete_pos(List *mylist, int i, ElementType *e)
{
int j = 0;
Node *p = mylist->first;
Node *q = NULL;
if( 0 == mylist->size )
{
printf("链表为空\n");
return false;
}
if( i < 1 || i > mylist->size )
{
printf("指定的 删除位置不合法,请重新选择\n");
return false;
}
for(j = 1; j < i; j++)
{
p = p->next;
}
q = p->next;
p->next = q->next;
*e = q->data;
if( NULL == q )
mylist->last = p; // 尾
free(q);
mylist->size--;
return true;
}
bool delete_val(List *mylist, ElementType e)
{
Node * p = NULL, *q = NULL;
if( NULL == ( p = find(*mylist, e, true)) )
{
printf("需要删除的节点不存在\n");
return false;
}
q = p->next;
p->next = q->next;
if( NULL == q )
mylist->last = p; // 尾
free(q);
mylist->size--;
return true;
}