数据结构:
程序 = 数据结构 + 算法
数据结构是计算机存储、组织数据的方式。
根据数据元素之间的关系,通常有如下四类基本结构:
(1) 集合
结构中的数据元素之间,除了"同属于一个集合"外,
别无其他的关系。
(2) 线性结构
数据元素之间的关系是线性关系。
(3) 树形结构
数据元素之间关系是树状(层次)
(4) 网状结构(图)
线性结构:
线性表"中的数据元素可以是各式各样的类型,但是在同一个线性表中,数据元素必须是同一类型。并且相邻的数据元素之间存在着序偶(顺序)关系。
若将线性表记为: (a1, a2, a3, …, an)
(1) 存在着唯一一个被称为"第一个"的数据元素。
(2) 存在着唯一一个被称为"最后一个"的数据元素。
(3) 除"第一个"元素外,集合中的每个数据元素有且仅有一个前驱数据元素。
(4) 除"最后一个"元素外,集合中的每个数据元素有且仅有一个后继数据元素。
顺序结构 => “数组”
线性表的顺序表示是指 用一组地址连续的存储单元依次存储‘线性表中的数据元素。
我们知道计算机储存空间是有限的,不能提供一段很大连续的存储空间,数据也不能无限的被存储。
链式结构=> “链表”
保存每个数据元素时,不必用连续的存储空间。
数据元素的存储单元不是连续的。
但是在保存每个数据元素的同时,额外开辟一个指针大小的内存空间,
来保存它(数据元素)逻辑上的 上一个数据元素 或 下一个数据元素 或
同时保存上下两个数据元素。
单链表
数据的类型:
typedef int ElemType;
数据节点类型:
struct node
{
ElemType data; //数据域
struct node * next; //指针域
};
根据用户的输入去创建一个有序链表
struct node* Create_Order(void)
{
ElemType date;
struct node * first = NULL;//指向第一个数据节点的指针
struct node * p = NULL;//指向代添加的那个数据节点
while (1)
{
scanf("%d", &date);
if (date == 0)//输入为0就结束
{
break;
}
//开辟空间 保存数据
p = (struct node*)malloc(sizeof(struct node));
p->data = date;
p->next = NULL;
//插入函数,使链表有序
first = insert_node(first,p);
}
return first;
}
//有序插入函数
struct node* insert_node(struct node* first, struct node* p)
{
if (first == NULL)
{
return p;
}
if (p == NULL)
{
return first;
}
//找插入位置
struct node* pk = NULL;
struct node* pr = NULL;
pk = first;
while (pk)
{
if (pk->data > p->data)
{
break;
}
else {
pr = pk;
pk = pk->next;
}
}
//插入操作
if (pk == NULL)
{
pr->next=p;
}
else if (pk == first)
{
p->next = first;
first = p;
}
else
{
pr->next=p;
p->next = pk;
}
return first;
}
带头结点的单链表
很多时候,我们需要经常用到单链表中的结点的个数,并且还可能需要用到单链表的最后一个结点指针。
所以用带头结点的链表,就可以轻松解决这些问题。
数据结点中的数据域类型:
typedef int ElemType;
数据结点的类型:
typedef struct node
{
ElemType data; //数据域
struct node * next;
}Node;
头结点数据类型:
typedef struct head_node
{
struct node * first;
int num;
struct node * last;
}Head;
根据用户的输入去创建一个有序链表
//创建一个无序链表
Head* Create_Head(void)
{
Head* h = (Head*)malloc(sizeof(Head)); //开辟头节点空间
h->first = NULL;
h->last = NULL;
h->num = 0;
Node* p = NULL;
ElemType d;
while (1)
{
scanf("%d", &d);
if (d==0)
{
break;
}
p = (Node*)malloc(sizeof(Node));
p->data = d;
p->next = NULL;
Insert_Node(h, p);//调用有序插入函数
}
return h; //返回头结点
}
//有序插入
void Insert_Node(Head* h, Node* p)
{
if (h == NULL || p == NULL)
{
return;
}
if (h->num == 0)
{
h->first = p;
h->last = p;
}
else
{
Node* pr = NULL;
Node* pk = h->first;
while (pk)
{
if (pk->data > p->data)
{
break;
}
else
{
pr = pk;
pk = pk->next;
}
}
if (pk == NULL)//尾插
{
h->last->next = p;
h->last = p;
}
else if (pk == h->first)//头插
{
p->next = h->first;
h->first = p;
}
else//中插
{
pr->next = p;
p->next = pk;
}
}
h->num++;
}
双向链表
单链表只有一个方向 next next …
在单链表上删除一个节点px,必须要找到px前面的那个节点,那能不能轻松的直接找到px的前面的节点。---- 双向链表
一个结点既要保存它的前面和后面的结点指针
typedef int ElemType;
//数据结点的类型
typedef struct biNode
{
ElemType data;
struct biNode *next; //下个节点
struct biNode *ago; //上个节点
}Node;
typedef struct biLinkedlist
{
struct biNode * first;
struct biNode * last;
int num ;
}Head;
根据用户的输入去创建一个有序链表
//创建无序链表
Head* Create_Head(void)
{
Head* h = (Head*)malloc(sizeof(Head));
h->first = NULL;
h->last = NULL;
h->num = 0;
Node* p = NULL;
ElemType data;
while (1)
{
scanf("%d", &data);
if (data==0)
{
break;
}
p = (Node*)malloc(sizeof(Node));
p->data = data;
p->next = NULL;
p->ago = NULL;
Insert_Node(h, p);
}
return h;
}
//有序插入
void Insert_Node(Head* h, Node* p)
{
if (h==NULL || p==NULL)
{
return;
}
if(h->num==0)//p为第一个节点
{
h->first = p;
h->last = p;
}
else
{
Node* pk = h->first;
while (pk)//找位置
{
if (pk->data > p->data)
{
break;
}
pk = pk->next;
}
if (pk == h->first)//头插
{
p->next = h->first;
h->first->ago = p;
h->first = p;
}
else if (pk == NULL)//尾插
{
h->last->next = p;
p->ago = h->last;
h->last = p;
}
else//中插
{
pk->ago->next = p;
p->ago = pk->ago;
p->next = pk;
pk->ago = p;
}
}
h->num++;
}
双向循环链表(单向循环链表)
如果遍历到最后一个结点,要返回第一个结点,
可能需要回到前面,再遍历一次,因为最后一个结点的next域为NULL.
能不能将最后一个结点的指针指向第一个结点?
单向循环链表
最后一个结点的next域,指向第一个结点
双向循环链表
最后一个结点的next域,指向第一个结点
第一个结点的prev域,指向最后一个结点
//数据域类型
typedef int Elemtype;
//数据结点的类型
typedef struct biNode
{
//数据域
Elemtype data;
//指针域
struct biNode * next;
struct biNode * ago;
}Node;
//头结点的类型
typedef struct biHead
{
//指向第一个数据结点指针
biNode * first;
//指向最后一个数据结点指针
biNode * last;
//数据结点的个数
//int num;
}Head;
根据用户的输入去创建一个有序链表
Head* Create_Head(void)
{
Head* h = (Head*)malloc(sizeof(Head*));
h->first = NULL;
h->last = NULL;
h->num = 0;
Node* p = NULL;
ElemType data;
while (1)
{
scanf("%d", &data);
if (data == 0)
{
break;
}
p = (Node*)malloc(sizeof(Node));
p->data = data;
p->next = NULL;
p->ago = NULL;
Insert_Node(h, p);
}
return h;
}
void Insert_Node(Head* h, Node* p)
{
if (h==NULL || p==NULL)
{
return;
}
if (h->num==0)
{
h->first = p;
h->last = p;
p->ago = p;
p->next = p;
}
else
{
Node* pk = h->first;
Node* pr = NULL;
while (pk!=pr)
{
if (pk->data > p->data )
{
break;
}
else
{
pr = h->first;
pk = pk->next;
}
}
if (pk==h->first && pr == NULL)
{
p->next = h->first;
h->first->ago = p;
h->last->next = p;
h->first = p;
h->first->ago = h->last;
}
else if (pk==pr)
{
h->last->next = p;
p->ago = h->last;
h->first->ago = p;
h->last = p;
h->last->next = h->first;
}
else
{
pk->ago->next = p;
p->ago = pk->ago;
p->next = pk;
pk->ago = p;
}
}
h->num++;
}