连续存储(数组)
1、什么叫数组?
元素的类型相同,大小相等。
2、优缺点?
查询速度快,增加删除慢
#include <stdio.h> #include <malloc.h> #include <stdlib.h> //定义一个数据类型,名字 Arr,成员分别 struct Arr { int * pBase; //存储的是数组第一个元素的地址 int len; //数组的长度 int cnt; //当前数组有效元素的个数 int increment; //自动增长因子,扩容 }; //参数一定要传地址,如果是变量只是把12个字节赋给了另12个字节,进行初始化 void init_arr(struct Arr * pArr , int length) { pArr->pBase = (int *)malloc(sizeof(int)*length)//相当于指针变量中结构体变量pBase成员,返回二十四个字节的第一个字节 if(NULL == pArr->pBase) //检测是否分配成功 { printf("动态内存分配失败!\\n"); exit(-1); //终止整个程序 } else { pArr->len = length; pArr->cnt = 0; } }; //添加到数组尾部 bool append_arr(struct Arr * pArr , int val) { //满时直接返回 if(is_full(pArr)) return false; //不满追加 else pArr->pBase[pArr->cnt] = val ; pArr->cnt++ }; //插入指定位置,下标为0的是第一个元素 bool insert_arr(struct Arr * pArr,int pos,int val) { int i ; if(is_full(pArr)) return false; if(pos<1||pos>pArr->cnt+1) return false; for(i = pArr->cnt - 1; i>=pos-1; --1) { pArr->pBase[i+1] = pArr->pBase[i];// 数组下标灯油POS的元素向后移 } pArr->pBase[pos-1] = val; //赋值POS位置 pArr->cnt++; return true; }; bool get(); //是否为空 bool is_empty(struct Arr * pArr) { if(0== pArr->cnt) { return true; } else { return false; } }; bool delete_arr(struct Arr * pArr,int pos,int val) { int i; if(is_empty(pArr)) { return false; } if(pos<1 || pos>pArr->cnt) { return false; } *val = pArr->pBase[pos-1]; //返回删除的元素 for(i=pos;i<pArr->cnt ; ++i) { pArr->pBase[i-1] = pArr->pBase[i]; } pArr->cnt--; return true ; }; //是否满了 bool is_full(struct Arr * pArr) { if(pArr->cnt == pArr->len) return true; else return false; }; 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; }; } } }; //最好传地址,不需要重新分配内存,输出 void show_arr(struct Arr * pArr) { if(is_empty(pArr)) { printf("数组为空!\\n"); } else { for(int i = 0; i<pArr->len;++i) { printf("%d",pArr->pBase[i]); } } }; //倒置 void inversion_arr(struct Arr * pArr) { int i =0; int j=pArr->cnt-1; int t; while(i<j) { t=pArr->pBase[i]; pArr->pBase[i]=pArr->pBase[j]; pArr->pBase[j]=t; ++i; --j; } }; int main(void) { struct Arr arr; //定义一个数据类型,此时的地址全是垃圾地址 int val ; //删除时,用来返回删除的元素 init_arr(&arr,6); show_arr(&arr); append_arr(&arr , 1); insert_arr(&arr , 1,10); delete_arr(&arr , 1,&val); inversion_arr(&pArr); sort_arr(&pArr); return 0; }
离散存储(链表)
定义:
N个结点离散分配,彼此通过指针相连,分配结点只有一个前驱结点和后续结点,首节点没有前驱结点,尾结点没有后续结点,
首节点:第一个有效结点
尾节点:最后一个有效结点
头节点:第一个有效结点前的节点,头节点不存放数据,但是数据类型跟后面节点的数据类型相同
头指针:指向头节点的指针变量
尾指针:指向尾节点的指针变量
分类:
单链表,
双链表:每个节点有两个指针
循环链表:可以通过任何一个节点找到所有结点
非循环链表
算法:
插入时分析
删除时分析
需要定义一个中间值
优缺点:
一个节点的生成:
#include <stdio.h> #include <malloc.h> //定义节点 typedef struct Node { int data;//数据域 struct Node *pNext; //指针域 } NODE,*PNODE; //NODE等价于struct NODE ,PNODE等价于struct NODE * int main(void) { PNODE pHead = NULL; //等价struct NODE * pHead = null; (定义一个头节点) pHead = create_list(); //创建一个非循环单链表并将该链表的第一个单元返回 traverse_list(pHead); return 0; } PNODE create_list(void) { int len = 5; int i; int val; PNODE pHead =(PNODE)malloc(sizeof(NODE)); //NODE结构体值类型,PNODE结构体地址类型 if(NULL == pHead) { exit(-1); } PNODE pTail = pHead; //定义一个尾节点 pTail->pNext =NULL; //清空指针域(保证尾节点始终指向最后一个) for(i=0 ; i<len ; i++) { PNODE pNew = (PNODE)malloc(sizeof(NODE));//存放每个节点的临时值 if(NULL == pNew) { exit(-1); } pNew ->data = val; //数据域赋值 pTail->pNext = pNew; //指向下一个节点 pNew->pNext = null; //清空下一个节点的指针域 pTail=pNew; //下一个节点赋值给尾节点 (保证pTail 永远指向尾节点这是关键) } return pHead; } //输出 void traverse_list(PNODE pHead) { PNODE p = pHead->pNext; //指向第一个有效节点 while(NULL !=p) { printf("输出数据域"); p=p->pNext; } return; } //是否为空 bool is_empty(PNODE pHead) { if(NULL==pHead->pNext) return true; return false; }; //输出长度 int length_list(PNODE pHead) { int i = 0; PNODE p=pHead->pNext; while(NULL!=p) { i++; p=pHead->pNext; } return i; }; //插入节点(在pHead所指向链表的Pos个节点前面插入个新节点,该值是val) 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)//判断最后一个节点的位置以及长度和最后一个节点是否为NULL { return false; } PNODE pNew =(PNODE)malloc(sizeof(NODE)); if(NULL == pNew) { printf("动态分配内存失败"); } pNew ->data =val; PNODE q=p->pNext; p->pNext= pNew; pNew->pNext =q; }; //删除一个元素 bool delete_list(PNODE pHead , int pos, int * val)//val是返回删除的元素 { int i=0 ; PNODE p =pHead while (NULL!=p->pNext &&i >pos-1) //找到要删除节点的前一个节点 { p = p->pNext; ++i; } if(i>pos-1 || NULL == p->pNext)//判断最后一个节点的位置以及长度和最后一个节点是否为NULL { return false; } PNODE q=p->pNext; *pVal = q ->data; //删除 p->pNext = p->pNext->pNext; free(q); q=NULL; }; //排序(链表的排序跟数组的排序不同,但是逻辑相同) bool sort_list(PNODE pHead) { int i,j,t; int len=length_list(pHead); PNODE p,q; for(i=0,p=pHead->pNext;i=len-1;++i , p=p->pNext) { for(j=i+1,q=p->pNext;i=len-1;++j,q=q->pNext) //循环的同时移动指针q的位置 { if(p->data > q->data) //类似a[i]>a[j] { t=p->data;//换值 p->data = q->data; q->data=t; } } } };