一、基本概念
- 1、数据(Data)
数据即信息的载体,是能够输入到计算机中并且能被计算机识别、存储和处理的符号总称。
2、数据元素(Data Element)
数据元素是数据的基本单位,又称之为记录(Record)。一般,数据元素由若干基本项(或称字段、域、属性)组成。
3、数据的逻辑结构
表示数据运算之间的抽象关系
按每个元素可能具有的直接前趋数和直接后继数将逻辑结构分为“线性结构”和“非线性结构”两大类。
4、数据的存储结构
存储结构:逻辑结构在计算机中的具体实现方法。
存储结构是通过计算机语言所编制的程序来实现的,因而是依赖于具体的计算机语言的。
(1)顺序存储
将数据结构中各元素按照其逻辑顺序存放于存储器一片连续的存储空间中
如c语言的一维数组,如表 L=(a1,a2,……,an)的顺序结构
(2)链式存储
将数据结构中各元素分布到存储器的不同点,用地址(或链指针)方式建立它们之间的联系
数据结构中元素之间的关系在计算机内部很大程度上是通过地址或指针来建立的。
(3)索引存储
在存储数据的同时,建立一个附加的索引表,即索引存储结构=数据文件+索引表。
(4)散列存储
根据数据元素的特殊字段(称为关键字key),计算数据元素的存放地址,然后数据元素按地址存放
二、线性表之顺序表
结构体:
typedef int data_t;
#define N 128
typedef struct{
data_t data[N];
int last;
}sqlist, *sqlink;
借助一维数组来描述线性表的顺序存储结构:
常用运算:
建立空表、置空表、判断表是否为空、求表长、取表中某个元素、定位运算、插入、删除
三、线性表之链表
结构体:
typedef int data_t;
typedef struct node{
data_t data;
struct node *next;
}listnode, *linklist;
结点:
结点的data域存放数据元素ai,next域是一个指针,指向ai的直接后继ai+1所在的结点:
带头结点的单链表:
常用运算:
建立空表、置空表、判断表是否为空、求表长、取表中某个元素、定位运算、插入、删除、链表倒置、链表排序、链表合并
四、栈
顺序栈结构体:
typedef int data_t;
typedef struct{
data_t *data;
int maxlen;
int top;
}sqstack;
链式栈结构体:
typedef int data_t;
typedef struct node{
data_t data;
struct node *next;
}linknode, *linkstack;
后进先出;在一端操作数据,栈底固定、栈顶允许操作;栈中没有元素时是空栈
五、队列
链式队列结构体
typedef int data_t;
typedef struct node{
data_t data;
struct node * next;
}linknode,* linklist;
typedef struct{
linklist front,rear;
}linkqueue;
1、限制在两端操作数据:队尾存入、队头删除(类似窗口卖饭排队的时候);
2、先进先出,没有元素时为空队
3、由于队列的特点,所以可以层次方法问树形结构的数据。
4、front指向对头元素的位置、rear指向队尾元素的下一个位置。
5、为区别空队和满队,满队元素个数比数组元素个数少一个
6、空队:L->front == L->rear;满队:(L->rear + 1)%N == L->front;(N是链表长度)
链式队列:
常用运算:
创建、清空、判断队列空、判断队列满、入队、出队
六、树
二叉树链式存储结构体
typedef char data_t;
typedef struct node_t{
data_t data;
struct node_t *left;
struct node_t *right;
}bitree_t;
bitree_t *root;
1、二叉树由根节点指针决定
2、遍历:沿某条搜索路径周游二叉树,对树中的每一个节点访问一次且仅访问一次
3、二叉树是非线性结构
树的遍历:前序、中序、后序(根节点、左子节点、右子节点的访问顺序)
七、查找
hash链表的查找:
常用保留除数法(质数除余法):设Hash表空间长度为m,选取一个不大于m的最大质数p, 令:H(key)=key%p
处理冲突的方法:
链地址法:发生冲突时,将各冲突记录链在一起,即同义词的记录存于同一链表。
优点:无聚积现象、删除表中记录容易实现。
【质数:大于1的自然数中,只能被1和它本身整除的数】
结构体:
hash.h
#ifndef _HASH_
#define _HASH_
#define N 15
typedef int datatype;
typedef struct node {
datatype key;
datatype value;
struct node * next;
}listnode, *linklist;
typedef struct {
listnode data[N];
}hash;
hash * hash_create();
int hash_insert(hash *HT, datatype key);
linklist hash_search(hash *HT, datatype key);
#endif
hash.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hash.h"
hash * hash_create() {
hash * HT;
if ((HT = (hash *)malloc(sizeof(hash))) == NULL) {
printf("malloc failed\n");
return NULL;
}
memset(HT, 0, sizeof(hash));
return HT;
}
int hash_insert(hash *HT, datatype key) {
linklist p, q;
if (HT == NULL) {
printf("HT is NULL\n");
return -1;
}
if ((p = (linklist)malloc(sizeof(listnode))) == NULL) {
printf("malloc failed\n");
return -1;
}
p->key = key;
p->value = key % N;
p->next = NULL;
q = &(HT->data[key % N]);
while (q->next && q->next->key < p->key ) {
q = q->next;
}
p->next = q->next;
q->next = p;
return 0;
}
linklist hash_search(hash *HT, datatype key) {
linklist p;
if (HT == NULL) {
printf("HT is NULL\n");
return NULL;
}
p = &(HT->data[key % N]);
while (p->next && p->next->key != key) {
p = p->next;
}
if (p->next == NULL) {
return NULL;
} else {
printf("found\n");
return p->next;
}
}
test.c
#include <stdio.h>
#include "hash.h"
int main(int argc, const char *argv[])
{
hash * HT;
int data[] = {23, 34, 14, 38, 46, 16, 68, 15, 7, 31, 26};
int i;
int key;
linklist r;
if ((HT = hash_create()) == NULL) {
return -1;
}
for (i = 0; i < sizeof(data)/sizeof(int); i++) {
hash_insert(HT, data[i]);
}
printf("input:");
scanf("%d", &key);
r = hash_search(HT, key);
if (r == NULL)
printf("not found\n");
else
printf("found:%d %d\n", key, r->key);
return 0;
}
八、排序
排序方式:
插入排序(直接插入排序、折半插入排序、链表插入排序)
交换排序(起泡排序、快速排序、)
选择排序
归并排序
快速排序:
标准库函数:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
base:存储数据地址,nmemb:数据总长,size:元素大小,compar:qsort的比较函数
/* compare()是qsort()的比较函数
* 原则:
* 升序:*p1 < *p2,返回-1;*p1 = *p2,返回0; *p1 > *p2,返回1;
* 降序:*p1 > *p2,返回-1;*p1 = *p2,返回0; *p1 < *p2,返回1;
*
* 比较好的方式就是:
* 升序:return p1 - p2 (返回-1,0,1)
* 降序:return p2 - p1 (返回-1,0,1)
* */
int compare(const void *p1,const void *p2){
return (*(const int *)p1 - *(const int *)p2); //升序
//return (*(const int *)p2 - *(const int *)p1); //降序
}
自定义:
#include <stdio.h>
#define N 10
/*分割函数*/
int partition(int *data, int low, int high){
int temp = data[low];
while(low < high){
while(low < high && temp <= data[high]){
high--;
}
data[low] = data[high];
while(low < high && temp >= data[low]){
low++;
}
data[high] = data[low];
}
data[low] = temp;
return low;
}
/*快排函数*/
int quick_sort(int *data, int low, int high){
int t = 0;
if(data == NULL){
return -1;
}
if(low >= high){
return 0;
}
t = partition(data, low, high);
quick_sort(data, low, t-1);
quick_sort(data, t+1, high);
return 0;
}
int main(int argc, const char *argv[]){
int data[N] = {0};
int i;
srandom(10);
for(i = 0; i < N; i++){
data[i] = random() % 100;//取余,是为了获得的数字是100以下的数字
}
for(i = 0; i < N; i++){
printf("%d ", data[i]);
}
puts("");
qsort(data, 0, N-1);
for(i = 0; i < N; i++){
printf("%d ", data[i]);
}
puts("");
return 0;
}