数据结构:元素之间的关系,分为逻辑结构和存储结构。
每个元素前、后最多都只能有一个节点,如:线性表、栈、队列、数组、串
如:二维数组、多维数组、树、图等
含有n个元素的线性表采用顺序存储,等概率删除其中任一个元素,平均需要移动 n − 1 2 \frac{n-1}{2} 2n−1个元素。

链表中的每个元素称为结点,每个结束是一个结构体变量,分为:
数据部分
指针变量:通常具有指向自身结构体类型的指针变量,存放下一结点的地址,最后一个结点的地址为NULL(单链表)。
尾结束:最后一个结点
尾指针:找尾结点的指针
头结点:第一个结点
头指针:指向头结点的指针变量
首结点:第一个有效结点
循环链表,尾指针指向头结点地址。
双向链表:每个结点增加一个front用来存放前一个结点地址。
数组:表示n个数据类型相同的元素所组成的序列。
字符串:字符构成的一维数组。



每一层都不能增加结点
除了最后一层,都不能增加结点。 最后一层左侧连续有,右侧连续无。
除了最后一层,都不能增加结点。但不满足最后一层左侧连续有、右侧连续无的条件 。
如果i=1,则结点i无父结点,二叉树的根;如果i>1,则父结点是 i/2取整。
如果2i>n,则结点i为叶子结点,无左子结点;否则,其左子结点是结点2i。
如果2i+1>n,则结点i无右子结点,否则,其右子结点是结点2i+1。

值最小的结点无左子树
值最大的结点无右子树。
二叉查找树的中序遍历序列为从小到大排列的序列
每一层从左到右进行遍历的序列为从小到大排列的序列。
一个顶点到另一个顶点是有方向的;
任意两个顶点之间都有一个路径相连。
n个顶点的无向图和有向图的完全图边的个数计算:
用一个n阶的方阵R来存放图中各结点的关联信息。


无穷大表示无连接。
指向该结点的边的数量
从该结点指出去的边的数量。

常见的算法时间复杂度:
O
(
1
)
<
(
l
o
g
2
n
)
<
O
(
n
)
<
O
(
n
l
o
g
2
n
)
<
O
(
n
2
)
<
O
(
n
3
)
<
O
(
2
n
)
O(1) < (log_2n)
临时空间占用大小。
从头到尾依次查找。
平均查找长度:
n
+
1
2
\frac{n+1}{2}
2n+1
int biSearch(int r[], int low, int high, int key){
int mid;
while(low<=high ){
mid = (low+high)/2;
if(key == r[mid]) return mid;
else if(key<r[mid]) high = mid-1;
else low = mid+1;
}
return -1;
}
int main(){
int data[] = {1,2,3,4,5};
int low=0;
int high=sizeof(data) /sizeof(int);
int key=3;
int find = biSearch(data, low, high, key);
printf("result: %d", find);
}
int biSearchRecursion(const int r[], int low, int high, int key){
int mid;
if(low<=high){
mid = (low + high) /2;
if(key ==r[mid]) return mid;
else if(key<r[mid]) return biSearchRecursion(r, low, mid-1, key);
else return biSearchRecursion(r, mid+1, high, key);
}
return -1;
}
int main(){
const int data[] = {1,2,3,4,5};
int low=0;
int high=sizeof(data) /sizeof(int);
int key=3;
int find = biSearchRecursion(data, low, high, key);
printf("result: %d", find);
return 0;
}
仍使用散列函数,用链地址法。按关键码构造链,链的数量与关键码一致。
插入的元素与现有元素挨个比较,每次从元素前面一个元素比较,比前一元素小的话就继续往前比较。
直接插入排序在元素基本有序时比较有优势。

