C++常用数据结构
常用数据结构
1.线性表
定义:
- 由n个具有相同性质的数据元素组成的有穷序列。
特点:
(一对一的关系)
- 存在唯一一个称为”第一个“的数据元素,它没有直接的前驱。
- 存在唯一一个称为“最后一个”的元素,他没有直接后驱。
- 除第一个数据元素以外,表中的每个数据元素有且仅有一个直接前驱。
- 除第一个数据元素以外,表中的每个数据元素有且仅有一个直接后驱。

1.1顺序表
定义:
- 用一组地址连续的存储单元依次存储线性表中每个数据元素。
特点:
- 逻辑关系相邻的两个元素在物理位置上也相邻。
实现:
- c语言实现:
typedef struct {int items[LISTSIZE];int length; } SqList;
- length:线性表当前的长度。
- LISTSIZE:最大容量。
- c++实现:
templateclass sqlist{ public:sqlist(int maxsize=10):Maxsize(maxsize){elements=new T[maxsize];length=0;} private:int Maxsize;//最大容量T *elements;//元素初始地址int length;//当前有效长度 };
基本操作:
初始化顺序表
//初始化顺序表,表的长度设置为0 void InitList(SqList *L) {L->length=0; }
求顺序表中当前元素的个数
//顺序表的长度 int ListLength(SqList * L) {return L->length; }
判断顺序表是否为空
//判断顺序表是否为空 bool ListEmpty(SqList *L) {if(L->length==0)return true;elsereturn false; }
向顺序表中插入数据元素
//向顺序表中插入数据元素 bool ListInsert(SqList *L,int pos,int item) {int i;if(L->length==LISTSIZE){printf("顺序列表已满,无法进行插入操作");return false;}if(pos<1||pos>L->length+1){printf("插入位置不合法");return false;}for(i=L->length-1;i>=pos-1;i--){L->items[i+1]=L->items[i];}L->items[pos-1]=item;L->length++;return true;}
删除顺序表中的元素
//删除顺序表中的元素 bool ListDelete(SqList *L,int pos,int *item) {int i;if(L->length==0){printf("顺序表为空表");return false;}if(pos<1||pos>L->length){printf("删除位置无效");}*item=L->items[pos-1];for(int i=pos-1;ilength-1;i++){L->items[i]=L->items[i+1];}L->length--;return true; }
查找指定元素在顺序表中的位置
//查找制定元素在顺序表中的位置 int Find(SqList L,int item) {int pos=0;if(ListEmpty(&L)){printf("顺序表为空表,无法进行查找操作");return 0;}while(pos
获取顺序表中指定位置上的数据元素
//获得顺序表中指定位置上的数据元素 int GetElem(SqList *L,int pos,int *item) {if(ListEmpty(L))return 0;if(pos<1||pos>L->length)return 0;*item=L->items[pos-1];return 1; }
- 遍历顺序表
//遍历顺序表 void TravereList(SqList *L) {int pos =0;while(poslength){printf("item1: %d",L->items[pos]);pos++;} } c语言版本:
#includeusing namespace std; #define LISTSIZE 100typedef struct {int items[LISTSIZE];int length; } SqList;//初始化顺序表,表的长度设置为0 void InitList(SqList *L) {L->length=0; }//顺序表的长度 int ListLength(SqList * L) {return L->length; }//判断顺序表是否为空 bool ListEmpty(SqList *L) {if(L->length==0)return true;elsereturn false; }//向顺序表中插入数据元素 bool ListInsert(SqList *L,int pos,int item) {int i;if(L->length==LISTSIZE){printf("顺序列表已满,无法进行插入操作");return false;}if(pos<1||pos>L->length+1){printf("插入位置不合法");return false;}for(i=L->length-1;i>=pos-1;i--){L->items[i+1]=L->items[i];}L->items[pos-1]=item;L->length++;return true;}//删除顺序表中的元素 bool ListDelete(SqList *L,int pos,int *item) {int i;if(L->length==0){printf("顺序表为空表");return false;}if(pos<1||pos>L->length){printf("删除位置无效");}*item=L->items[pos-1];for(int i=pos-1;i length-1;i++){L->items[i]=L->items[i+1];}L->length--;return true; }//查找制定元素在顺序表中的位置 int Find(SqList L,int item) {int pos=0;if(ListEmpty(&L)){printf("顺序表为空表,无法进行查找操作");return 0;}while(pos L->length)return 0;*item=L->items[pos-1];return 1; }//遍历顺序表 void TravereList(SqList *L) {int pos =0;while(pos length){printf("item1: %d",L->items[pos]);pos++;} }int main() {SqList Fibonacci;cout<<"建立顺序表"< >num;if(ListInsert(&Fibonacci,i+1,num))i++;}TravereList(&Fibonacci);int item;ListDelete(&Fibonacci,7,&item);TravereList(&Fibonacci);return 0; } c++版本:
#includeusing namespace std; template class sqlist{ public:sqlist(int maxsize=10):Maxsize(maxsize){elements=new T[maxsize];length=0;}//打印顺序表的长度int listLength(){return length;}//判断顺序表是否为空bool IsEmpty(){return length==0;}//顺序表中插入元素void InsertElement(T elem,int position){if(IsEmpty()){elements[length++]=elem;}else{for(int i=length;i>=position;i--)elements[i]=elements[i-1];elements[position-1]=elem;length++;}}//顺序表中删除元素void DelElement(T elem,int position){T del_elem=elements[position-1];for(int i=position-1;i sq(20);sq.InsertElement(10,2);sq.Printf();sq.InsertElement(30,1);sq.Printf();sq.InsertElement(50,1);sq.Printf();sq.InsertElement(100,2);sq.Printf();sq.DelElement(30,3);sq.Printf();sq.FindElement(100);return 0; }
1.2链表
定义:
- 用一组任意的存储单元存储线性表中的数据元素。
特点:
- 相比顺序存储结构,链式存储结构中,除了需要存储数据元素信息之外,还需要存储它的后继元素的存储地址(指针)。
- 单链表结点的物理位置不一定连续,单链表逻辑上通过指针实现连续。
- 单链表有一个头结点和一个尾结点,并且只有尾结点没有后继结点,其他结点有且仅有一个后继结点。
- 只要知道了链表的头结点,就可以遍历整个链表。
- 单链表的每一个结点包含两部分:数据域和指针域。
- 表头:用来存放第一个结点的地址。
- 表尾:表尾没有后继,所以尾结点的指针域为空指针(NULL)。
实现:
- c语言定义:
typedef struct node{int data;//数据域 node * next;//指针域 }LNode,*LinkList;//LinkList是指向LNode类型数据的指针类型定义
- LinkList是指向LNode类型数据的指针类型定义 ,也就是说,在定义一个指向LNode类型数据的指针变量时,语句
LNode *L;和
LinkList L;是等价的。
- c++定义:
class ListNode{public: ListNode * next;int data;
};
class LinkList
{
public:LinkList(){node=new ListNode;node->next=NULL;}~LinkList(){delete node;}void CreateLinkListBack(int n);void CreateLinkListHead(int n);void InsertNode(int position,int elem);void removeNode(ListNode* p); ListNode* findNode(int value);void PrintLinkList();
public:ListNode *node;
};
基本操作:
- 初始化链表
//初始化链表
LinkList init_list()
{LinkList L=new LNode;if(!L)return NULL;L->next=NULL;//指针域置空 return L;
}
- 打印链表
//打印链表
void Printf_list(LinkList &L)
{LinkList temp=L->next;while(temp!=NULL){cout<data<<"->";temp=temp->next;}}
- 插入数据(头插)
步骤:
- 先创建一个新节点s(LinkList),并给数据域赋值,
- 新节点的指针域指向L-next,
- L的指针域next指向s。
//插入数据(头插)
void create_LinkList(LinkList &L,int n)
{ while(n--){LinkList s=new LNode;cin>>s->data;s->next=L->next;L->next=s; }
}

注意:使用头插法插入数据后,链表中数据的顺序和插入前的数据顺序相反。
- 插入数据(尾插)
步骤:
- 先让r节点指向尾结点,
- 创建一个新节点s(LinkList),并给数据域赋值,且s->next为NULL,因为s为尾结点,
- r的指针域指向s,
- 更新尾节点,即r=s。
//插入数据(尾插)
void create_LinkList_back(LinkList &L,int n)
{LinkList r=L;while(n--){LinkList s=new LNode;cin>>s->data;s->next=NULL;r->next=s;r=s;}}

注意:使用尾插法插入数据后,链表中数据的顺序和插入前的数据顺序相同。
- 在指定位置插入数据
//插入数据
void InsertList(LinkList q,int e)
{LinkList p=new LNode;p->data=e;p->next=q->next;q->next=p;}

- 查找相应数据
LinkList Get_elem(LinkList &L,int e)
{LinkList temp=L->next;while(temp!=NULL){if(e==temp->data){return temp;}temp=temp->next; }return NULL;}

完整程序
#include using namespace std;typedef struct node{int data;//数据域 struct node * next;//指针域
}LNode,*LinkList;//LinkList是指向LNode类型数据的指针类型定义 //初始化链表
LinkList init_list()//引用
{LinkList L=new LNode;if(!L)return NULL;L->next=NULL;//指针域置空 return L;
}
//插入数据(头插)
void create_LinkList(LinkList &L,int n)
{ while(n--){LinkList s=new LNode;cin>>s->data;s->next=L->next;L->next=s; }
}
//插入数据(尾插)
void create_LinkList_back(LinkList &L,int n)
{LinkList r=L;while(n--){LinkList s=new LNode;cin>>s->data;s->next=NULL;r->next=s;r=s;}}
//打印链表
void Printf_list(LinkList &L)
{LinkList temp=L->next;while(temp!=NULL){cout<data<<"->";temp=temp->next;}cout<data=e;p->next=q->next;q->next=p;}
LinkList Get_elem(LinkList &L,int e)
{LinkList temp=L->next;while(temp!=NULL){if(e==temp->data){return temp;}temp=temp->next; }return NULL;}
int main()
{LinkList L=init_list();if(!L){cout<<"初始化失败"<>num;create_LinkList_back(L,num); Printf_list(L); int elem;LinkList elem_list;cout<<"请输入需要查找的数"<>elem;elem_list=Get_elem(L,elem);while(!elem_list) {cout<<"没有查找到,请重新输入"<>elem; elem_list=Get_elem(L,elem);}cout<<"找到相应数据,数据地址为:"<>elem_insert; InsertList(elem_list,elem_insert); Printf_list(L);} return 0;
}
c++版本:
#include
using namespace std;
class ListNode{public: ListNode * next;int data;
};
class LinkList
{
public:LinkList(){node=new ListNode;node->next=NULL;}~LinkList(){delete node;}void CreateLinkListBack(int n);void CreateLinkListHead(int n);void InsertNode(int position,int elem);void removeNode(ListNode* p); ListNode* findNode(int value);void PrintLinkList();
public:ListNode *node;
};
//头插
void LinkList::CreateLinkListHead(int n)
{while(n--){//插入的数据 ListNode* l=new ListNode;cin>>l->data;l->next=node->next;node->next=l;}
}
//尾插
void LinkList::CreateLinkListBack(int n)
{ListNode* r=node;while(n--){ListNode* l=new ListNode;cin>>l->data;l->next=NULL;r->next=l;r=l;}}
//在第i个位置插入元素
void LinkList::InsertNode(int position,int elem)
{int j;ListNode* p=node->next;for(j=1;jnext;if(p==NULL)break;}if(p==NULL &&j<(position-1))return ;
// while(p)
// {
// j++;
// if(j==position)
// break;
// p=p->next;
// }ListNode* q=new ListNode;q->data=elem;q->next=p->next;p->next=q;
}
//移除节点
void LinkList::removeNode(ListNode* p)
{if(p==NULL)return;ListNode* temp=node;while(temp->next!=p){temp=temp->next; }temp->next=p->next;delete p;
}
//寻找某节点
ListNode* LinkList::findNode(int value)
{ListNode* temp=node->next;while(temp){if(temp->data==value)return temp;temp=temp->next;}return NULL;}
//打印链表
void LinkList::PrintLinkList()
{ListNode* temp=node->next;while(temp){cout<data<<"->";temp=temp->next;}std::cout<

2.栈
-
定义:
栈(stack)是一种元素满足后进先出(Last in first out, LIFO)规则的线性表。
-
特点:
- 栈的本质是一种线性表, 但是具有其特殊的操作要求——元素后进先出。这种要求也决定了栈的操作是在表尾进行
- 栈底(bottom):栈的表头
- 栈顶(top):将栈的表尾,所以栈的所有操作都是在栈顶进行的。
- 添加元素,称为入栈(push);删除元素,称为出栈(pop)。
-
实现:
栈可以用顺序存储实现,也可以用链式存储实现,分别成为顺序栈和链栈。但一般使用顺序存储实现,因为栈不允许在栈中间进行插入和删除,需要准寻栈特有的规则。
- 动态实现
typedef struct SqStack_dynamic{int* base;//栈底 int* top;//栈顶
}SqStack_dynamic;
- 静态实现
typedef struct SqStack_static{int data[Maxsize];int top;//栈顶
}SqStack_static;
- C++
class stack_static{public:stack_static(){MaxSize=10;top=0; data= new int[MaxSize]; }void push(int e);void pop(int &e);void GetTop(int &e);private:int MaxSize;int top;int *data;
};
操作:
- 初始化
void InitStack(SqStack_dynamic &stack)
{stack.base= new int[Maxsize];stack.top=stack.base;
}
- 入栈
void push(SqStack_dynamic &stack,int e)
{if((stack.top-stack.base)>=Maxsize)return;*stack.top=e;stack.top++;
}
void stack_static::push(int e)
{data[top]=e;top++;
}
- 出栈
void pop(SqStack_dynamic &stack,int &e)
{if(stack.base==stack.top)return;stack.top--;e=*stack.top;
}
void stack_static::pop(int &e)
{top--;e=data[top];
}
- 栈顶元素
int GetTop(SqStack_dynamic &stack)
{if(stack.base!=stack.top)return *(stack.top-1);elsereturn -1;
}
void stack_static::GetTop(int &e)
{if(top!=MaxSize)e=data[top-1];elsee=-1;
}
完整程序
#include
using namespace std;
#define Maxsize 100
typedef struct SqStack_dynamic{int* base;//栈底 int* top;//栈顶
}SqStack_dynamic;class stack_static{public:stack_static(){MaxSize=10;top=0; data= new int[MaxSize]; }void push(int e);void pop(int &e);void GetTop(int &e);private:int MaxSize;int top;int *data;
};
void stack_static::push(int e)
{data[top]=e;top++;
}
void stack_static::pop(int &e)
{top--;e=data[top];
}
void stack_static::GetTop(int &e)
{if(top!=MaxSize)e=data[top-1];elsee=-1;
}
void InitStack(SqStack_dynamic &stack)
{stack.base= new int[Maxsize];stack.top=stack.base;
}
void push(SqStack_dynamic &stack,int e)
{if((stack.top-stack.base)>=Maxsize)return;*stack.top=e;stack.top++;
}
void pop(SqStack_dynamic &stack,int &e)
{if(stack.base==stack.top)return;stack.top--;e=*stack.top;
}
int GetTop(SqStack_dynamic &stack)
{if(stack.base!=stack.top)return *(stack.top-1);elsereturn -1;
}
int main()
{SqStack_dynamic stack;InitStack(stack);push(stack,2);push(stack,5);push(stack,10);std::cout<<"------dynamic stack-----"<

3.树
1.定义
树是指由 n(n≥0)个结点组成的有穷集合 D 与 D 上的关系的集合 R构成的结构,通常我们用 T 表示。树需要满足以下 3 个条件:
- 当 n=0 时,该结点集合为空,该树被称为空树。
- 在任意的非空树中,有且仅有一个根结点 root。
- 当 n>1 时 ,除根结点以外的其余结点可以分为 m(m>0)个不相交的子集D1,D2,D3,…,Dm, 其中每一个这样的子集 Di(i≤m)本身又是一棵树, 称为根结点 root的子树
注意:
- 树的定义是一个递归定义,因为树是由根结点和子树构成的,而每一个子树也是一棵树。
- 从图中我们还了解,树结构在形式上最主要的特点就是分层特点和具有一定的排列顺序。
2.树的表示方法
- 树形表示法
- 文氏图表示法
3.基本术语
-
结点的度
结点拥有的直接子树数目。如图 A结点的度为3,B结点的度为2,c结点的度为1,D结点的度为3,E、F、G、H、I 以及J度都为0
-
树的度
树中各结点度的最大值称为该树的度。如上图,树的度为3.
-
分支结点
度不为 0 的结点称为分支结点或普通结点。
- 叶子结点
度为 0 的结点称为叶子结点或终端结点。由此可知叶子结点没有子结点。
-
结点的层次
从树的根结点开始,根结点为第 1 层,根结点的子结点为第 2 层,第 2 层结点的子结点为第 3 层……
-
树的深度
树中结点的最大层次数被定义为该树的深度或高度。
-
森林
n(n≥0)棵不相交的树的集合称为森林。
4.基本结构
- 二叉树具有的几种形态
5.性质

6. 存储方式
- 顺序存储
顺序存储将二叉树的每一个节点和数组的编号一一对应,根据这个编号,可以找到该结点的父结点和孩子结点

BinaryTree[0]表示该树的根结点,从根结点开始我们可以按照性质 6 去检索该树的所有结点,比如一个有 20 个结点的
二叉树, 根据性质 6 编号为 10 的结点的父结点为编号为 5 的结点,其左孩子结点为编号为20 的结点,其没有右孩子结点。由此可以看出:
- 如果二叉树是一棵完全二叉树的话,顺序结构的优点就非常明显,它能紧凑的存储二叉树,而且可以随机存取二叉树的某个结点,只需要根据性质 6 计算出该结点的元素下标即可;
- 如果是非完全二叉树,则顺序存储结构就存在空间的浪费,它会为不存在的结点分配空间,而且如果二叉树规模很大,在实际应用中,内存里也很难找出相应的连续存储空间。
- 链式存储
二叉树的节点一般定义为:数据部分、左子树指针和右子树指针,用指针将节点串起来,其中 l 表示左孩子指针, r 表示右孩子指针,∧表示空指针


优点:
- 能够很直观地表示二叉树的逻辑结构;
- 在二叉树不是完全二叉树的时候,链式结构不会像顺序存储结构一样产生空结点,而且链式存储结构能很好地利用内存中的碎片空间,提高内存空间利用效率。
缺点:
- 链式存储结构不能随机存取某个结点,要找到某个结点,必须从根结点开始沿着指针往叶子结点遍历。
7.基本操作
参考:
- 二叉树的前中后和层序遍历详细图解(递归和非递归写法)
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 构建一棵树,即初始化操作
#include
using namespace std;
class BinaryTreeNode{
public://initBinaryTreeNode(){data=NULL;lchild=NULL;rchild=NULL; }BinaryTreeNode(int n){data=new int;*data=n;lchild=NULL;rchild=NULL;}
private:int *data;//dataBinaryTreeNode* lchild;//left child tree BinaryTreeNode* rchild;//right child tree
};
int main()
{BinaryTreeNode bt(5); return 0;
}
- 前序遍历(根、左、右)
//递归
void preorderTraversal(BinaryTreeNode *node)
{if(!node)return;std::cout<data<<" ";preorderTraversal(node->lchild);preorderTraversal(node->rchild);
}
//迭代
void preoder(BinaryTreeNode *root)
{BinaryTreeNode *cur=root;std::stacks;while(cur||!s.empty()){//遍历直到最左叶子节点 while(cur){std::cout<data<<" "; s.push(cur);cur=cur->lchild;}//while结束时,cur=NULL//cur为左子节点 cur=s.top();s.pop();cur=cur->rchild;}}
- 中序遍历(左、根、右)
void midorderTraversal(BinaryTreeNode *node){if(!node)return;preorderTraversal(node->lchild);std::cout<data<<" ";preorderTraversal(node->rchild); }void midoder(BinaryTreeNode *root){BinaryTreeNode *cur=root;std::stacks;while(cur||!s.empty()){//遍历直到最左叶子节点 while(cur){s.push(cur);cur=cur->lchild;}//while结束时,cur=NULL//cur为左子节点 cur=s.top();std::cout<data<<" "; s.pop();cur=cur->rchild;}}
- 后序遍历(左、右、根)
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
