冒泡排序
冒泡排序是一种基础的排序算法,它遍历整个待排序的数组,逐对比较相邻的两个元素,如果它们的顺序错误(比如前面的比后面的大),就将它们交换位置。
排序的过程是从数组的一端开始,逐对比较每一对相邻元素,并根据需要交换位置。每一轮排序都保证了最大(或最小)的元素移动到数组的一端,然后在剩余的元素中重复这个过程,每次需要比较的元素数量减一,直到没有元素需要比较为止。
#include <stdio.h>
void bubble_sort(int arr[], int n) {
int i, j, temp;
for(i = 0; i < n-1; i++){
int is_swapped = 0; // 添加标志位,用于判断数组是否已经排序好
for(j = 0; j < n-i-1; j++){
if(arr[j] > arr[j+1]){
temp = arr[j]; // 交换元素的位置
arr[j] = arr[j+1];
arr[j+1] = temp;
is_swapped = 1; // 存在交换,更改标志位
}
}
if(is_swapped == 0) break; // 若一轮比较下来没有发生交换,则终止排序
}
}
int main() {
int i, len;
int arr[] = {10, 34, 78, 54, 87, 67};
len = sizeof(arr)/sizeof(arr[0]); // 计算数组的长度
bubble_sort(arr, len); // 对数组进行排序
printf("排序后的数组为:\n");
for(i = 0; i < len; i++) { // 输出排序后的结果
printf("%d ", arr[i]);
}
return 0;
}
这段代码首先定义了一个冒泡排序的函数bubble_sort。这个函数接受一个整型数组和一个整数n(代表数组长度)作为输入。
在bubble_sort函数中,我们有两个循环。外部循环控制排序的总轮数,内部循环进行每轮的比较和交换。我们添加了一个标志位is_swapped,如果一轮比较中没有元素交换位置,那么我们可以提前结束排序,因为这意味着数组已经被排序好了。
在主函数main中,我们定义了一个整型数组arr,并通过sizeof运算符计算得到数组的长度len。然后调用bubble_sort来排序这个数组,并且打印出排序后的结果。
实际应用:冒泡排序是一个简单但效率较低的排序算法,它虽然不适合处理大规模的数据,但可以用在一些小规模且对效率要求不高的场景,比如学生的分数排序、电子商务平台的商品价格排序等。
附:实际应用
#include <stdio.h>
typedef struct {
char name[50];
int score;
} Student;
void bubble_sort(Student arr[], int n) {
int i, j;
Student temp;
for(i = 0; i < n-1; i++){
for(j = 0; j < n-i-1; j++){
if(arr[j].score < arr[j+1].score){ // 比较每对学生的成绩,若前一名学生的分数小于后一名,就交换他们
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
int main() {
int i, len;
// 定义一个学生成绩数组
Student students[] = {{"Alice", 85}, {"Bob", 90}, {"Charlie", 80}, {"Dave", 95}, {"Eve", 92}};
len = sizeof(students)/sizeof(students[0]);
// 对学生的成绩进行冒泡排序
bubble_sort(students, len);
printf("按照成绩降序排序后的学生成绩为:\n");
for(i = 0; i < len; i++) {
printf("%s: %d\n", students[i].name, students[i].score); // 输出排序后的学生名字和对应成绩
}
return 0;
}
这段代码首先定义了一个学生结构体Student实例,包含学生的姓名和分数两个字段。然后我们定义了一个冒泡排序函数bubble_sort,该函数接受一个Student类型的数组和一个整数n(代表数组长度)作为输入。
在bubble_sort函数中,我们会遍历Student数组,并按照分数将学生进行排序。我们会比较每对相邻学生的分数,如果前面的学生分数小于后面的学生,我们就交换他们的位置。直到数组已经完全排序为止。
在主函数main中,我们初始化了一个Student数组,并使用sizeof运算符来计算数组的长度。然后,我们调用了bubble_sort函数对学生名单进行排序。最后,我们遍历并打印出排序后的学生成绩。
快速排序
快速排序是一种效率高且常用的排序方式。它的基本思想是,选择一个基准值(Pivot),通过一趟排序后,将待排序的记录分割成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,然后分别对这两部分进行排序,以达到整个序列有序的目标。
#include <stdio.h>
void bubble_sort(int arr[], int n) {
int i, j, temp;
for(i = 0; i < n-1; i++){
int is_swapped = 0; // 添加标志位,用于判断数组是否已经排序好
for(j = 0; j < n-i-1; j++){
if(arr[j] > arr[j+1]){
temp = arr[j]; // 交换元素的位置
arr[j] = arr[j+1];
arr[j+1] = temp;
is_swapped = 1; // 存在交换,更改标志位
}
}
if(is_swapped == 0) break; // 若一轮比较下来没有发生交换,则终止排序
}
}
int main() {
int i, len;
int arr[] = {10, 34, 78, 54, 87, 67};
len = sizeof(arr)/sizeof(arr[0]); // 计算数组的长度
bubble_sort(arr, len); // 对数组进行排序
printf("排序后的数组为:\n");
for(i = 0; i < len; i++) { // 输出排序后的结果
printf("%d ", arr[i]);
}
return 0;
}
这段代码首先定义了一个快速排序的函数quicksort。这个函数接受一个整型数组,并有两个整数low和high作为输入,分别代表了待排序的数组区间。另一个函数partition,将数组的指定区间分成两个独立的部分,其中左边的部分所有元素都与右边的部分所有元素相比较都小。
在quicksort函数中,我们首先会判断当前待排序的数组区间是否有效(即low < high)。如果有效,那么就通过partition函数选取一个基准值,并将数组分割成两部分,然后对每一部分进行递归排序。如果待排序的数组区间无效,那么直接返回。
快速排序的实际应用很广泛,从各种数据的排序,如学生的分数排序,电子商务平台商品价格排,等等,都可以用到快速排序。
附:实际应用
#include <stdio.h>
typedef struct {
char name[50];
int score;
} Student;
void swap(Student* a, Student* b) {
Student t = *a;
*a = *b;
*b = t;
}
int partition(Student arr[], int low, int high) {
int pivot = arr[high].score;
int i = low - 1;
for(int j = low; j <= high - 1; j++) {
if(arr[j].score > pivot) { // 对学生成绩进行比较,如果当前元素大于pivot,与i+1位置的元素交换,并将i增加1
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]); // 将pivot移到正确的位置
return i + 1; // 返回pivot的位置
}
void quick_sort(Student arr[], int low, int high) {
if(low < high) {
int pi = partition(arr, low, high);
quick_sort(arr, low, pi - 1); // 分别对pivot左侧和右侧的元素进行递归排序
quick_sort(arr, pi + 1, high);
}
}
int main() {
int i, len;
// 定义学生成绩数组
Student students[] = {{"Alice", 85}, {"Bob", 90}, {"Charlie", 80}, {"Dave", 95}, {"Eve", 92}};
len = sizeof(students)/sizeof(students[0]);
// 对学生的成绩进行快速排序
quick_sort(students, 0, len - 1);
printf("按照成绩降序排序后的学生成绩为:\n");
for(i = 0; i < len; i++) {
printf("%s: %d\n", students[i].name, students[i].score); // 输出排序后的学生信息
}
return 0;
}
这段代码首先定义了一个学生结构体Student,包含学生的姓名和分数两个字段。然后我们定义了一个快速排序函数quick_sort,该函数接受一个Student类型的数组和两个整数low和high作为输入,分别表示待排序数组区间的起始和结束下标。
在quick_sort函数中,我们会使用partition函数将待排序的数组区间以一个pivot为界分成两个部分,所有较大的元素都在该pivot左侧,而所有较小的元素都在右侧。然后我们对pivot左侧和右侧的元素分别进行递归排序。最终,我们会得到一个有序的学生成绩列表。
在主函数main中,我们初始化了一个Student数组,并使用sizeof运算符计算出数组的长度。然后我们调用了quick_sort函数对学生名单进行排序,最后,我们遍历并打印出排序后的学生成绩。
链表
链表的节点定义
在C语言中,链表的节点通常通过结构体定义。结构体中不仅包含存储数据的变量,还有一个或多个指针指向其它节点,实现链式连接。
示例代码:定义单向链表的节点
typedef struct Node {
int data; // 数据部分
struct Node *next; // 指向下一个节点的指针
} Node;
创建链表
创建链表通常涉及到初始化头节点,并依次添加新节点。
示例代码:创建链表和添加新节点
#include <stdio.h>
#include <stdlib.h>
// 链表节点的定义
typedef struct Node {
int data;
struct Node *next;
} Node;
// 创建一个节点并返回其指针
Node* createNode(int data) {
Node *newNode = (Node*)malloc(sizeof(Node));
if (newNode == NULL) {
perror("Unable to allocate memory for new node");
exit(1);
}
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// 添加节点到链表末尾
void appendNode(Node **head, int data) {
Node *newNode = createNode(data);
if (*head == NULL) { // 如果链表为空,新节点即为头节点
*head = newNode;
} else {
Node *current = *head;
while (current->next != NULL) { // 遍历到链表末尾
current = current->next;
}
current->next = newNode; // 将新节点添加到链表末尾
}
}
int main() {
Node *head = NULL; // 初始化链表头节点为NULL
appendNode(&head, 1); // 向链表中添加数据
appendNode(&head, 2);
appendNode(&head, 3);
// ...
return 0;
}
遍历链表
遍历链表通常通过循环结构实现,从头节点开始,通过指针访问链表的每个节点。
示例代码:遍历链表并打印节点数据
void printList(Node *head) {
Node *current = head;
while (current != NULL) {
printf("%d ", current->data);
current = current->next; // 移至下一个节点
}
printf("\n");
}
删除链表节点
删除链表节点需要注意改变相应节点的指针,确保链表的连续性不被破坏。
示例代码:删除链表中的节点
void deleteNode(Node **head, int key) {
Node *temp = *head, *prev = NULL;
// 如果头节点就是要删除的节点
if (temp != NULL && temp->data == key) {
*head = temp->next; // 改变头指针
free(temp); // 释放内存
return;
}
// 查找需要删除的节点
while (temp != NULL && temp->data != key) {
prev = temp;
temp = temp->next;
}
// 如果没有找到
if (temp == NULL) return;
// 从链表中移除节点
prev->next = temp->next;
// 释放内存
free(temp);
}