代码示例:
void insertSort(int data[], int n){
int i,j;
int tmp;
for(i=1;i<n;i++){
if(data[i]<data[i-1]){
tmp = data[i];
data[i] = data[i-1];
// 元素往后移
for(j=i-2;j>=0 && data[j]>tmp;j--){
data[j+1]=data[j];
}
data[j+1]=tmp;
}
}
}
int main(){
int data[] = {3,4,5,3,5,1,22};
insertSort(data, 7);
for(int i=0;i<7;i++){
printf("%d=%d\n", i, data[i]);
}
return 0;
}
不稳定排序
相邻元素比较和交换,一趟排序后最大移到最右、或最小移到最左。
示例代码:
#include
int less(int x,int y){
return ((x<y)?1:0);
}
int large(int x, int y){
return ((x>y)?1:0);
}
void bubbleSort(int arr[], int n, int(*compare)(int,int)){
int i,j;
int swapped =1;
for(i=0;swapped;i++){
swapped=0;
for(j=0;j<n-1;j++){
if(compare(arr[j+1],arr[j])){
swap(arr[j+1], arr[j]);
swapped = 1;
}
}
}
}
void bubbleSortTest(){
int data1[] = {4,2,6,3,1};
bubbleSort(data1, 5, less);
for(int i : data1){
printf("%d ", i);
}
}
int main() {
bubbleSortTest();
return 0;
}
代码:
int qusort(int s[],int start,int end) //自定义函数 qusort()
{
int i,j; //定义变量为基本整型
i=start; //将每组首个元素赋给i
j = end; //将每组末尾元素赋给j
s[0]=s[start]; //设置基准值
while(i<j)
{
while(i<j&&s[0]<s[j])
j--; //位置左移
if(i<j)
{
s[i]=s[j]; //将s[j]放到s[i]的位置上
i++; //位置右移
}
while(i<j&&s[i]<=s[0])
i++; //位置左移
if(i<j)
{
s[j]=s[i]; //将大于基准值的s[j]放到s[i]位置
j--; //位置左移
}
}
s[i]=s[0]; //将基准值放入指定位置
if (start<i)
qusort(s,start,j-1); //对分割出的部分递归调用qusort()函数
if (i<end)
qusort(s,j+1,end);
return 0;
}
void selectSort(int data[], int n){
// k 指向最小值的下标
int i,j,k;
int temp;
for(i=0;i<n-1;i++){
for(k=i,j=i+1;j<n;j++){
if(data[j]<data[k])k=j;
if(k!=i){
temp = data[i];
data[i]=data[k];
data[k]=temp;
}
}
}
}
| 类别 | 排序方法 | 平均时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定性 |
|---|---|---|---|---|---|
| 插入排序 | 直接插入 | O ( n 2 ) O(n^2) O(n2) | O ( n 2 ) O(n^2) O(n2) | O ( 1 ) O(1) O(1) | 稳定 |
| 插入排序 | Shell排序 | O ( n 1.25 ) O(n^{1.25}) O(n1.25) | − - − | O ( 1 ) O(1) O(1) | 不稳定 |
| 选择排序 | 直接选择排序 | O ( n 2 ) O(n^2) O(n2) | O ( n 2 ) O(n^2) O(n2) | O ( 1 ) O(1) O(1) | 不稳定 |
| 选择排序 | 堆排序 | O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) | O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) | O ( 1 ) O(1) O(1) | 不稳定 |
| 交换排序 | 冒泡排序 | o ( n 2 ) o(n^2) o(n2) | O ( n 2 ) O(n^2) O(n2) | O ( 1 ) O(1) O(1) | 稳定 |
| 交换排序 | 快速排序 | O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) | O ( n 2 ) O(n^2) O(n2) | O ( l o g 2 n ) O(log_2n) O(log2n) | 不稳定 |
| 归并排序 | O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) | O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) | O ( n ) O(n) O(n) | 稳定 | |
| 基数排序 | O ( d ( r + n ) ) O(d(r+n)) O(d(r+n)) | O ( d ( r + n ) ) O(d(r+n)) O(d(r+n)) | O ( r + n ) O(r+n) O(r+n) | 稳定 |