数据结构
顺序结构
链式结构
栈和队列
树和图(二叉树)
查找和排序(hash表)
画图写代码
1.顺序表
顺序表
根据画图了解顺序表的特点 :
1. 地址连续,大小固定
2. 除了第一个元素外,其它元素都有前驱。
除了最后一个元素外,其它元素都有后继。
3. 访问方便,通过下标来访问
4. 删除和插入不方便,可能需要移动元素
- 创建顺序表、实现数据的增、删、改、查、删除表
功能性的接口和测试分开
list.c/list.h/test.c
分析:
list.h
常量定义
类型申明
全局变量申明
函数的申明
list.c
定义全局变量
定义函数
test.c
main函数
list.h:
#ifndef _LIST_H_
#define _LIST_H_
//常量定义
#define SIZE 10
typedef enum e_result
{
ERROR = -1,
OK,
FALSE = 0,
TRUE,
}E_RESULT;
//类型声明
typedef int data_type;
typedef unsigned int uInt;
typedef struct list
{
data_type data[SIZE];
uInt count;
}LIST;
//函数的申明
/*
函数名:createList
函数功能:创建线性表
函数参数:无
函数返回值:成功时返回线性表的首地址,失败返回NULL.
*/
LIST * createList(void);
/*
函数名:destroyList
函数功能:销毁线性表
函数参数:LIST * pList 表示要销毁的线性表的首地址
函数返回值:无.
*/
void destroyList(LIST * pList);
/*
函数名:insertToList
函数功能:插入一个元素到线性表中
函数参数:
LIST * pList 表示要插入的线性表的首地址
int offset :表示要插入的位置
data_type newItem : 表示要插入的元素的值
函数返回值:成功时返回0,失败返回-1.
*/
int insertToList(LIST * const pList, int offset, data_type newItem);
/*
函数名:deleteFromList
函数功能:从线性表中删除一个元素
函数参数:
LIST * pList 表示要操作的线性表的首地址
int offset :表示要删除的位置
data_type * pDelItem : 保存被删除的元素的值
函数返回值:成功时返回0,失败返回-1.
*/
int deleteFromList(LIST * const pList, int offset, data_type * const pDelItem);
/*
函数名:updateList
函数功能:修改线性表中的一个元素
函数参数:
LIST * pList 表示要操作的线性表的首地址
int offset :表示要修改的位置
data_type newValue : 修改后元素的值
函数返回值:成功时返回0,失败返回-1.
*/
int updataList(LIST * const pList, int offset, data_type newValue);
/*
函数名:searchItemFormList
函数功能:从线性表中查找和指定元素相等的元素,返回第一次出现的位置
函数参数:
LIST * pList 表示要操作的线性表的首地址
data_type item : 被查找的元素的值
函数返回值:成功时返回下标,失败返回-1.
*/
int searchItemFormList(LIST * const pList, data_type item);
/*
函数名:showList
函数功能:显示线性表中元素的值
函数参数:
LIST * pList 表示要显示的线性表的首地址
函数返回值:无.
*/
void showList(LIST * pList);
#endif
list.c:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "list.h"
/*
函数名:createList
函数功能:创建线性表
函数参数:无
函数返回值:成功时返回线性表的首地址,失败返回NULL.
*/
LIST * createList(void)
{
LIST * pList = NULL;
pList = (LIST *)malloc(sizeof(LIST));
if(NULL != pList)
{
memset(pList, 0, sizeof(LIST));
pList->count = 0;//表为空
}
return pList;
}
/*
函数名:destroyList
函数功能:销毁线性表
函数参数:LIST * pList 表示要销毁的线性表的首地址
函数返回值:无.
*/
void destroyList(LIST * pList)
{
if(NULL == pList)
return ;
free(pList);
pList = NULL;
}
/*
函数名:insertToList
函数功能:插入一个元素到线性表中
函数参数:
LIST * pList 表示要插入的线性表的首地址
int offset :表示要插入的位置
data_type newItem : 表示要插入的元素的值
函数返回值:成功时返回0,失败返回-1.
*/
int insertToList(LIST * const pList, int offset, data_type newItem)
{
int i = 0;
//参数判断
if(NULL == pList || offset >pList->count || offset < 0)
{
printf("参数不对\r\n");
return ERROR;
}
//表是否为满
if(SIZE == pList->count)
{
printf("线性表满\r\n");
return ERROR;
}
//移动元素
for(i = pList->count - 1; i >= offset; i--)
{
pList->data[i + 1] = pList->data[i];
}
//插入元素
pList->data[offset] = newItem;
//更新计数器
pList->count++;
return OK;
}
/*
函数名:showList
函数功能:显示线性表中元素的值
函数参数:
LIST * pList 表示要显示的线性表的首地址
函数返回值:无.
*/
void showList(LIST * pList)
{
int i = 0;
//参数判断
if(NULL == pList)
return ;
for(i = 0; i < pList->count; i++)
printf("%d\t",pList->data[i]);
printf("\n");
}
/*
函数名:deleteFromList
函数功能:从线性表中删除一个元素
函数参数:
LIST * pList 表示要操作的线性表的首地址
int offset :表示要删除的位置
data_type * pDelItem : 保存被删除的元素的值
函数返回值:成功时返回0,失败返回-1.
*/
int deleteFromList(LIST * const pList, int offset, data_type * const pDelItem)
{
int i = 0;
//判断参数
if(NULL == pList || offset > pList->count || offset < 0)
{
printf("参数不对\r\n");
return ERROR;
}
//保存被删除元素的值
if(NULL != pDelItem)
{
*pDelItem = pList->data[offset];
}
//移动元素
for(i = offset + 1; i < pList->count; i++)
{
pList->data[i - 1] = pList->data[i];
}
//更新计算器
pList->count--;
return OK;
}
/*
函数名:updateList
函数功能:修改线性表中的一个元素
函数参数:
LIST * pList 表示要操作的线性表的首地址
int offset :表示要修改的位置
data_type newValue : 修改后元素的值
函数返回值:成功时返回0,失败返回-1.
*/
int updataList(LIST * const pList, int offset, data_type newValue)
{
//判断参数
if(NULL == pList || offset > pList->count || offset < 0)
{
printf("参数不对\r\n");
return ERROR;
}
pList->data[offset] = newValue;
return OK;
}
/*
函数名:searchItemFormList
函数功能:从线性表中查找和指定元素相等的元素,返回第一次出现的位置
函数参数:
LIST * pList 表示要操作的线性表的首地址
data_type item : 被查找的元素的值
函数返回值:成功时返回下标,失败返回-1.
*/
int searchItemFormList(LIST * const pList, data_type item)
{
int i = 0;
//判断参数
if(NULL == pList)
{
printf("参数不对\r\n");
return ERROR;
}
for(i = 0; i < pList->count; i++)
{
if(pList->data[i] == item)
break;
}
if(i == pList->count)
{
printf("找不到该元素\r\n");
return ERROR;
}
return i;
}
//如果表满,返回1,如果表不满,返回0,如果表不存在-1;
int isFull(LIST * pList)
{
if (NULL == pList)
return ERROR;
if (SIZE == pList -> count)
return TRUE;
return FALSE;
}
int isEmpty(LIST * pList)
{
if (NULL == pList)
{
return ERROR;
}
if (0 == pList->count)
{
return TRUE;
}
return FALSE;
}
test.c:
#include <stdio.h>
#include "list.h"
int main(void)
{
LIST * pList = NULL;
data_type * pDelItem = NULL;
data_type delData = 0;
//创建线性表
pList = createList();
if(NULL == pList)
{
printf("线性表创建失败\r\n");
return ERROR;
}
//插入数据
insertToList(pList, 0, 1);
insertToList(pList, 1, 3);
insertToList(pList, 2, 5);
insertToList(pList, 1, 4); // 1,4,3,5
//显示
showList(pList);
//删除
if (OK == deleteFromList(pList, -10, pDelItem))
{
if (NULL != pDelItem)
printf("delete item =%d\r\n", *pDelItem );
}
//显示
showList(pList);
//删除
if (OK == deleteFromList(pList, 0, &delData))
{
printf("delete item =%d\r\n", delData );
}
//显示
showList(pList);
updataList(pList, 2, 100);
showList(pList);
int m = searchItemFormList(pList, 200);
if(m != -1)
printf("该元素下标为%d\n",m);
//销毁线性表
destroyList(pList);
return 0;
}
输出结果:
1 4 3 5
参数不对
1 4 3 5
delete item =1
4 3 5
4 3 100
找不到该元素
2.链表
单向不循环链表
概念:
- 头结点:数据域为空
- 首结点:头结点的下一个结点
- 尾结点:指针域为空
- 一般,在操作链表的时候,都是从头结点开始。
特点:
- 地址可以不连续
- 大小不固定
- 访问不方便,一般要通过头结点开始向后挨个结点进行访问
- 插入和删除方便,不需要移动元素
操作:创建表、销毁表、增、删、改、查、判空
list.h:
#ifndef _LIST_H_
#define _LIT_H_
typedef enum e_result
{
ERROR = -1,
OK,
FALSE = 0,
TRUE,
}E_RESULT;
enum position
{
TAIL = -1,
HEAD,
};
//类型声明
typedef int data_type;
typedef unsigned int uInt;
typedef struct list
{
data_type data;//数据域
struct list * pNext;//指针域
}LIST;
//函数的申明
/*
函数名:createList
函数功能:创建线性表
函数参数:无
函数返回值:成功时返回线性表的首地址,失败返回NULL.
*/
LIST * createList(void);
/*
函数名:destroyList
函数功能:销毁线性表
函数参数:LIST * pList 表示要销毁的线性表的首地址
函数返回值:无.
*/
void destroyList(LIST * pList);
/*
函数名:insertToList
函数功能:插入一个元素到线性表中
函数参数:
LIST * pList 表示要插入的线性表的首地址
int offset :表示要插入的位置,
当offset=0,表示头插;当offset=-1时,尾插;首结点的编号为1,后面挨个加1.
例:offset=5时,表示插入到第5个结点之后
data_type newItem : 表示要插入的元素的值
函数返回值:成功时返回0,失败返回-1.
*/
int insertToList(LIST * const pList, int offset, data_type newItem);
/*
函数名:deleteFromList
函数功能:从线性表中删除一个元素
函数参数:
LIST * pList 表示要操作的线性表的首地址
int offset :表示要删除的位置
data_type * pDelItem : 保存被删除的元素的值
函数返回值:成功时返回0,失败返回-1.
*/
int deleteFromList(LIST * const pList, int offset, data_type * const pDelItem);
/*
函数名:updateList
函数功能:修改线性表中的一个元素
函数参数:
LIST * pList 表示要操作的线性表的首地址
int offset :表示要修改的位置
data_type newValue : 修改后元素的值
函数返回值:成功时返回0,失败返回-1.
*/
int updateList(LIST * const pList, int offset, data_type newValue);
/*
函数名:searchItemFormList
函数功能:从线性表中查找和指定元素相等的元素,返回第一次出现的位置
函数参数:
LIST * pList 表示要操作的线性表的首地址
data_type item : 被查找的元素的值
函数返回值:成功时返回下标,失败返回-1.
*/
int searchItemFormList(LIST * const pList, data_type item);
/*
函数名:showList
函数功能:显示线性表中元素的值
函数参数:
LIST * pList 表示要显示的线性表的首地址
函数返回值:无.
*/
void showList(const LIST * pList);
int isEmpty(LIST * pList);
#endif
linkedList.c :
include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
/*
函数名:createList
函数功能:创建线性表
函数参数:无
函数返回值:成功时返回线性表的首地址,失败返回NULL.
*/
LIST * createList(void)
{
LIST * pList = NULL;
pList = (LIST *)malloc(sizeof(LIST));
if(NULL != pList)
{
memset(pList, 0, sizeof(LIST));
}
return pList;
}
/*
函数名:destroyList
函数功能:销毁线性表
函数参数:LIST * pList 表示要销毁的线性表的首地址
函数返回值:无.
*/
void destroyList(LIST * pList)
{
LIST * pTmp;
//判断参数
if(NULL == pList)
return ;
while(1)
{
//pTmp指向首结点
pTmp = pList->pNext;
if(NULL == pTmp)
{
break;
}
//保护pTmp后的所有结点
pList->pNext = pTmp->pNext;
//释放pTmp
free(pTmp);
}
free(pList);
pList = NULL;
}
/*
函数名:insertToList
函数功能:插入一个元素到线性表中
函数参数:
LIST * pList 表示要插入的线性表的首地址
int offset :表示要插入的位置
当offset=0,表示头插;当offset=-1时,尾插;首结点的编号为1,后面挨个加1.
例:offset=5时,表示插入到第5个结点之后
data_type newItem : 表示要插入的元素的值
函数返回值:成功时返回0,失败返回-1.
int insertToList(LIST * const pList, int offset, data_type newItem)
{
LIST * pNew = NULL;
LIST * pTmp = NULL;
int count = 0;
//判断参数
if(NULL == pList || offset < TAIL)
return ERROR;
//新建一个结点pNew
pNew = (LIST *)malloc(sizeof(LIST));
if(NULL == pNew)
{
printf("新建一个结点pNew失败\r\n");
return ERROR;
}
memset(pNew, 0, sizeof(LIST));
memcpy(&(pNew->data), &newItem, sizeof(data_type));//pNew->data = newItem;
//头插法
if(HEAD == offset)
{
//找到要插入的位置pTmp后面
pTmp = pList;
//保护pTmp后的所有结点
pNew->pNext = pTmp->pNext;
//pTmp指向pNew
pTmp->pNext = pNew;
}
//尾插法
else if(TAIL == offset)
{
//找到尾结点pTmp
pTmp = pList;
while(NULL != pTmp)
{
pTmp = pTmp->pNext;
if(NULL == pTmp->pNext)
{
break;
}
}
//pTmp指向pNew
pTmp->pNext = pNew;
}
//中间插入
else
{
//找到要插入的位置pTmp后面
pTmp = pList;
while(NULL != pTmp)
{
pTmp = pTmp->pNext;
count++;
if(count == offset)
{
break;//找到了
}
}
if(NULL == pTmp)
{
//没找到
free(pNew);
pNew = NULL;
return ERROR;
}
//保护pTmp后的所有结点
pNew->pNext = pTmp->pNext;
//pTmp指向pNew
pTmp->pNext = pNew;
}
return OK;
}
/*
函数名:showList
函数功能:显示线性表中元素的值
函数参数:
LIST * pList 表示要显示的线性表的首地址
函数返回值:无.
*/
void showList(const LIST * pList)
{
const LIST * pTmp = pList;
//参数判断
if(NULL == pList || NULL == pList->pNext)
return ;
//从首结点到尾结点依次打印
while(NULL != pTmp)
{
pTmp = pTmp->pNext;
if(NULL != pTmp)
{
printf("%d -> ",pTmp->data);
}
}
printf("^\r\n");
}
/*
函数名:deleteFromList
函数功能:从线性表中删除一个元素
函数参数:
LIST * pList 表示要操作的线性表的首地址
int offset :表示要删除的位置
data_type * pDelItem : 保存被删除的元素的值
函数返回值:成功时返回0,失败返回-1.
*/
int deleteFromList(LIST * const pList, int offset, data_type * const pDelItem)
{
LIST * pTmp = NULL;
LIST * pCur = NULL;
LIST * pDel = NULL;
pTmp = pList;
int count = 0;
//判断参数
if(NULL == pList || NULL == pList->pNext || offset < TAIL)
return ERROR;
if(HEAD == offset)
{
*pDelItem = pTmp->pNext->data;
pDel = pTmp->pNext;
//保护后面的结点
pTmp->pNext = pDel->pNext;
free(pDel);
pDel = NULL;
}
else if(TAIL == offset)
{
//找到尾结点pTmp
while(NULL != pTmp->pNext)
{
pCur = pTmp;
pTmp = pTmp->pNext;
}
*pDelItem = pTmp->data;
pCur->pNext = NULL;
pDel = pTmp;
free(pDel);
pDel = NULL;
}
else
{
while(NULL != pTmp)
{
pCur = pTmp;
pTmp = pTmp->pNext;
count++;
if(count == offset)
{
break;
}
}
if(NULL == pTmp)
{
printf("删除失败,没有此节点\r\n");
return ERROR;
}
//找到结点
*pDelItem = pTmp->data;
pCur->pNext = pTmp->pNext;
pDel = pTmp;
free(pDel);
pDel = NULL;
}
/*
函数名:updateList
函数功能:修改线性表中的一个元素
函数参数:
LIST * pList 表示要操作的线性表的首地址
int offset :表示要修改的位置
从offset=1开始修改;当offset=-1时,就是修改尾结点;首结点的编号为1,后面挨个加1.
例:offset=5时,表示修改第5个结点
data_type newValue : 修改后元素的值
函数返回值:成功时返回0,失败返回-1.
*/
int updateList(LIST * const pList, int offset, data_type newValue)
{
LIST * pTmp = pList;
int count = 0;
//判断参数
if(NULL == pList || NULL == pList->pNext || offset < TAIL)
return ERROR;
if(HEAD == offset)
{
pTmp->pNext->data = newValue;
}
else if(TAIL == offset)
{
while(NULL != pTmp)
{
pTmp = pTmp->pNext;
if (NULL == pTmp->pNext)
{
break;
}
}
pTmp->data = newValue;
}
else
{
while(NULL != pTmp)
{
pTmp = pTmp->pNext;
count++;
if(count == offset)
{
pTmp->data = newValue;
break;
}
}
if(NULL == pTmp)
{
printf("修改失败,没有此结点\r\n");
return ERROR;
}
}
return OK;
}
/*
函数名:searchItemFormList
函数功能:从线性表中查找和指定元素相等的元素,返回第一次出现的位置
函数参数:
LIST * pList 表示要操作的线性表的首地址
data_type item : 被查找的元素的值
函数返回值:成功时返回下标,失败返回-1.
*/
int searchItemFormList(LIST * const pList, data_type item)
{
int count = 0;
LIST * pTmp = pList;
//判断参数
if(NULL == pList || NULL == pList->pNext)
return ERROR;
while(NULL != pTmp)
{
pTmp = pTmp->pNext;
count++;
if(NULL != pTmp && item == pTmp->data)
{
break;
}
}
if(NULL == pTmp)
{
printf("没有找到该元素\r\n");
}
return count;
}
int isEmpty(LIST * pList)
{
//判断元素
if(NULL == pList)
{
printf("该链表不存在\r\n");
return ERROR;
}
if(NULL == pList->pNext)
{
printf("该链表为空\r\n");
return TRUE;
}
return 0;
}
test.c:
#include <stdio.h>
#include "list.h"
int main()
{
LIST * pList = NULL;
data_type * pDelItem = NULL;
data_type delData;
//int ret = 0;
//创建线性表
pList = createList();
if (NULL == pList)
{
printf("线性表创建失败\r\n");
return ERROR;
}
int ret = isEmpty(pList);
printf("ret = %d\r\n",ret);
//插入数据
insertToList(pList, 0, 1);
insertToList(pList, 0, 3);
insertToList(pList, 0, 5);
insertToList(pList, -1, 4); // 5314
insertToList(pList, 3, 7); // 53174*/
//显示
showList(pList);
//修改
updateList(pList,-1,1);//5 -> 3 -> 1 -> 7 -> 1 -> ^
showList(pList);
updateList(pList,0,7);//7 -> 3 -> 1 -> 7 -> 1 -> ^
showList(pList);
updateList(pList,2,12);//7 -> 12 -> 1 -> 7 -> 1 -> ^
showList(pList);
int num = searchItemFormList(pList, 3);
printf("该元素的结点为%d\r\n",num);
num = searchItemFormList(pList, 12);
printf("该元素的结点为%d\r\n",num);
updateList(pList,3,20);
showList(pList);
//删除
if (OK == deleteFromList(pList, 0, &delData))
{
printf("delete item =%d\r\n", delData );
}
//显示
showList(pList);//12 -> 1 -> 7 -> 1 -> ^
//删除
if (OK == deleteFromList(pList, -1, &delData))
{
printf("delete item =%d\r\n", delData );
}
//显示
showList(pList);//12 -> 1 -> 7 -> 1 -> ^
//删除
if (OK == deleteFromList(pList, 2, &delData))
{
printf("delete item =%d\r\n", delData );
}
//显示
showList(pList);//12 -> 1 -> 7 -> 1 -> ^
ret = isEmpty(pList);
printf("ret = %d",ret);
printf("\n");
//销毁线性表
destroyList(pList);
return 0;
}
运行结果:
该链表为空
ret = 1
5 -> 3 -> 1 -> 7 -> 4 -> ^
5 -> 3 -> 1 -> 7 -> 1 -> ^
7 -> 3 -> 1 -> 7 -> 1 -> ^
7 -> 12 -> 1 -> 7 -> 1 -> ^
没有找到该元素
该元素的结点为6
该元素的结点为2
7 -> 12 -> 20 -> 7 -> 1 -> ^
delete item =7
12 -> 20 -> 7 -> 1 -> ^
delete item =1
12 -> 20 -> 7 -> ^
delete item =20
12 -> 7 -> ^
ret = 0
创建空的单向链表:
单向循环头删:
双向链表插入: