1、数据结构
1.1 动态数组
用C语言实现动态数组
1. 数组特点
存储特点: 内存是连续存储
优点: 查找快
缺点: 插入、删除低效
2. 如何实现动态可扩展数组
① 先分配一块内存 malloc() calloc()
② 如果内存不够,realloc() 扩容
③ 程序结束前,释放内存
代码实现
1.定义动态数组结构体并进行初始化/释放操作
定义结构体
// 定义元素类型
typedef int ele_type;
// 定义结构体 表示动态数组类型
typedef struct
{
ele_type *data; // 存储元素的内存区域地址
size_t size; // 以存储的元素个数,动态数组的长度
size_t capacity; // 动态数组的最大容量
} DynamicArray;
初始化数组
/**************************************************************
* @brief 初始化动态数组
*
* @param DynamicArray dyarray 需要进行初始化的动态数组
* @param size_t initialCapacity 初始化容量
***************************************************************/
void initDynamicArray(DynamicArray *dyarray, size_t initialCapacity)
{
// 动态开辟内存
dyarray->data = (ele_type *)malloc(initialCapacity * sizeof(ele_type));
// 设置初始化长度和容量
dyarray->size = 0;
dyarray->capacity = initialCapacity;
}
释放动态数组内存
/**************************************************************
* @brief 释放动态数组内存
*
* @param DynamicArray *dyarray 要释放的动态数组
***************************************************************/
void destroyDynamicArray(DynamicArray *dyarray)
{
// 释放动态开辟的内存区域
free(dyarray->data);
// 重置成员的值
dyarray->data = NULL;
dyarray->size = 0;
dyarray->capacity = 0;
}
2.动态数组的增删改查
增:调整动态数组的内存大小
/* @brief 调整动态数组内存大小
* @param DynamicArray *dyarray 要调整的动态数组
* @param size_t newCapacity 新的数组容量
*/
void resizeDynamicArray(DynamicArray *dyarray, size_t newCapacity)
{
// 动态调整数组容量大小
dyarray->data = (ele_type *)realloc(dyarray->data, newCapacity * sizeof(ele_type));
// 调整容量值
dyarray->capacity = newCapacity;
}
删:删除指定/末尾位置的元素
/**************************************************************
* @brief 删除指定位置的元素
*
* @param DynamicArray *dyarray 动态数组
* @param size_t index 位置
* @return ele_type 被删除的元素值
***************************************************************/
ele_type deleteAt(DynamicArray *dyarray, size_t index)
{
// 如果位置不在合理范围内
if (index < 0 || index >= dyarray->size)
{
return -1;
}
// 保存被删元素
ele_type deletedElement = dyarray->data[index];
// 从删除位置开始,依次将后面元素的值赋值到最前面的元素
for (size_t i = index; i < dyarray->size - 1; i++)
{
dyarray->data[i] == dyarray->data[i + 1];
}
// 长度递减
dyarray->size--;
// 返回
return deletedElement;
}
/**************************************************************
* @brief 删除末尾元素
*
* @param DynamicArray *dyarray 动态数组
* @return ele_type 被删除的元素值
***************************************************************/
ele_type deleteEnd(DynamicArray *dyarray)
{
return deleteAt(dyarray, dyarray->size - 1);
}
改:在指定/末尾位置插入新元素
/**************************************************************
* @brief 指定位置插入新元素
* @param DynamicArray *dyarray 动态数组
* @param size_t index 位置
* @param ele_type element 新元素值
***************************************************************/
void insertAt(DynamicArray *dyarray, size_t index, ele_type element)
{
// 如果位置不在合理范围内
if (index < 0 || index > dyarray->size)
{
return;
}
// 如果容量已满 需要扩容
if (dyarray->size == dyarray->capacity)
{
resizeDynamicArray(dyarray, dyarray->capacity * 2);
}
// 循环 从插入位置起,元素依次赋值给后面的元素
for (size_t i = dyarray->size; i > index; i--)
{
// 将前面元素的值赋值给后面的元素
dyarray->data[i] = dyarray->data[i - 1];
}
// 将新元素赋值到指定位置
dyarray->data[index] = element;
// 长度递增
dyarray->size++;
}
/**************************************************************
* @brief 在末尾插入新元素
*
* @param DynamicArray *dyarray 动态数组
* @param ele_type element 新元素值
***************************************************************/
void insertEnd(DynamicArray *dyarray, ele_type element)
{
insertAt(dyarray, dyarray->size, element);
}
查:遍历动态数组
/**************************************************************
* @brief 遍历数组所有的元素
* @param DynamicArray *dyarray 动态数组
***************************************************************/
void printDynamicArray(DynamicArray *dyarray)
{
for (size_t i = 0; i < dyarray->size; i++)
{
printf("%d ", dyarray->data[i]);
}
printf("\n");
}
3.main()
int main()
{
// 定义动态数组(结构体变量)
DynamicArray da;
// 动态数组的初始化
initDynamicArray(&da, 4);
// 添加新元素,依次在最后面添加
insertEnd(&da, 100);
insertEnd(&da, 200);
insertEnd(&da, 300);
insertEnd(&da, 400);
insertEnd(&da, 500);
// 在指定位置添加新元素
insertAt(&da, 2, 250);
// 删除最后一个元素
deleteEnd(&da);
// 删除指定元素
printf("被删除的元素是:%d \n", deleteAt(&da, 2));
printf("被删除的元素是:%d \n", deleteAt(&da, 3));
// 遍历数组
printDynamicArray(&da);
// 获取数组长度
printf("动态数组长度:%zu \n", getLenth(&da));
// 释放动态数组的内存
destroyDynamicArray(&da);
return 0;
}
4.总结
难点在于插入和删除操作,如何通过代码来实现。插入操作逻辑是在任意位置插入新元素时,从插入位置起,需要将前面的元素依次赋值给后面的元素。删除相反。
1.2 链表
1. 链表分类
单向链表、双向链表、循环单向链表、循环双向链表
2. 链表特点
存储特点: 不一定是连续的空间,节点中使用指针指向下一个节点
优点: 插入、删除节点高效
缺点: 查找慢
3. 如何实现单向链表
节点的结构体: 数据、下一个节点地址
如何查找节点
如何增加节点
如何删除节点
代码实现
1.定义结构体表示节点/链表,并初始化和释放链表
// 定义结构体 表示节点
typedef struct Node //(节点名,结构体名称Node)
{
ele_type data; // 节点中的数据
struct Node *next; // 指向下一个节点的地址
} Node; // (别名Node,指代struct Node)
// 定义结构体 表示整个链表
typedef struct
{
Node *head; // 第一个节点的地址
size_t size; // 链表中节点的数量(链表长度)
} LinkedList;
初始化/释放链表
/**************************************************************
* @brief 初始化链表
*
* @param LinkedList *list 需要初始化的链表
***************************************************************/
void initLinkedList(LinkedList *list)
{
// 给成员赋初始值
list->head = NULL;
list->size = 0;
}
/**************************************************************
* @brief 释放链表内存
*
* @param LinkedList *list 链表
***************************************************************/
void destoryLinkedList(LinkedList *list)
{
// 获取第一个节点
// nodeELe 用于保存遍历过程中的每一个节点
Node *nodeELe = list->head;
// 循环 依次释放每一个节点的内存空间
while (nodeELe != NULL)
{
// 先把当前节点存下来
Node *tmp = nodeELe;
// 获取到下个节点
nodeELe = nodeELe->next;
free(tmp);
}
// 重置链表长度
list->head = NULL;
list->size = 0;
}
链表释放需要一个一个释放
2.链表的增加/删除
/**************************************************************
* @brief 在指定位置插入节点
*
* @param LinkedList *list 链表
* @param size_t index 位置 (下标、索引,从0开始)
* @param ele_type element 新节点的数据值
***************************************************************/
void insertAt(LinkedList *list, size_t index, ele_type element)
{
// 排除不合理的值
if (index < 0 || index > list->size)
{
return;
}
// 为新节点分配内存空间,并使用变量保存新节点
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->data = element;
newNode->next = NULL;
// 如果在最前面插入节点
if (index == 0)
{
// 新节点的next 先指向原来的第一个节点
newNode->next = list->head;
// 再把 链表中的head 指向新节点
list->head = newNode;
}
else // 新节点在中间位置插入
{
// 获取到前一个节点
Node *prevNode = getPrevNode(list, index);
// 让新节点指向下个节点
newNode->next = prevNode->next;
// 让上个节点指向新节点
prevNode->next = newNode;
}
// 链表长度递增
list->size++;
}
/**************************************************************
* @brief 在末尾位置插入节点
*
* @param LinkedList *list 链表
* @param ele_type element 新节点的数据值
***************************************************************/
void insertEnd(LinkedList *list, ele_type element)
{
insertAt(list, list->size, element);
}
/**************************************************************
* @brief 删除指点位置的节点
*
* @param LinkedList *list 链表
* @param size_t index 位置 (下标、索引,从0开始)
* @return int 被删除节点的数据值
***************************************************************/
ele_type deletAt(LinkedList *list, size_t index)
{
// 如果不在合理范围内
if (index < 0 || index >= list->size)
{
return -1;
}
// 定义变量 用于存储即将被删除的节点
Node *deletedNode = NULL;
// 如果要删除的节点是 第一个
if (index == 0)
{
// 定义变量 存储即将被删除的元素
deletedNode = list->head;
// 让 list->head 指向该节点的下一个节点
// list->head = list->head->next;
list->head = deletedNode->next;
}
else // 要被删除的节点不是第一个
{
// 获取要被删除元素的前一个结点
Node *prevNode = getPrevNode(list, index);
// 定义变量 存储即将被删除的元素
deletedNode = prevNode->next;
// 让前一个节点指向被删除节点的下一个
prevNode->next = deletedNode->next;
}
// 定义变量 存储被删除节点的数据值
ele_type deletdElement = deletedNode->data;
// 释放被删除节点内存的空间
free(deletedNode);
// 链表长度递减
list->size--;
// 返回被删除节点的元素值
return deletdElement;
}
/**************************************************************
* @brief 删除末尾位置的节点
*
* @param LinkedList *list 链表
* @return int 被删除节点的数据值
***************************************************************/
ele_type deletEnd(LinkedList *list)
{
return deletAt(list, list->size - 1);
}
3.链表的修改/遍历
/**************************************************************
* @brief 修改指定位置元素的值
*
* @param LinkedList *list 链表
* @param size_t index 位置 (下标、索引,从0开始)
* @return int 节点值
***************************************************************/
void modifyAt(LinkedList *list, size_t index, ele_type element)
{
// 排除不合理的值
if (index < 0 || index >= list->size)
{
return -1;
}
// 定义变量存储当前节点到index对应的节点
Node *currentNode;
// 如果获取的是第一个节点
if (index == 0)
{
currentNode = list->head;
}
else // 获取的不是第一个节点
{
// 先获取指定位置的前一个节点
Node *prevNode = getPrevNode(list, index);
currentNode = prevNode->next;
}
// 修改当前节点的值
currentNode->data = element;
}
/**************************************************************
* @brief 循环打印链表中的数据
* @param LinkedList *list 链表的地址
***************************************************************/
void printLinkedList(LinkedList *list)
{
// 获取第一个节点
Node *nodeELe = list->head;
// 循环 继续打印后面节点的内容
while (nodeELe != NULL)
{
// 打印当前节点的数据值
printf("%d ", nodeELe->data);
// 让 nodeELe 指向下一个节点
nodeELe = nodeELe->next;
}
}
获得指定位置的前一个节点
/**************************************************************
* @brief 获取指定位置的前一个节点
*
* @param LinkedList *list 链表
* @param size_t index 位置 (下标、索引,从0开始)
* @return 指定位置的前一个结点
***************************************************************/
Node *getPrevNode(LinkedList *list, size_t index)
{
// 先定义变量保存上一个节点 从第一个节点开始
Node *prevNode = list->head;
// 没开始循环前 prveNode 已经指向0节点(第一个节点)
// 为了循环变量与prevNode指向的节点的下标对应,循环从1开始
for (size_t i = 1; i < index; i++)
{
prevNode = prevNode->next;
}
// 返回前一个节点
return prevNode;
}
1.3 栈
1. 特点
先进后出、后进先出
2. 名词
栈顶(增加、删除的一端)
栈底
进栈(压栈)
出栈(弹栈)
代码实现
1.定义栈的结构体,进行初始化/释放操作
// 定义栈结构体
typedef struct
{
element_t *data; // 内存区域地址
size_t size; // 已存储元素的个数(长度)
size_t capacity; // 栈的最大容量
} Stack;
/**************************************************************
* @brief 初始化栈
*
* @param Stack *stack 要初始化的栈
* @param size_t initalCapacity 起始容量
***************************************************************/
void initStack(Stack *stack, size_t initalCapacity)
{
// 分配内存
stack->data = (element_t *)malloc(initalCapacity * sizeof(element_t));
// 初始化容量和长度
stack->size = 0;
stack->capacity = initalCapacity;
}
/**************************************************************
* @brief 释放栈内存
*
* @param Stack *stack 要初始化的栈
***************************************************************/
void destoryStack(Stack *stack)
{
free(stack->data);
// 重置成员值
stack->data = NULL;
stack->size = 0;
stack->capacity = 0;
}
2.进栈/出栈操作
/**************************************************************
* @brief 进栈(添加元素)
*
* @param Stack *stack 栈
* @param element_t element 要添加的元素
*
***************************************************************/
void pushStack(Stack *stack, element_t element)
{
// 如果容量不够 扩容
if (stack->size == stack->capacity)
{
resizeStack(stack, stack->capacity * 2);
}
// 在数组尾部添加元素
stack->data[stack->size] = element;
// 修改长度 递增
stack->size ++;
}
/**************************************************************
* @brief 出栈(删除元素)
*
* @param Stack *stack 栈
* @param element_t 被删除的元素
***************************************************************/
element_t popStack(Stack *stack)
{
// 如果空栈
if (stack->size == 0)
{
return -1;
}
// 长度递减(最后一个元素不纳入管理,出栈)
stack->size --;
// 返回被删除的元素
return stack->data[stack->size];
}
3.遍历
/**************************************************************
* @brief 遍历
*
* @param Stack *stack 要打印的栈
***************************************************************/
void printStack(Stack *stack)
{
for (size_t i = 0; i < stack->size; i++)
{
printf("%d ",stack->data[i]);
}
printf("\n");
}
4.其他
/**************************************************************
* @brief 调整栈内存容量
*
* @param Stack *stack 要调整内存的栈
* @param size_t newCapacity 新容量
***************************************************************/
void resizeStack(Stack *stack, size_t newCapacity)
{
// 调整内存容量
stack->data = (element_t *)realloc(stack->data, newCapacity * sizeof(element_t));
// 设置成员
stack->capacity = newCapacity;
}
/**************************************************************
* @brief 获取栈长度(元素个数)
*
* @param Stack *stack 要获取长度的栈
* @param size_t 栈长度(元素个数)
***************************************************************/
size_t getSize(Stack *stack)
{
return stack->size;
}
1.4 队列(Queue)
1 特点
先进先出、后进后出
2. 名词
对头(在队头删除)
队尾(在队尾插入)
入队
出队
代码实现
1.定义结构体表示队列,进行初始化赋值和释放操作
// 定义结构体 表示队列
typedef struct
{
element_t *data; // 指向存储数据的内存
size_t size; // 队列长度(已存储元素个数)
size_t capacity; // 最大容量
size_t front; // 队头(删除元素的位置)
size_t rear; // 队尾(添加元素的位置)
} Queue;
/**************************************************************
* @brief 初始化队列
*
* @param Queue *queue // 要初始化的队列
* @param size_t capacity // 最大容量
***************************************************************/
void initQueue(Queue *queue, size_t capacity)
{
// 分配内存空间
queue->data = (element_t *)malloc(capacity * sizeof(element_t));
// 成员赋值
queue->size = 0;
queue->capacity = capacity;
queue->front = 0;
queue->rear = 0;
}
/**************************************************************
* @brief 释放队列
*
* @param Queue *queue 要释放的队列
***************************************************************/
void destoryQueue(Queue *queue)
{
// 释放
free(queue->data);
// 重置成员
queue->data = NULL;
queue->size = 0;
queue->capacity = 0;
queue->front = 0;
queue->rear = 0;
}
2.入队/出队
/**************************************************************
* @brief 入队(添加元素)
*
* @param Queue *queue 队列
* @param element_t element 需要添加的元素
***************************************************************/
void enqueue(Queue *queue, element_t element)
{
// 如果队列已满, 不再添加元素
if (queue->size == queue->capacity)
{
printf("队列已满! 入队失败!\n");
return;
}
// 在队尾添加元素
queue->data[queue->rear] = element;
// 队列递增
queue->size ++;
// 队尾递增 队尾永远保存即将添加的位置
queue->rear = (queue->rear + 1) % queue->capacity;
// queue->rear ++;
// if (queue->rear > queue->capacity - 1)
// {
// queue->rear = 0;
// }
}
/**************************************************************
* @brief 出队(删除元素)
* @param Queue *queue 队列
* @return element_t 返回被删除的元素
***************************************************************/
element_t dequeue(Queue *queue)
{
// 如果是空队列
if (queue->size == 0)
{
return -1;
}
// 返回出队的元素
element_t dequeuedElement = queue->data[queue->front];
// 让队头递增 指向下一个
queue->front = (queue->front + 1) % queue->capacity;
// 长度递减
queue->size --;
// 返回
return dequeuedElement;
}
3.遍历及其他
/**************************************************************
* @brief 获取队列长度(元素个数)
* @param Queue *queue 队列
* @return size_t 队列长度
***************************************************************/
size_t getSize(Queue *queue)
{
return queue->size;
}
/**************************************************************
* @brief 打印队列元素
* @param Queue *queue 队列
***************************************************************/
void printQueue(Queue *queue)
{
// 循环 循环size 次
for (size_t i = 0; i < queue->size; i++)
{
// 获取到元素的下标
size_t index = (queue->front + i) % queue->capacity;
printf("%d ",queue->data[index]);
}
}
4.总结
1. 循环队列的初始化:需要初始化队列的头尾指针,并且需要额外一个变量来记录队列中元素的个数。 2. 循环队列的入队操作:需要考虑队列满的情况,需要移动头尾指针来实现循环。 3. 循环队列的出队操作:同样需要考虑队列为空的情况,并且需要移动头尾指针来实现循环。 4. 循环队列的空间复杂度分析:循环队列的空间复杂度为O(n),其中n为队列的最大容量。 5. 循环队列的应用:循环队列常用于需要频繁进行插入和删除操作的场景,如缓冲区、任务调度等。
2、算法
2.1 查找算法
1.顺序查找
代码实现
#include <stdio.h>
// 顺序查找
// 参数 数组 、长度、元素
// 返回: 位置
int sequenceSearch(int arr[], int len, int element)
{
// 计算数组长度
//int len = sizeof(arr) / sizeof(int);
// 循环
for (int i = 0; i < len; i++)
{
if (arr[i] == element)
{
return i; // 找到元素,返回索引
}
}
// 循环结束 还未找到数组
return -1;
}
int main()
{
int nums[6] = {10,11,7,89,56,563};
printf("89在数组中的位置:%d \n", sequenceSearch(nums, 6, 89));
return 0;
}
2.二分查找
代码实现
#include <stdio.h>
// 二分查找法
int binarySearch(int arr[], int len, int element)
{
// 定义变量 分别保存第一个元素和最后一个元素的索引
int left = 0, right = len - 1;
// 循环 条件:要找的范围有元素的
while (left <= right)
{
// 获取中间元素
int mid = (left + right) / 2;
// 判断要查找的元素与中间元素是否相等
if (element == arr[mid])
{
return mid;
}
// 如果要查找的元素小于中间元素
if (element < arr[mid])
{
right = mid - 1;
}
else
{
// 如果要查找的元素大于中间元素
left = mid + 1;
}
}
// 循环结束 没有找到 返回-1
return -1;
}
int main()
{
int nums[] = {10,20,30,40,50,60,70,80,90};
printf("20的位置:%d \n", binarySearch(nums, 9, 90));
return 0;
}
适用于排好序的数据
2.2 排序算法
1.冒泡排序
代码实现
#include <stdio.h>
// 冒泡排序的函数
void bubbleSort(int nums[], int len)
{
// 外层循环 控制轮数
for (int k = 1; k < len; k++)
{
// 内层循环 具体比较
for (int i = 0; i < len - k; i++)
{
// 比较相邻两个数的大小 如果前面的元素值大,交换两个元素的值
if (nums[i] > nums[i + 1])
{
int temp = nums[i];
nums[i] = nums[i + 1];
nums[i + 1] = temp;
}
}
printf("经过第%d轮比较的数组:", k);
printArr(nums, len);
}
}
// 打印数组元素
void printArr(int arr[], int len)
{
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
printf("\n\n");
}
int main()
{
// 定义数组
int nums[9] = {3000, 500, 869, 666, 1523, 6394, 52, 13, 69};
int len = 9;
printArr(nums, len);
bubbleSort(nums, len);
// // 第一轮比较 将最大元素放在最后
// for (int i = 0; i < len - 1; i++)
// {
// // 比较相邻两个数的大小 如果前面的元素值大,交换两个元素的值
// if (nums[i] > nums[i + 1])
// {
// int temp = nums[i];
// nums[i] = nums[i + 1];
// nums[i + 1] = temp;
// }
// }
// printf("经过第一轮比较:");
// printArr(nums, len);
// // 第二轮比较 将最大元素放在最后
// for (int i = 0; i < len - 2; i++)
// {
// // 比较相邻两个数的大小 如果前面的元素值大,交换两个元素的值
// if (nums[i] > nums[i + 1])
// {
// int temp = nums[i];
// nums[i] = nums[i + 1];
// nums[i + 1] = temp;
// }
// }
// printf("经过第二轮比较:");
// printArr(nums, len);
return 0;
}
使用循环嵌套的方式来实现冒泡排序,外层循环控制轮数,内层循环具体实现冒泡排序,由规律len-1,len-2,len-3等可知,内层循环的次数正好是 len 减去外层循环的次数即 len - k 。
2.快速排序
代码实现
#include <stdio.h>
/**
* [12, 1, 3, 5, 7, 13, 14, 15, 21];
* 基准 12
* 从左到右找第一个比12大的是 13,索引 5 low
* 从右到左找第一个比12小的是 7,索引 4 high
*
* 基准元素与high换值
* [7, 1, 3, 5, 12, 13, 14, 15, 21];
*
*/
// 定义函数 交换两个变量的值
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
// 快速排序的函数
// 参数1 数组
// 参数2 首元素索引
// 参数3 尾元素索引
void quickSort(int arr[], int start, int end)
{
// 如果要排序的数组中只有一个元素,结束
if (start >= end)
{
return;
}
// 定义从前向后的指针
int low = start;
// 定义从后向前的指针
int high = end + 1;
// 从前向后查找第一个比基准元素大的元素
// while (low <high)
// {
// low ++;
// if (arr[start] < arr[low])
// {
// break;
// }
// }
// 一轮比较,确定基准元素应该待的位置
while (1)
{
// 从前向后查找第一个比基准元素大的元素
while (low < high && arr[start] >= arr[++low])
;
// 从后向前查找第一个比基准元素小的元素
while (start < high && arr[start] <= arr[--high])
;
// 判断 如果 low < high ,没有交叉,交换两个元素的值
if (low < high)
{
swap(&arr[low], &arr[high]);
}
else
{
// 结束本轮的比较
break;
}
}
// high位置元素与基准元素换值
swap(&arr[start], &arr[high]);
// 分裂
// 递归调用 左半边排序
quickSort(arr, start, high - 1);
// 递归调用 右半边排序
quickSort(arr, high + 1, end);
}
// 定义函数 遍历数组
void printArr(int arr[], int len)
{
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
// 定义数组
int nums[] = {9, -20, 30, 29, -30, -45, 25, 87, 55};
int len = sizeof nums / sizeof(int);
printf("没排序前的数组:");
printArr(nums, len);
// 调用函数排序
quickSort(nums, 0, len - 1);
printf("\n排序后的数组:");
printArr(nums, len);
return 0;
}
1. **Partition操作**:快速排序的核心在于Partition操作,即如何将数组分割成两部分,并确保左边的元素都小于右边的元素。Partition操作通常使用一个基准元素(pivot)来实现,需要理解如何选择合适的基准元素,并进行元素交换,以实现分割。
2. **递归实现**:快速排序通常使用递归来实现,需要理解递归的调用过程和递归终止条件。递归的正确实现是保证算法正确性的关键之一。
3. **边界条件处理**:在实现快速排序时,需要考虑数组为空或只有一个元素的情况,以及如何处理相等元素的情况,避免出现死循环或错误的排序结果。
4. **性能优化**:快速排序的性能高度依赖于基准元素的选择,不同的选择方式可能导致不同的性能表现。需要理解如何选择合适的基准元素,以及如何优化算法以提高排序效率。
5. **稳定性**:快速排序是一种不稳定的排序算法,即相同元素的相对位置在排序后可能发生改变。理解快速排序的稳定性特点对于某些应用场景很重要。