线性结构[把所有的节点用一根直线穿起来]
A:连续存储[数组]
1.什么叫数组
元素类型相同,大小相等
2.数组的优缺点
B:离散存储[链表]
1.定义:
n个节点离散分配
彼此通过指针相连
每个节点只有一个前驱结点,每个节点只有一个后续阶段
首节点没有前驱节点,尾节点没有后续节点
专业术语:
首节点:
第一个有效的节点
尾节点:
最后一个有效的节点
头结点:
在首节点前加一个头结点,便于链表操作(不存放有效数据)
头指针
指向头结点的指针变量
尾指针
指向尾节点的指针变量
需要用函数对链表进行处理,需要接受那些参数:
只需要知道一个参数:头结点
2.分类:
单链表
双链表(两个指针域)
循环链表(通过任何一个节点找到其他)
非循环链表
3.算法:
遍历
查找
清空
销毁
求长度
排序
删除节点 r = p->pNext; P->pNext = p->pNext->pNext; free(r);
插入节点 写法1.r = p->pNext; p->pNext = q; q->pNext = r;
写法2.q->pNext = p->pNext; p->pNext=q;
算法:
狭义的算法与数据存储相关,广义的算法与存储方式无关
泛型:
利用某种技术发到的效果就是:不同的存数方式执行的操作时一样的
数据的存储结构
线性
连续存储【数据】
离散存储【链表】
非线性
树
图
连续存储【数组】
优点
存取速度快
缺点
需知道数组长度
插入删除元素慢
插入元素慢
需要大快内存
插入删除元素效率低
离散存储【链表】
优点
空间没有限制
插入删除元素快
缺点
存取速度慢
A:连续存储[数组]
1.什么叫数组
元素类型相同,大小相等
2.数组的优缺点
实例:数组操作
#include <stdio.h>
#include<malloc.h>
#include <stdlib.h>
struct Arr
{
int * pBase; //数组第一个元素的地址
int len; //数组长度
int cnt; //有效元素个数
//int incremant; //自动增长因子
};
void init_arr(struct Arr * pArr, int length);
bool append_arr(struct Arr * pArr, int val); //追加
bool insert_arr(struct Arr * pArr, int pos, int val); //pos从1开始
bool delete_arr(struct Arr * pArr, int pos, int * pval);
bool get(struct Arr * pArr, int pos, int * pval);
bool is_empty(struct Arr * pArr);
bool is_full(struct Arr * pArr);
void show_arr(struct Arr * pArr);
void inversion_arr(struct Arr * pArr);
void sort_arr(struct Arr * pArr);
//find deleteAll
int main()
{
struct Arr arr;
int Val;
init_arr(&arr, 6);
show_arr(&arr);
append_arr(&arr, 1);
append_arr(&arr, 2);
append_arr(&arr, 3);
append_arr(&arr, 4);
show_arr(&arr);
if(delete_arr(&arr, 1, &Val))
{
printf("删除成功,元素的值为%d\n", Val);
}
else
{
printf("删除失败\n");
}
show_arr(&arr);
inversion_arr(&arr);
show_arr(&arr);
sort_arr(&arr);
show_arr(&arr);
get(&arr, 1, &Val);
printf("得到的值为%d\n", Val);
/*append_arr(&arr, 2);
append_arr(&arr, 3);
append_arr(&arr, 4);
append_arr(&arr, 5);
//append_arr(&arr, 6);
insert_arr(&arr, 6, 99);
show_arr(&arr);*/
//printf("%d\n" , arr.len);
return 0;
}
void init_arr(struct Arr * pArr, int length)
{
pArr->pBase = (int *)malloc(sizeof(int)*length);
if(NULL == pArr->pBase)
{
printf("动态内存分配失败");
exit(-1);
}
else
{
pArr->len = length;
pArr->cnt = 0;
}
return;
}
bool is_empty(struct Arr * pArr)
{
if(0 == pArr->cnt)
return true;
else
return false;
}
bool is_full(struct Arr * pArr)
{
if(pArr->cnt == pArr->len)
{
return true;
}
else
{
return false;
}
}
void show_arr(struct Arr * pArr)
{
if(is_empty(pArr))
{
printf("数组为空!\n");
}
else
{
for(int i=0; i<pArr->cnt; ++i)
printf("%d ", pArr->pBase[i]);
printf("\n");
}
}
bool append_arr(struct Arr * pArr, int val)
{
if( is_full(pArr) )
{
return false;
}
else
{
pArr->pBase[pArr->cnt]=val;
pArr->cnt++;
return true;
}
}
bool insert_arr(struct Arr * pArr, int pos, int val) //3 88
{
if( is_full(pArr) )
return false;
if(pos<1 || pos>pArr->cnt+1)
return false;
for(int i=pArr->cnt-1;i>=pos-1;i--)
{
pArr->pBase[i+1]=pArr->pBase[i];
}
pArr->pBase[pos-1] = val;
pArr->cnt++;
return true;
}
bool delete_arr(struct Arr * pArr, int pos, int * pval)
{
if( is_empty(pArr) )
return false;
if(pos<1 || pos>pArr->cnt)
return false;
*pval = pArr->pBase[pos-1];
for(int i=pos; i<pArr->cnt; i++)
{
pArr->pBase[i-1] = pArr->pBase[i];
}
pArr->cnt--;
}
void inversion_arr(struct Arr * pArr)
{
int t;
for(int i=0;i<=pArr->cnt/2;i++)
{
t = pArr->pBase[i];
pArr->pBase[i]=pArr->pBase[pArr->cnt-1-i];
pArr->pBase[pArr->cnt-1-i] = t;
}
return;
}
void sort_arr(struct Arr * pArr)
{
int i, j, t;
for(i=0; i<pArr->cnt; i++)
{
for(j=i+1; j<pArr->cnt; j++)
{
if(pArr->pBase[i]>pArr->pBase[j])
{
t = pArr->pBase[i];
pArr->pBase[i] = pArr->pBase[j];
pArr->pBase[j]=t;
}
}
}
}
bool get(struct Arr * pArr, int pos, int * pval)
{
*pval = pArr->pBase[pos-1];
return true;
}
B:离散存储[链表]
1.定义:
n个节点离散分配
彼此通过指针相连
每个节点只有一个前驱结点,每个节点只有一个后续阶段
首节点没有前驱节点,尾节点没有后续节点
专业术语:
首节点:
第一个有效的节点
尾节点:
最后一个有效的节点
头结点:
在首节点前加一个头结点,便于链表操作(不存放有效数据)
头指针
指向头结点的指针变量
尾指针
指向尾节点的指针变量
需要用函数对链表进行处理,需要接受那些参数:
只需要知道一个参数:头结点
2.分类:
单链表
双链表(两个指针域)
循环链表(通过任何一个节点找到其他)
非循环链表
3.算法:
遍历
查找
清空
销毁
求长度
排序
删除节点 r = p->pNext; P->pNext = p->pNext->pNext; free(r);
插入节点 写法1.r = p->pNext; p->pNext = q; q->pNext = r;
写法2.q->pNext = p->pNext; p->pNext=q;
算法:
狭义的算法与数据存储相关,广义的算法与存储方式无关
泛型:
利用某种技术发到的效果就是:不同的存数方式执行的操作时一样的
4.链表的优缺点:
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
typedef struct Node
{
int data;
struct Node * pNext;
}Node, *PNODE;
PNODE create_list(void);
void traverse_list(PNODE pHead);
bool is_empty(PNODE pHead);
int length_list(PNODE pHead);
bool insert_list(PNODE pHead, int pos, int val);
bool delete_list(PNODE pHead, int pos, int * pVal); //最后一个删除值
void sort_list(PNODE pHead);
int main()
{
int len = 0;
int val = 0;
PNODE pHead = NULL;
pHead = create_list();
traverse_list(pHead);
if(is_empty(pHead))
{
printf("空\n");
return 0;
}
else
printf("不空\n");
len = length_list(pHead);
printf("%d\n",len);
sort_list(pHead);
traverse_list(pHead);
insert_list(pHead, 3, 4);
traverse_list(pHead);
if( delete_list(pHead, 3, &val) )
{
printf("删除成功\n");
printf("删除值为%d\n", val);
}
else
{
printf("删除失败!\n");
}
traverse_list(pHead);
return 0;
}
/*
**创建一个非循环链表
*/
PNODE create_list(void)
{
int len;
int i;
int val;
//分配了一个不存放有效数据的头结点
PNODE pHead = (PNODE)malloc(sizeof(PNODE));
if(NULL == pHead)
{
printf("分配失败,程序终止!\n");
exit(-1);
}
PNODE pTail =pHead; //pHead赋值给pTail,使得pTail->指向尾节点
pTail->pNext = NULL; //防止0个节点
printf("请输入需要生成链表节点个数:\n");
scanf("%d", &len);
for(i=0;i<len;++i)
{
printf("请输入读%d个节点的值:",i+1);
scanf("%d", &val);
PNODE pNew = (PNODE)malloc(sizeof(PNODE));
if(NULL == pHead)
{
printf("分配失败,程序终止!\n");
exit(-1);
}
pNew->data = val; //节点存放数据
pTail->pNext = pNew; //前一个节点指向当前
pNew->pNext = NULL; //此节点指向NULL
pTail = pNew;
}
return pHead;
}
void traverse_list(PNODE pHead)
{
PNODE p = pHead->pNext;
while(NULL != p)
{
printf("%d ", p->data);
p = p->pNext;
}
printf("\n");
}
bool is_empty(PNODE pHead)
{
if(NULL == pHead->pNext)
return true;
else
return false;
}
int length_list(PNODE pHead)
{
PNODE p = pHead->pNext;
int len = 0;
while(NULL != p)
{
++len;
p = p->pNext;
}
return len;
}
void sort_list(PNODE pHead)
{
int i, j, t;
PNODE p, q;
int len = length_list(pHead);
for(i=0,p=pHead->pNext; i<len-1; ++i,p=p->pNext)
{
for(j=i+1,q=p->pNext; j<len; j++,q=q->pNext)
{
if(p->data > q->data) //类似于数组中的if(a[i]>a[j])
{
t = p->data; //t=a[i];
p->data = q->data; //a[i]=a[j];
q->data= t; //a[j]=t;
}
}
}
}
//在pos个前插入一个新节点
bool insert_list(PNODE pHead, int pos, int val)
{
int i = 0;
PNODE p = pHead;
while(NULL!=p && i<pos-1) //精要
{
p = p->pNext;
++i;
}
if(i>pos-1 || NULL==p)
return false;
PNODE pNew = (PNODE)malloc(sizeof(PNODE));
if(NULL == pNew)
{
printf("动态内存分配失败!\n");
exit(-1);
}
pNew->data = val;
PNODE q =p ->pNext;
p->pNext= pNew;
pNew->pNext =q;
return true;
}
bool delete_list(PNODE pHead, int pos, int * pVal) //最后一个删除值
{
int i = 0;
PNODE p = pHead;
while(NULL!=p->pNext && i<pos-1) //精要
{
p = p->pNext;
++i;
}
if(i>pos-1 || NULL==p->pNext)
return false;
PNODE q = p->pNext;
*pVal = q->data;
p->pNext = p->pNext->pNext;
q=NULL;
free(q);
return true;
}
小结
数据的存储结构
线性
连续存储【数据】
离散存储【链表】
非线性
树
图
连续存储【数组】
优点
存取速度快
缺点
需知道数组长度
插入删除元素慢
插入元素慢
需要大快内存
插入删除元素效率低
离散存储【链表】
优点
空间没有限制
插入删除元素快
缺点
存取速度慢
数据结构
狭义:
数据结构是专门研数据存储的问题
数据的存储包含两方面:个体的存储和个体关系的存储
算法是对存储数据的操作
广义:
数据的存储和操作
算法
狭义;
算法和数据的存储方式密切相关
广义
算法和数据的存储方式无关
泛型思想