数据结构课程(数据的组织、数据的快速查找)
节点: 数据结构中的每个元素
前驱: 某个节点前面的节点
后继: 某个节点后面的节点
数据结构:线性结构,树形结构,图形结构
线性结构:在存储关系上,每个元素最多有一个前驱,一个后继
树形结构:在存储关系上,每个元素最多有一个前驱,但可以有多个后继
图形结构:在存储关系上,每个元素可以有多个前驱,多个后继
算法(完成一个功能,所用的程序)复杂度
1) 时间复杂度(运行速度是否快)
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
{
;//处理
}
}
上面的时间复杂度
T(n) = O(n^2) // 执行此数 n * n
冒泡排序: 时间复杂度 O(n^2)
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
{
for(k = 0; k < n; k++)
{
//
}
}
}
上面的时间复杂度
T(n) = O(n^3) // 执行此数 n * n * n
for(i = 0; i < n; i++)
{
}
for(j = 0; j < n; j++)
{
}
T(n) = O(2 * n) // 执行此数 n + n
2) 空间复杂度(运行程序需要的空间)
///需要内存越少越好
练习: (笔试题)
1. long foo(long x)
{
if(x < 2)
return 1;
return x*x*foo(x-1);
}
上面算法的时间复杂度是( A ):
A O(n) B O(n^2) C O(n^3) D O(1)
2. 下面算法的时间复杂度为( B )
int f(unsigned int n)
{
if(n==0 || n==1)
return 1;
else
return n*f(n-1);
}
A O(1)
B O(n)
C O(N*N)
D O(n!)
1 线性表(每一个节点都有一个前驱和一个后继,首节点和尾节点除外)
1)顺序表(数据存储时是连续存放的,典型的是数组)
主要用数组来存储顺序表
练习:
用数组来存储学生成绩(线性表)
int score[20] = {56, 62, 74, 83};
1) 编写一个函数, 能向数组中插入数据 如:位置2, 成绩为65
#include <stdio.h>
void insert(int *p, int x, int pos)
{
int i;
for(i = 3; i >= pos; i--)
{
p[i + 1] = p[i];
}
p[pos] = x;
}
int main()
{
int i, score[20] = {56, 62, 74, 83};
insert(score, 65, 2);
for(i = 0; i < 5; i++)
{
printf("%d\n", score[i]); //56 62 65 74 84
}
}
2) 再编写一个函数,能从数组中删除一个元素
#include <stdio.h>
void insert(int *p, int x, int pos)
{
int i;
for(i = 3; i >= pos; i--)
{
p[i + 1] = p[i];
}
p[pos] = x;
}
void delete(int *p, int pos)
{
int i;
for(i = pos; i < 5; i++)
{
p[i] = p[i + 1];
}
}
int main()
{
int i, score[20] = {56, 62, 74, 83};
insert(score, 65, 2);
for(i = 0; i < 5; i++)
printf("%d\n", score[i]); //56 62 65 74 84
delete(score, 2);
for(i = 0; i < 4; i++)
printf("%d\n", score[i]); //56 62 74 84
}
顺序表是线性表的一种,类似于数组,记录在内存中是挨着放的
顺序表有这些操作
创建空顺序表
求顺序表中有效元素个数
取出顺序表中某个元素
向顺序表中插入元素
从顺序表中删除元素
在顺序表中查找数据
类型重定义 (typedef type define)
1 普通类型重定义
typedef int size_t; //typedef 能将int 重定义成size_t
size_t a; //int a
typedef unsigned char UINT8; //UINT8 a; //定义了一个 无符号8位的整型
typedef char INT8;
typedef unsigned short UINT16;
typedef short INT16;
typedef unsigned int UINT32;
typedef int INT32;
char 是一个特殊的整型,8位,里面存储的是ascii码
2 学生结构体类型重定义
struct student
{
char name[20];
int age;
};
struct student s1;
方法1:
typedef struct student stu_t;
stu_t s1; //可以省略struct
方法2:
typedef struct student
{
char name[20];
int age;
}stu_t;
方法3: 省略结构体名
typedef struct
{
char name[20];
int age;
}stu_t;
例:
#include <stdio.h>
typedef struct
{
char name[20];
int age;
}stu_t;
int main()
{
stu_t s1 = {"xiaoli", 25};
printf("%s,%d\n", s1.name, s1.age);
}
typedef int data_t;
typedef struct
{
int data[100]; //存储顺序表的数组
int last; //元素个数(当表空时,last = 0, last 同时也是下一个要存储数据的位置)
} sqlist_t;
创建空顺序表
求顺序表中有效元素个数
取出顺序表中某个元素
向顺序表中插入元素
从顺序表中删除元素
在顺序表中查找数据
顺序表的定义
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int data[100];
int last;
}sqlist_t;
//1) 创建空顺序表
sqlist_t *CreateEmptySqlist()
{
sqlist_t *p = malloc(sizeof(sqlist_t)); //sizeof(sqlist_t) ? 404
p->last = 0;
return p;
}
//2) 判断顺序表是不是空 如果空,返回1, 非空 返回0
int EmptySqlist(sqlist_t *p)
{
if(p->last == 0)
return 1;
else
return 0;
}
//3)判断顺序表是否满 //如果为满返回 1, 不满 返回0
int FullSqlist(sqlist_t *p)
{
if(p->last == 100)
return 1;
else
return 0;
}
//4 清空顺序表
void ClearSqlist(sqlist_t *p)
{
p->last = 0;
}
//5 求表长
int LengthSqlist(sqlist_t *p)
{
return p->last;
}
//6 在表中指定位置插入元素 成功返回0, 失败返回-1
int InsertSqlist(sqlist_t *p, int pos, int x)
{
int i;
if(pos > p->last || pos < 0)
return -1;
for(i = p->last; i >= pos; i--)
{
p->data[i + 1] = p->data[i];
}
p->data[pos] = x;
p->last++;
return 0;
}
//7 从顺序表中删除指定位置的元素 成功返回0, 失败返回-1
int DeleteSqlist(sqlist_t *p, int pos)
{
int i;
if(pos >= p->last || pos < 0)
return -1;
for(i = pos; i < p->last; i++)
{
p->data[i] = p->data[i + 1];
}
p->last--;
return 0;
}
//8 打印表中所有数据
void print_all(sqlist_t *p)
{
int i;
for(i = 0; i < p->last; i++)
printf("%d,", p->data[i]);
printf("\n");
}
///测试
int main()
{
sqlist_t *p = CreateEmptySqlist();
InsertSqlist(p, 0, 40); //40
InsertSqlist(p, 0, 30); //30, 40
InsertSqlist(p, 0, 10); //10, 30, 40
InsertSqlist(p, 1, 20); //10, 20, 30, 40
print_all(p); //10, 20, 30, 40
DeleteSqlist(p, 1);
print_all(p); //10, 30, 40
}
//
顺序表:
使用方便,但如果有大量数据,进行插入和删除将非常麻烦(要移动大量的数据)
数据元素个数固定
2)链表
用来解决1 顺序表数据大量移动的问题
2 解决顺序表元素数量固定的问题
链表分为单向链表,双向链表,单向循环链表,双向循环链表
单向链表有两个域,数据域和指针域
typedef struct node_t
{
int data; //数据域
struct node_t *next; //指针域,通过指针域可以找到下一个节点
}link_node_t;
/
有这些名字,我用链表将这些名字连接起来
"yang", "li", "liu", "wang"
#include <stdio.h>
typedef struct node_t
{
char name[20];
struct node_t *next;
}link_node_t;
int main()
{
link_node_t A = {"yang", NULL};
link_node_t B = {"li", NULL};
link_node_t C = {"liu", NULL};
link_node_t D = {"wang", NULL};
A.next = &B;
B.next = &C;
C.next = &D;
link_node_t *p = &A;
//输出?????
while(p != NULL)
{
printf("%s\n", p->name);
p = p->next;
}
}
单向链表有2种类型:
1) 不带头结点的单向链表:
2) 带头结点的单向链表
/
单向链表 两种类型
1 带头结点 (头结点: 是一个空节点,这个节点不存有效数据,只有next是有效的)
上面名字例子改为用带头结点的单向链表实现:
#include <stdio.h>
typedef struct node_t
{
char name[20];
struct node_t *next;
}link_node_t;
int main()
{
link_node_t A = {"yang", NULL};
link_node_t B = {"li", NULL};
link_node_t C = {"liu", NULL};
link_node_t D = {"wang", NULL};
link_node_t E = {" ", &A};
A.next = &B;
B.next = &C;
C.next = &D;
link_node_t *p = &E;
//输出?????
while(p->next != NULL)
{
p = p->next;
printf("%s\n", p->name);
}
}
用带头结点的单向链表存储n个学生成绩 ,成绩由键盘输入,输入<=0 时结束
#include <stdio.h>
#include <stdlib.h>
typedef struct node_t
{
int data;
struct node_t *next;
}link_node_t;
int main()
{
link_node_t *h = malloc(sizeof(link_node_t));//h 是头节点
h->next = NULL;
link_node_t *q = h; //q 永远指向最后一个节点
while(1)
{
int n;
scanf("%d", &n);
if(n <= 0)
break;
link_node_t *p = malloc(sizeof(link_node_t));//p 是新节点
p->data = n;
p->next = NULL;
q->next = p;
q = p;
}
while(h->next != NULL)
{
h = h->next;
printf("%d\n", h->data);
}
}
作业:定义一个学生结构体,然后用单向链表保存学生信息,由scanf输入学生信息后形成链表,再打印出所有学生信息
//复习顺序表,复习链表
typedef struct
{
char name[20];
int age;
int score;
}student;
typedef struct node_t
{
student s; //数据域
struct node_t *next; //指针域
}linknode_t;