数据结构:将数据组织在内存中的一种形式。
一、线性存储
特点:除了第一个没有前驱,最后一个没有后继,其他的结点都只有一个前驱和一个后继。
线存储分为顺序存储,链式存储。
顺序存储:在内存中连续的存储空间。如:顺序表。
链式存储:元素在内存中的位置并不连续。如:单链表,双向链表。
二、非线性存储
图:一个数据可能有n个后继,有m个前驱。
树:有一个前驱,n个后继。
二叉树:有一个前驱,两个后继。
对数据的操作有初始化,增删改查,销毁等。
数组:大小固定。分配在栈区或堆区。
数组名记录数组的起始位置。
顺序表:大小可以改变。分配在堆区。
1. 用elem记录起始位置。
2.size表示当前顺序表的总大小。
3.count当前顺序表中元素的个数。
顺序表特点:1.存储空间连续,并且没有浪费空间。
2.插入数据元素时,可能会存在空间的扩充。插入位置之后的元素需要后移。
3.删除数据元素时,数据元素也会挪动。
三、单链表
特点:数据存储空间不连续,每一个元素存储一个结点。 结点有数据域和指针域(下一个结点的起始地址)。
单链表带头结点初始化如下:
struct Node
{
ElemType data;
struct Node *next;
};
struct LinkList
{
struct Node head;
int count;//结点个数
};
单链表不带头结点初始化如下:
struct Node
{
ElemType data;
struct Node *next;
}Node;
struct LinkList
{
Node *head;
int count;
};
具体代码如下:
LinkList.h
#ifndef __LINKLIST_H
#define __LINKLIST_H
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef int ElemType;
//定义带头结点的单链表
typedef struct Node
{
ElemType data;
struct Node *next;
}Node;
typedef struct LinkList
{
int count;
struct Node head;
}LinkList, *pList;
void InitLinkList(pList list); //初始化
void InsertLinkList(pList list, ElemType val, int pos); //插入结点
void InsertHeadLinkList(pList list, ElemType val); //头插
void InsertTailLinkList(pList list, ElemType val); //尾插
void DeleteLinkLst(pList list, int pos); //删除结点
void DeleteHeadLinkLst(pList list); //头删
void DeleteTailLinkLst(pList list); //尾删
void Show(pList list); //打印输出
void InversionLinkList(pList list); //将单链表逆置
void Destroy(pList list); //销毁
#endif
LinkList.c
#include "LinkList.h"
void InitLinkList(pList list) //初始化单链表
{
list->count = 0;
list->head.next = NULL;
}
static Node *BuyNode(ElemType val, Node *next) //插入结点
{
Node *s = (Node *)malloc(sizeof(Node));
assert(s != NULL);
s->data = val;
s->next = next;
return s;
}
void InsertLinkList(pList list, ElemType val, int pos)
{
assert(list != NULL);
if( pos < 0 || pos > list->count)
{
printf("pos is error\n");
return ;
}
Node *p = &list->head;
while( pos > 0)
{
p = p->next;
pos --;
}
Node *s = BuyNode(val, p->next);
p->next = s;
list->count ++;
}
void InsertHeadLinkList(pList list, ElemType val) //头插
{
InsertLinkList(list, val, 0);
}
void InsertTailLinkList(pList list, ElemType val) //尾插
{
InsertLinkList(list, val, list->count);
}
void DeleteLinkList(pList list, int pos) //删除结点
{
assert(list != NULL);
if( pos < 1 || pos > list->count)
{
printf("pos is error\n");
return;
}
Node *p = &list->head;
while( pos > 1)
{
p = p->next;
pos --;
}
Node *s = p->next;
p->next = s ->next;
free(s);
list->count--;
}
void DeleteHeadLinkList(pList list) //头删
{
DeleteLinkList(list, 1);
}
void DeleteTailLinkList(pList list) //尾删
{
DeleteLinkList(list, list->count);
}
void Show(pList list) //输出打印
{
assert(list != NULL);
Node *p = &list->head;
while( p->next!= NULL)
{
p = p->next;
printf("%3d",p->data);
}
printf("\n");
}
void InversionLinkList(pList list) //将单链表逆置
{
assert(list != NULL);
Node *first = list->head.next;
Node *middle = first->next;
Node *last = middle->next;
while(last->next != NULL)
{
if(first == list->head.next)
{
first->next = NULL;
}
middle->next = first;
first = middle;
middle = last;
last = last->next;
}
middle->next = first;
last->next = middle;
list->head.next = last;
}
void Destroy(pList list) //销毁单链表
{
assert(list != NULL);
Node *p = &list->head;
//while(p->next != NULL)
//采用指针遍历循环会出错,因为每次删除头结点会把指针释放掉(存在问题 继续调试)
//{
// p = p->next;
// DeleteHeadLinkList(list);
//}
while( list->count > 0)
{
DeleteHeadLinkList(list);
}
printf("OK\n");
}
main.c
#include "LinkList.h"
int main()
{
LinkList list;
InitLinkList(&list);
Show(&list);
for( int i = 0; i < 5; i++)
{
InsertLinkList(&list, i * 10, i);
}
Show(&list);
DeleteLinkList(&list,1);
Show(&list);
Destroy(&list);
return 0;
}
四、顺序表与链表的区别
1.顺序表存储空间连续(虚拟地址空间连续,物理存储空间不连续),链表存储空间不连续。
2.链表相比于顺序表稍微有点浪费空间(每个数据元素存储还需额外的存储指针域)。
3.链表插入或删除数据时,原始数据不需要移动,顺序表反之。
4.顺序表的访问方式简单,速度较快。