一、线性表
1、顺序存储=============
类型定义:
const Maxsize=100;
typedef struct
{
DataType data[Maxsize];
int length;
}SeqList;
SeqList L;
相关操作实现
1)插入
//在顺序表的第i个节点前插入节点值为x新节点
void InsertSeqList(SeqList L,int i,DataType x)
{
if(L.length==Maxsize) exit "表已满"
if(i<1||i>L.length+1) exit "位置错"
else
for(int j=L.length;j>=i;j--)
{
L.data[j]=L.data[j-1];
}
L.data[i-1]=x;
L.length++;
}
----------------------------------------
2)删除
void DeleteSeqList(SeqList L,int i)
{
if(i<1||i>L.length) exit "非法位置"
else
for(int j=i;j { L.data[j-1]=L.data[j]; } L.length--; } ----------------------------------------- 3)定位 //在顺序表中查找值为x的节点序号,找不到返回0 int LocateSeqList(SeqList L,DataType x) { int i=0; while(i { i++; } if(i else return 0; } 2、链式存储============= 类型定义: typedef struct node { DataType data; struct node * next; }Node,*LinkList, ----------------------------- 1)初始化 LinkList InitiateLinkList() { LinkList head; head=malloc(sizeof(Node)); head->next=NULL; return head; } ----------------------------- 2)求表长 int LengthLinkList(LinkList head) { LinkList p = head; int cnt=0; while(NULL != p->next) { p=p->next; cnt++; } return cnt; } ----------------------------- 3)读表元素 //在链表中找第i个元素的节点,找到返回指向该节点的指针,找不到返回NULL LinkList GetLinkList(LinkList head,int i) { LinkList p = head->next; int c=1; while((NULL != p) && (c < i)) { c++; p=p->next; } if(c == i) { retrun p; } else retrun NULL; } ----------------------------- 4)定位 //在表head中查找值为x的节点序号,找不到返回0 int LocateLinkList(LinkList head,DateType x) { LinkList p = head->next; int c=1; while(NULL != p && p->data !=x) { p=p->next; c++; } if(NULL != p) return c; else return 0; } 5)插入 //在链表第i个节点前插入新节点数值为x,(指针q指向插入节点的前一个节点,p指向新生成的节点) void InsertlinkList(LinkList head,int i,DataType x) { LinkList * p, *q; if(1==i) q=head; else q=GetLinkList(LinkList head,int i-1); //找到第i-1个数据元素结点,单链表插入时必须找到插入节点的前一个节点 if(NULL = q) { exit "找不到合法插入位置" } else { p=malloc(sizeof(Node)); p->data=x; //给新节点赋值 p->next=q->next; q->next=p; } } 6)删除 //删除表第i个节点(指针q指向删除节点的前一个节点,p指向删除节点) void DeletelinkList(LinkList head,int i) { LinkList * p, *q; if(1==i) q=head; else q=GetLinkList(LinkList head,int i-1); //找到第i-1个数据元素结点 if(NULL != q && NULL != q->next) { p=q->next; q->next=p->next; free(p); } else exit "删除的节点不存在" } 建表操作(三种方法) 方法一: 方法二: //尾插法,每次向表尾插入新的节点,设置指针q一直指向尾节点,设备指针t指向新生成的节点 LinkList CreateLinkList() { Linklist head; //定义头指针变量 Node *q,*t; int x; head = malloc(sizeof(Node));//生成头节点 q=head; //尾指针首先指向头节点 scanf("%d",&x); //读取第一个元素 while(x !=0) { t=malloc(sizeof(Node)); t->data=x; q->next=t; q=t; //修改尾指针,让其指向新的尾节点 scanf("%d",&x); //读取新的元素 } q->next = NULL; return head; } 方法三: //头插法,每次向表头插入新的节点,设置指针p指向新生成的节点 LinkList CreateLinkList() { Linklist head; //定义头指针变量 Node *p; int x; head = malloc(sizeof(Node));//生成头节点 head->next=NULL; //初始时,首节点为空 scanf("%d",&x); //读取第一个元素 while(x) { p=malloc(sizeof(Node)); p->data = x; p->next=head->next; //第一个加入的节点将成为尾节点q->next=NULL; head->next=q; scanf("%d",&x); //读取新的元素 } return head; } 3、循环链表 1)删除 2)插入 ---------------------------- ---------------------------- //将一个带头结点的链表逆转 LinkList * reverse(LinkList *L) { LinkList * p,*q; p=L->next; L->next=NULL; while(p!=NULL) { q=p; p=p->next; q->next=L->next; //用头插入法 L->next=q; } retrun L; } ---------------------------- ---------------------------- //计算头指针为head的单链表中值为X的个数 int count(LinkList head,DataType x) { int cnt = 0; LinkList p = head; while(NULL!=p) { if(x==p->data) cnt++; p=p->next; } retrun cnt; } 二、栈、队列、数组 (一)栈,一种运算受限的线性表,操作只能在表的一端,具有先进后出的特点 ====================================================== 顺序实现: 数据类型定义: const init maxsize=10; typedef struct seqstack; { DataTye data[maxisze]; int top //标识栈顶位置的变量 }SeqStk; 基本运算如下: 1、初始化 int InitStack(SeqStk * stk) { stk->top=0; return 1; } 2、判断空 int EmptyStack(SeqStk * stk) { if(stk->top==0); return 1; else return 0; } 3、进栈 int PushStack(SeqStk * stk,DataType x) { if(stk->top==maxsize-1); { error("栈已满") return 0; } else { stk->top++; stk->data[stk-top]=x; return 1; } return 1; } 4、出栈 int PopStack(SeqStk * stk) { if(EmptyStack(stk)) { error("下溢") return 0; } else { stk->top--; return 1 } } 5、取元素 int GetStack(SeqStk * stk) { if(EmptyStack(stk)) { retrun NULLdata; } else { return stk->data[stk->top]; } } ==================================== 链式实现 数据类型定义: typedef struck node { DataType data; struck node * next; }LkStk; //链栈可以用一个带头结点的链表来实现 基本运算: 1、初始化 void InitStack(LKStk * LS) { LS=(LKStk *)malloc(sizeof(LKStk)); //生成头节点 LS->next=NULL; //头节点NEXT为空 } 2、判断空 int EmptyStack(LKStk * LS) { if(LS->next=NULL); return 1; else return 0; } 3、进栈 void PushStck(LKStk * LS,DataType x) { LKSst * temp; temp=(LKStk *)malloc(sizeof(LKStk)); temp->data=x; temp->next=LS->next; LS-next=temp; } 4、出栈 int PopStck(LKStk * LS) { if(!EmptyStack) { LKStk * temp; temp=LS->next; LS-next=temp-next; free(temp); return 1 } else return 0 } 5、取栈顶元素 DateType GetTop(LKStk * LS) { if(!EmptyStack) { return LS->next->data; } else return NULLdata; } (2)队列 顺序实现,它由一个一维数组及两个分别指示队列首和队列尾的变量组成, 两个变量分别称为“队列首指针”和“队列尾指针” 循环队列数据类型定义: const int maxsize=6; typedef struck cycqueue { DataType data[maxsize]; int front,rear; }Cycque; Cycque CQ; 循环队列满条件:(CQ.rear+1)%maxsize == CQ.front 循环队列空条件:CQ.rear == CQ.front 循环队列的设计,利用模运算 入队:rear=(rear+1)%maxsize 出队:front=(front+1)%maxsize 基本运算: 1、初始化 void Initcycqueue(Cycque CQ) { CQ.front=0 CQ.rear=0 } 2、判断空 int Emptyqueue(Cycque CQ) { if(CQ.rear == CQ.front) return 1; else return 0; } 3、入队列 int Enqueue(Cycque CQ,DataType x) { if((CQ.rear+1)%maxsize == CQ.front) { error("队列满");return 0; } else { CQ.rear=(CQ.rear+1)%maxsize; CQ.data[CQ.rear]=x; return 1; } } 4、出队列 int Outqueue(Cycque CQ) { if(Emptyqueue(CQ)) { error("队列空");return 0; } else { CQ.front=(CQ.front+1)%maxsize; return 1; } } 5、取队列首元素 DataType Gethead(Cycque CQ) { if(Emptyqueue(CQ)) { return NULLdata; } else { return CQ.data[(CQ.front+1)%maxsize]; } } ===================================== 队列的链接实现 //用一个带头结点的链表来表示队列,称为链队列 //头指针指向头结点,头结点的next指向首结点,尾指针指向队列尾结点 数据类型定义: typedef struct LinkQueueNode { DataType data; struck LinkQueueNode * next; }LkQueNode; typedef struct LKQueue { LkQueNode *front *rear; }LKQue; LKQue LQ; 基本运算: 1、队列初始化 void InitQueue(LKQue LQ) { LKQueNode *temp; temp = (LKQueNode *)malloc(sizeof(LkQueNode)) LQ->front = temp; LQ->rear = temp; LQ->rear->next = NULL; } 2、判断空 int Emptyqueue(LKQue LQ) { if(CQ->rear == CQ->front) return 1; else return 0; } 3、入队列 void Enqueue(LKQue LQ,DataType x) { LKQueNode * temp; temp = (LkQueNode *)malloc(sizeof(LkQueNode)); temp->data=x; temp->next=NULL; (LQ->rear)->next=temp; LQ->rear=temp; } 4、出队列 int Outqueue(LKQue LQ) { LKQueNode * temp; if(Emptyqueue(LQ)) { error("队列空") return 0; } else { temp = (LQ->front)->next; //使temp指向队列的首节点 LQ->front->next=temp->next;//使头结点指针指向新的首结点 if(temp->next==NULL) LQ->front=LQ->rear; //无首节点时 free(temp); return 1; } } 5、取队列首元素 DataTye Getqueue(LKQue LQ) { LKQueNode * temp; if(Emptyqueue(LQ)) { return NULLdata; } else { temp=LQ.front->next; return temp->data; } } 三、树和二叉树 1)基本概念: 结点的度:树上任一结点拥有的子树的数目称为该结点的度。 树的度:一棵树中所有结点的度的最大值称该结的度。 结点的层次:从根开始算起,根的层次为1,其余结点的层次为其双亲的层次加1. 树的高度:一棵树中所有结点层次数的最大值为该树的高度或深度。 二叉树的性质: 1.二叉树的第i层上至多有2 i-1个结点 2.深度为K的二叉树至多有2的K次方-1个结点 3.叶子结点n0,度为2的结点为n2,则n0=n2+1 4.n个结点的完全二叉绔的深度为 二叉对的存储结构: 1、 2、链式存储结构 二叉树的数据类型定义: typedef struct btnode { DataType data; struct btnode lchild,*rchild; }*BinTree; 2)二叉树的遍历 2.1)二叉树遍历的递归实现 2.1.1)先序遍历 void perorder(BinTree bt) { if(bt!=NULL) { visit(bt); perorder(bt->lchild); perorder(bt->rchild); } } 2.1.2)中序遍历 void inorder(BinTree bt) { if(bt!=NULL) { inorder(bt->lchild); visit(bt); inorder(bt->rchild); } } 2.1.3)后序遍历 void postorder(BinTree bt) { if(bt!=NULL) { postorder(bt->lchild); postorder(bt->rchild); visit(bt); } } 2.2)二叉树的层次遍历 思路:利用一个队列,首先将根(头指针)入队列,以后若队列不空则取队头元素p, 如果p不空,则访问之,然后将其左右子树入队列,如此循环直到队列为空。 void Levelorder(BinTree bt) { InitQueue(Q) // 队列初始化为空 Enqueue(Q,bt) //根入队列 while(!Emptyqueue(Q)) //队列不空则继续遍历 { Getqueue(Q,bt); //取队头元素 if(NULL !=p) { visit(p->data); Enqueue(Q,p->lchild) //左右子树入队 Enqueue(Q,p->rchild; } } } 2.3)二叉树遍历的非递归实现 一般借助栈实现。设想一指针沿二叉树 中序遍历顺序移动,每当向上层移动时就要出栈。 中序非递归遍历最最重要,后面的两个用于提高。(a)中序非递归遍历 指针p从根开始, 首先沿着左子树向下移动,同时入栈保存;当到达空子树后需要退栈访问结点, 然后移动到右子树上去。 树和森林 一).树的存储结构 1.孩子表示法 2.孩子兄弟链表表示法 3.双亲表示法 四、图 五、查找 六、排序