基数排序算法:
#include <stdio.h>
// 获取数组中的最大值
int getMax(int arr[], int n) {
int max = arr[0];
for (int i = 1; i < n; i++) {
if (arr[i] > max)
max = arr[i];
}
return max;
}
/**
* 基数排序函数
* 排序的次数根据序列的最大数确定,最大数是三位数,循环三次,最大数是四位数,循环四次,从个位数
* 开始排,依次是个,十,百,千,万...
* 每次排序需要用到十个桶,分别是0号桶,1号桶,2号桶...一直到9号桶,将对应元素放在各自桶中
* 比如刚开始排个数,将个位数是0的放在0号桶,个位数是1的放在1号桶... 将所有的元素放入桶之后,
* 再依次从桶中取出,形成一个新的待排序列,然后按照相同的方式再排十位数,百位数...
时间复杂度:
基数排序的时间复杂度取决于数据的位数和桶的数量。假设数据的位数为 d,桶的数量为 k,数据的个数为n。
1. 对于每一位的分配和收集步骤,需要遍历整个数组,时间复杂度为 O(n)。
2. 对于位数的迭代,最多进行 \( d \) 次迭代。每次迭代需要进行一次分配和收集步骤,因此总时间复杂度为 O(d * n)。
因此,基数排序的总时间复杂度为 O(d * (n + k))。在数据的位数 d, 较小且桶的数量 k, 不是很大的情况下,
时间复杂度通常可以近似为 O(n)。
空间复杂度
基数排序的空间复杂度取决于额外空间的使用情况,主要包括临时存储排序结果的数组和存储每个桶中元素个数的数组。
1. 临时存储排序结果的数组:它的大小与待排序数组的大小相同,因此空间复杂度为 O(n)。
2. 存储每个桶中元素个数的数组:这个数组的大小是固定的,与桶的数量 k 相关,因此空间复杂度为 (k)。
因此,基数排序的总空间复杂度为O(n + k)。在数据量较大、桶的数量较大时,空间复杂度会相对较高。
是稳定排序算法
* @param arr
* @param n
* @return
*/
void radixSort(int arr[], int n) {
// 找到数组中的最大值,以确定迭代次数
int max = getMax(arr, n);
// 用于临时存储排序结果的数组
int output[n];
// 定义一个count数组,用于存储每个桶中元素的个数
int count[10];
// 初始化count数组
for (int i = 0; i < 10; i++)
count[i] = 0;
// 计算每个桶中元素的个数
for (int exp = 1; max / exp > 0; exp *= 10) {
// 清零count数组
for (int i = 0; i < 10; i++)
count[i] = 0;
// 统计每个桶中元素的个数
for (int i = 0; i < n; i++)
count[(arr[i] / exp) % 10]++;
// 更新count数组,使其包含当前桶中元素的最终位置
for (int i = 1; i < 10; i++)
count[i] += count[i - 1];
// 生成排序结果
for (int i = n - 1; i >= 0; i--) {
output[count[(arr[i] / exp) % 10] - 1] = arr[i];
count[(arr[i] / exp) % 10]--;
}
printf("\n");
// 将排序结果复制回原数组
for (int i = 0; i < n; i++) {
printf("%d,", output[i]);
arr[i] = output[i];
}
printf("\n");
}
}
// 打印数组
void printArray(int arr[], int n) {
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
}
int main() {
int arr[] = {170, 45, 75, 90, 802, 24, 2, 66};
int n = sizeof(arr) / sizeof(arr[0]);
printArray(arr, n);
radixSort(arr, n);
printf("排序后的数组:\n");
printArray(arr, n);
return 0;
}
双链表:尾插法建立双链表,删除节点,查找节点
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//双向循环链表
typedef struct DuLNode {
int data;
struct DuLNode *prior;//直接前驱指针
struct DuLNode *next;//直接后继指针
} *DList, DLNode;
DLNode *BuyNode() {
DLNode *node = (DLNode *) malloc(sizeof(DLNode));
return node;
}
/**
* 尾插法建立链表
* @param l
* @param len
*/
void InitDListByTail(DLNode **l, int len) {
DLNode *head = BuyNode();
if (!head) {
printf(" InitListByTail fail .");
}
*l = head;
DLNode *r = head;
while (len > 0) {
int data = random() % 20;
DLNode *node = BuyNode();
if (!node) {
printf(" buy node fail .");
}
node->data = data;
r->next = node;
node->prior = r;
r = r->next;//指针指向最后一个节点
len--;
}
}
/**
* 按照位置插入,遍历的p指针应该指向插入位置的前一个节点,和单链表一样,还要考虑插入位置是最后
* 节点情况
* @param l
* @param index
* @param data
*/
void InsertOneByIndex(DLNode *l, int index, int data) {
if (index < 1) {
printf(" %d is not fit position,too small ", index);
return;
}
DLNode *p = l;
while (p && index > 1) {
p = p->next;
index--;
}
if (index != 1) {
printf(" %d is not fit position,too big ", index);
return;
}
DLNode *node = BuyNode();
if (p->next) {//插入位置不是最后一个
node->next = p->next;
p->next->prior = node;
}
p->next = node;
node->prior = p;
node->data = data;
}
DLNode *FindNodeByData(DLNode *l, int data) {
DLNode *p = l->next;
while (p) {
if (p->data == data)
return p;
p = p->next;
}
return NULL;
}
/**
* 删除p节点的后继节点
* @param p
*/
void DeleteNodeByPoint(DLNode *p) {
if (!p) {
printf(" this point is null");
return;
}
DLNode *a = p->next;//a指向的节点是要删除的节点
p->next = a->next;
a->next->prior = p;
free(a);
}
void PrintList(DLNode *p) {
printf("\n print :\n");
while (p != NULL) {
printf(" %d ,", p->data);
p = p->next;
}
}
int main() {
printf("Hello World, now we need create a double Linklist !\n");
DLNode *l;
InitDListByTail(&l, 5);
printf("print this new double linklist !\n");
PrintList(l->next);
printf("\ninsert one node \n");
InsertOneByIndex(l, 3, 90);
PrintList(l->next);
DLNode *p = FindNodeByData(l, 6);
printf("\n delete find one %d\n", p->data);
DeleteNodeByPoint(p);
PrintList(l->next);
return 0;
}
两个无序单链表,分别用指针A和B指向,合并成一个非递减单链表,用指针C指向
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//双向循环链表
typedef struct DuLNode {
char data;
struct DuLNode *prior;//直接前驱指针
struct DuLNode *next;//直接后继指针
} *list, List;
typedef struct LNode {
int data;
struct LNode *next;
} Node, *PNode;
PNode BuyNode() {
PNode node = (PNode) malloc(sizeof(Node));
return node;
}
/**
* 尾插法建立链表
* @param l
* @param len
*/
void InitListByTail(Node **l, int len) {
PNode head = BuyNode();
if (!head) {
printf(" InitListByTail fail .");
}
*l = head;
PNode t = head;
while (len > 0) {
int data = random() % 20;
Node *node = BuyNode();
if (!node) {
printf(" buy node fail .");
}
node->data = data;
t->next = node;
t = t->next;//指针指向最后一个节点
len--;
}
}
/**
* 将原无序链表变成非递减链表
* 在不申请新结点的基础上,在原来链表改动每个结点的next指向。
* 首先使用指针ol指向第一个结点(不是头结点),ol指向的是待排序链表,简称老链表
* 其次使用h指针指向头结点,将头结点的next置为NULL,h指向的是排序之后的链表,简称新链表
* 然后每次从老表中找到一个最大的,通过头插法插入到新链表中,直到老表为空
* @param l
*/
void SetListIncrement(Node **l) {
Node *p,//用于遍历循环找到最大节点,每次遍历到尾节点
*h = *l,//新链表的头指针
*f,//指向
*oh = (*l)->next,
*s;//
h->next = NULL;//新递增链表的头指针
while (oh) {
s = oh;
p = oh;
f = oh;
while (p && p->next) {
//每次找到最大的 用s指向最大值节点
p = p->next;
if (p->data > s->data) {
s = p;//找到最大的
}
}
while (f && f->next) {
if (f->next == s) {
break;
}
f = f->next;
}
//构造递增链表 1原来链表删除该节点 2新递增链表添加该节点
if (s == oh) {
oh = oh->next;//旧的单链表头指针不能丢失,永远指向第一个
} else {
f->next = f->next->next;//原来的链表保持连贯
}
//头插法建立递增单链表
s->next = h->next;
h->next = s;
}
}
/**
* 合并两个链表
* @param A
* @param B
* @param C
*/
void MergeList(PNode *A, PNode *B, PNode *C) {
*C = *A;//c指向a的头节点
Node *p = (*A)->next, *q = (*B)->next, *t = *C;
while (p != NULL && q != NULL) {
if (p->data > q->data) {
t->next = q;
q = q->next;
} else {
t->next = p;
p = p->next;
}
t = t->next;
}
if (p != NULL)
t->next = p;
if (q != NULL)
t->next = q;
free(*B);
}
void PrintList(Node *p) {
printf("\n print :\n");
while (p != NULL) {
printf(" %d ,", p->data);
p = p->next;
}
}
void InitIt(list *l) {
list q = (list) malloc(sizeof(List));
q->data = 'a';
*l = q;
}
int main() {
printf("Hello, World!\n");
Node *A, *B, *C;
InitListByTail(&A, 3);
InitListByTail(&B, 5);
PrintList(A->next);
PrintList(B->next);
SetListIncrement(&A);
SetListIncrement(&B);
printf("\n after merge :");
MergeList(&A, &B, &C);
PrintList(C->next);
return 0;
}
线性表的链式存储 带头节点的单链表
#include <stdio.h>
#include <stdlib.h>
#define NULL 0
//带头节点的单链表
typedef struct LNode {
char data;
struct LNode *next;
} LNode, *LinkList;
LinkList InitLinkList() {
LinkList head = (LinkList) malloc(sizeof(LNode));
if (!head) {
printf("initialize fail !\n");
}
head->data = '1';
head->next = NULL;
return head;
}
LinkList BuyNode() {
LinkList node = (LinkList) malloc(sizeof(LNode));
if (!node) {
printf("buy fail !\n");
}
return node;
}
/**
* 按照位置插入
* @param l
* @param index
* @param e
*/
void InsertOneByPos(LinkList l, int index, char e) {
LinkList f = l->next;
//判断插入位置是否合理
if (index < 1) {
printf("this position is not fit !");
return;
}
int len = 0;
while (f != NULL) {
f = f->next;
len++;
}
if (len + 1 < index) {
printf("this position is not fit !");
return;
}
LinkList p = BuyNode();
LinkList r = l;
int i = 1;
//找到插入位置的前一个节点
while (i < index) {
r = r->next;
i++;
}
p->next = r->next;
p->data = e;
r->next = p;
}
/**
* 头插入法
* 比如说当前列表是 head -> h -> e
* 现在要插入的数据是 a
* 插入完之后链表内容是:head ->a -> h -> e
* @param l
* @param e
*/
void InsertOneFromHead(LinkList l, char e) {
LinkList p = BuyNode();
if (!p) {
printf("apply node fail !\n");
}
p->next = l->next;
p->data = e;
l->next = p;
}
/**
* 尾插入法
* 比如说当前列表是 head -> h -> e
* 现在要插入的数据是 a
* 插入完之后链表内容是:head -> h -> e ->a
* @param l
* @param e
*/
void InsertOneFromTail(LinkList l, char e) {
LinkList p = BuyNode();
LinkList f = l;
//找到最后一个节点
while (f->next != NULL) {
f = f->next;
}
p->data = e;
p->next = f->next;
f->next = p;
}
//打印链表
void PrintLinkList(LinkList l) {
printf("\nstart print :\n");
for (LinkList i = l; i != NULL; i = i->next) {
printf("%c ", i->data);
}
}
int main() {
printf("\nHello, World!\n");
LinkList l = InitLinkList();
InsertOneFromTail(l, 'h');
InsertOneFromTail(l, 'e');
InsertOneFromTail(l, 'l');
InsertOneFromTail(l, 'l');
InsertOneFromTail(l, 'o');
InsertOneFromTail(l, '.');
InsertOneByPos(l,8,'X');
PrintLinkList(l);
return 0;
}
线性表顺序存储
#include <stdio.h>
#include <stdlib.h>
#define LIST_INIT_SIZE 10
//线性表的顺序存储结构
typedef struct {
char *elem;
int length;//当前长度
int list_size;//分配空间的长度
} sqList, *Link;
//初始化
int InitList(sqList *L) {
L->elem = (char *) malloc(LIST_INIT_SIZE * sizeof(char));
if (!L->elem) {
printf("fail");
} else {
printf("ok\n");
}
L->length = 0;
L->list_size = LIST_INIT_SIZE;
}
//插入元素
void InsertOne(sqList *l, char e, int i) {
//先判断位置是否正确
if (i < 1 || i > LIST_INIT_SIZE) {
printf("not ok, it's too big position ! \n");
}
if (i == 1 && l->length == 0) {
*l->elem = e;
} else {
char *q = l->elem + i-1;
//找到插入位置
for (char *p = &l->elem[l->length - 1]; p >= q; --p) {
*(p + 1) = *p;
}
*q = e;
}
l->length++;
}
//遍历顺序存储线性表
void PrintList(char *p, int length) {
printf("\nl.length = %d \n", length);
char *s = p;
while (s < p + length) {
printf("%c ", *s);
s++;
}
}
int main() {
sqList l;
InitList(&l);
InsertOne(&l, 'h', 1);
InsertOne(&l, 'e', 2);
PrintList(l.elem, l.length);
return 0;
}