#pragma once
#include
#include
#define TRUE 1
#define FALSE 0
typedef int ElemType;//假定线性表的元素类型为整型
//定义节点
typedef struct node {
int data;
struct node *pNext;
}LinkListNode;
///创建带有头节点的链表Init
///函数的返回值是头节点,没有参数
LinkListNode* InitLinkList(void);
///求长度:求顺序表中的元素的个数
///函数的返回值是顺序表的长度,参数pHead:是单链表的头节点
int GetSizeLinkList(LinkListNode* pHead);
///取元素:取给定位置的元素值
///返回值:第i个元素的地址,pHead:头指针,i 待查节点的序号
LinkListNode* GetLinkListNode(LinkListNode* pHead, int pos);
///查元素:查找给定元素值的位置
///返回值:节点的地址,找不到就返回NULL
///pHead:单链表的头指针,objData:是需要匹配的元素值
LinkListNode* LocateLinkList(LinkListNode* pHead, int objData);
///插入元素:在指定的位置插入给定的值
///尾插法建立单链表(将逻辑上的顺序表放入单链表的物理结构当中)
///返回值:链表的头指针,arr:传入的顺序表,length:顺序表的长度
LinkListNode* Create_Rear_LkList(ElemType arr[], int length);
///头插法建立单链表
///返回值:链表的头指针,arr:传入的顺序表,length:顺序表的长度
LinkListNode* Create_Front1_LkList(ElemType arr[], int length);
///头插法2
///返回值:链表的头指针,arr:传入的顺序表,length:顺序表的长度
LinkListNode* Create_Front2_LkList(ElemType arr[], int length);
///头插法建立
///返回值:链表的头指针,arr:传入的顺序表,length:顺序表的长度
LinkListNode* Create_Front3_LkList(ElemType arr[], int length);
///插入元素:在指定的位置插入给定的值
//ptr:带插入的元素位置,将在ptr的后继结点中插入,x:插入的值
void Insert_After_LkList(LinkListNode* ptr, ElemType x);
///指定位置之前插入
///pHead:链表的头指针,ptr:带插入的元素位置,x:插入的值
void Insert_Before_LkList(LinkListNode* pHead, LinkListNode* ptr, ElemType x);
///删除节点:Ptr是需要删除的节点,将删除ptr的后续节点
///返回值是带删除的节点位置
LinkListNode* Delete_After_LkList(LinkListNode* ptr);
///删除第i个节点
///返回值是带删除的节点位置,pHead:头节点,i是第i个元素
LinkListNode* Delete_i_LkList(LinkListNode* pHead, int i);
///遍历
void ShowLkList(LinkListNode* pHead);
#pragma once
#include
#include
typedef int ElemType;//假定线性表的元素类型为整型
#define LIST_SIZE 1024 //假定我们的线性表长度是1024
#define TRUE 1
#define FALSE 0
typedef struct {
ElemType data[LIST_SIZE];
int last;//指向最后一个节点的位置
}SequenList;
//last的存在的目的:为了在函数调用的时候传递数据方便,因为我们与分配
//的空间中,并不是立即存满的
///数组顺序表的实现初始化
///获得一个长度为0的数组
SequenList* InitSeq();
///求长度:求线性表中的元素的个数
///获得当前数组顺序表的元素个数,pList:顺序表的起始地址
int GetSizeSeq(SequenList* pList);
///取元素:取给定位置的元素值
///返回值是元素值
///pList:目标的顺序表, pos:获取元素的下标 ,e:将元素值放入
int GetElemSqList(SequenList* pList, int pos, ElemType *e);
/// 查元素:查找给定元素值的位置
///相同值只去第一个
///返回值:-1表示没有找到,否则返回带查找元素的角标
///pList:传入的数组顺序表,Key比对的值
int LocateElemSqList(SequenList* pList, ElemType key);
/// 插入元素:在指定的位置插入给定的值
/// 插入的位置为k:k: 0 -- n-1
//pList:目标顺序表,x待插入的元素,k插入的位置
int InsertElemSqList(SequenList* pList, ElemType x, int k);
///删除:删除指定位置的值或者是删除给定的值。
//pList:目标顺序数组,k表示需要删除的位置
int DelElemSqList(SequenList *pList, int k);
///遍历元素:从头到尾扫描线性表。
///pList:目标顺序数组
void showSeqList(SequenList* pList);
//#ifndef _LIST_HEAD_H
//#define _LIST_HEAD_H
//
双向链表节点
//struct list_head {
// struct list_head *next, *prev;
//};
//
初始化节点:设置name节点的前继节点和后继节点都是指向name本身。
//#define LIST_HEAD_INIT(name) { &(name), &(name) }
//
定义表头(节点):新建双向链表表头name,并设置name的前继节点和后继节点都是指向name本身。
//#define LIST_HEAD(name) \
// struct list_head name = LIST_HEAD_INIT(name)
//
初始化节点:将list节点的前继节点和后继节点都是指向list本身。
//static inline void INIT_LIST_HEAD(struct list_head *list)
//{
// list->next = list;
// list->prev = list;
//}
//
添加节点:将new插入到prev和next之间。
//static inline void __list_add(struct list_head *new,
// struct list_head *prev,
// struct list_head *next)
//{
// next->prev = new;
// new->next = next;
// new->prev = prev;
// prev->next = new;
//}
//
添加new节点:将new添加到head之后,是new称为head的后继节点。
//static inline void list_add(struct list_head *new, struct list_head *head)
//{
// __list_add(new, head, head->next);
//}
//
添加new节点:将new添加到head之前,即将new添加到双链表的末尾。
//static inline void list_add_tail(struct list_head *new, struct list_head *head)
//{
// __list_add(new, head->prev, head);
//}
//
从双链表中删除entry节点。
//static inline void __list_del(struct list_head * prev, struct list_head * next)
//{
// next->prev = prev;
// prev->next = next;
//}
//
从双链表中删除entry节点。
//static inline void list_del(struct list_head *entry)
//{
// __list_del(entry->prev, entry->next);
//}
//
从双链表中删除entry节点。
//static inline void __list_del_entry(struct list_head *entry)
//{
// __list_del(entry->prev, entry->next);
//}
//
从双链表中删除entry节点,并将entry节点的前继节点和后继节点都指向entry本身。
//static inline void list_del_init(struct list_head *entry)
//{
// __list_del_entry(entry);
// INIT_LIST_HEAD(entry);
//}
//
用new节点取代old节点
//static inline void list_replace(struct list_head *old,
// struct list_head *new)
//{
// new->next = old->next;
// new->next->prev = new;
// new->prev = old->prev;
// new->prev->next = new;
//}
//
双链表是否为空
//static inline int list_empty(const struct list_head *head)
//{
// return head->next == head;
//}
//
获取"MEMBER成员"在"结构体TYPE"中的位置偏移
//#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
//
根据"结构体(type)变量"中的"域成员变量(member)的指针(ptr)"来获取指向整个结构体变量的指针
//#define container_of(ptr, type, member) ({ \
// const typeof( ((type *)0)->member ) *__mptr = (ptr); \
// //(type *)( (char *)__mptr - offsetof(type,member) );})
//
遍历双向链表
//#define list_for_each(pos, head) \
// for (pos = (head)->next; pos != (head); pos = pos->next)
//
//#define list_for_each_safe(pos, n, head) \
// for (pos = (head)->next, n = pos->next; pos != (head); \
// pos = n, n = pos->next)
//
//#define list_entry(ptr, type, member) \
// container_of(ptr, type, member)
//
//#endif
#include "SeqList.h"
/*
1) 初始化:给线性表中的相关参数赋值
2) 求长度:求线性表中的元素的个数
3) 取元素:取给定位置的元素值
4) 查元素:查找给定元素值的位置
5) 插入元素:在指定的位置插入给定的值
6) 删除:删除指定位置的值或者是删除给定的值。
7) 遍历元素:从头到尾扫描线性表。
*/
SequenList* lPtr;
//实现初始化
SequenList* InitSeq() {
SequenList *pList=NULL;
pList = (SequenList *)malloc(sizeof(SequenList));
if (pList != NULL)
pList->last = 0;//初始化成功,且长度为0
return pList;
}
//SequenList seqenList;
//SequenList *seqenList;
//前者分配空间了,而后者没有空间
//求长度:求线性表中的元素的个数
int GetSizeSeq(SequenList* pList) {
return pList->last;
}
//取元素:取给定位置的元素值
/// pList:目标的顺序表, pos:获取元素的下标 ,e:将元素值放入
int GetElemSqList(SequenList* pList, int pos, ElemType *e) {
if (pos<0 || pos>pList->last) {
return FALSE;
}
if (pList->last <= 0)
return FALSE;
//说明此时pos在0 -- n之间
*e = pList->data[pos];
return TRUE;
}
// 查元素:查找给定元素值的位置
//相同值只去第一个
//返回值:-1表示没有找到,否则返回带查找元素的角标
//pList:传入的数组顺序表,Key比对的值
int LocateElemSqList(SequenList* pList, ElemType key) {
int i;
for (i = 0;i < pList->last;i++) {
if (pList->data[i] == key)
return i;
}
return -1;
}
// 插入元素:在指定的位置插入给定的值
// 插入的位置为k:k: 0 -- n-1
// 顺序表:不满
//pList:目标顺序表,x待插入的元素,k插入的位置
int InsertElemSqList(SequenList* pList, ElemType x, int k) {
int j;
//顺序表尚未填满
if (pList->last >= LIST_SIZE - 1)
return FALSE;
//表明K是有效位置
if (k<0 || k>(pList->last + 1))
return FALSE;
for (j = pList->last;j >= k;j--) {
pList->data[j + 1] = pList->data[j];
}
pList->data[k] = x;
pList->last = pList->last + 1;
return TRUE;
}
//删除:删除指定位置的值或者是删除给定的值。
//pList:目标顺序数组,k表示需要删除的位置
int DelElemSqList(SequenList *pList, int k) {
if ((k >= 0 && k <= pList->last) && (pList->last != 0)) {
for (int j = k;j <= pList->last;j++) {
pList->data[j] = pList->data[j + 1];
}
pList->last--;
return TRUE;
}
return FALSE;
}
//遍历元素:从头到尾扫描线性表。
void showSeqList(SequenList* pList) {
for (int i = 0;i < pList->last;i++) {
printf(" %d", pList->data[i]);
}
}
int main1(void) {
lPtr = InitSeq();//这样是否可以=>可以的,且使用NULL来判断是否初始化完毕
if (lPtr) {
//todo:继续使用这个顺序表
for (int i = 0;i < 10;i++) {
InsertElemSqList(lPtr, i, i);
}
printf("初始化后顺序表的元素个数:%d", GetSizeSeq(lPtr));
printf("************\n");
showSeqList(lPtr);
InsertElemSqList(lPtr, 2000, 0);
printf("初始化后顺序表的元素个数:%d", GetSizeSeq(lPtr));
printf("************\n");
showSeqList(lPtr);
DelElemSqList(lPtr, 1);
printf("初始化后顺序表的元素个数:%d", GetSizeSeq(lPtr));
printf("************\n");
showSeqList(lPtr);
int pos = LocateElemSqList(lPtr, 16);
if (pos >= 0) {
printf("当前元素位于%d", pos);
}
else {
printf("没有找到这个元素");
}
printf("************\n");
showSeqList(lPtr);
}
else {
//todo:提示没有可以使用的空间
}
getchar();
getchar();
return 0;
}
#include "LinkList.h"
/*
1) 初始化:给线性表中的相关参数赋值
2) 求长度:求线性表中的元素的个数
3) 取元素:取给定位置的元素值
4) 查元素:查找给定元素值的位置
5) 插入元素:在指定的位置插入给定的值
6) 删除:删除指定位置的值或者是删除给定的值。
7) 遍历元素:从头到尾扫描线性表。
*/
///创建带有头节点的链表Init
LinkListNode* InitLinkList(void) {
LinkListNode* pHead = NULL;
pHead = (LinkListNode*)malloc(sizeof(LinkListNode));
if (pHead) {
pHead->pNext = NULL;
}
return pHead;
}
//求长度:求线性表中的元素的个数
int GetSizeLinkList(LinkListNode* pHead) {
int n = 0;
while (pHead->pNext) {
n++;
pHead = pHead->pNext;
}
return n;
}
//取元素:取给定位置的元素值
//输入链表的头指针,要查找的编号,输出第i个元素的地址
///pHead:头指针,i 待查节点的序号
LinkListNode* GetLinkListNode(LinkListNode* pHead, int pos) {
int j;
LinkListNode* p;
p = pHead;
j = 0;
if(pos == 0)
return NULL;
while (j < pos && p->pNext != NULL) {
p = p->pNext;
j++;
}
if (pos == j)
return p;
else
return NULL;
}
//查元素:查找给定元素值的位置
///找到就返回节点的地址,找不到就返回NULL
LinkListNode* LocateLinkList(LinkListNode* pHead, int objData) {
LinkListNode* p;
p = pHead->pNext;//跳过头节点
while (p != NULL && p->data != objData) {
p = p->pNext;
}
return p;
}
//插入元素:在指定的位置插入给定的值
//因为链表这种结构的内存是由程序员管理的,因此它的建立有一定的运算
//方法
///尾插法建立单链表(将逻辑上的顺序表放入单链表的物理结构当中)
//arr:传入的顺序表,length:顺序表的长度
LinkListNode* Create_Rear_LkList(ElemType arr[], int length) {
LinkListNode* pHead, *p, *q;
int i;//循环变量,用来遍历全部的顺序表
pHead = (LinkListNode*)malloc(sizeof(LinkListNode));
q = pHead; //q是获得了当前链表的头节点
//q保存了pHead,同时通过q不断前移使得链表串联起来
for (i = 0;i < length;i++) {
//获得一个单链表的节点,将这个节点加入到有
//pHead指向的这个链表当中
p = (LinkListNode*)malloc(sizeof(LinkListNode));
//p获得一个可以加入链表的节点单元
p->data = arr[i];//将顺序表的内容存入单链表的节点
q->pNext = p;//
q = p;
}
p->pNext = NULL;
return pHead;
}
///头插法建立单链表
LinkListNode* Create_Front1_LkList(ElemType arr[], int length) {
LinkListNode* pHead, *p, *q;
int i;
pHead = (LinkListNode*)malloc(sizeof(LinkListNode));
pHead->pNext = NULL;
q = pHead->pNext;
//头插的时候,必须逆序遍历顺序表
for (i = length - 1;i >= 0;i--) {
p = (LinkListNode*)malloc(sizeof(LinkListNode));
p->data = arr[i];
p->pNext = q;//是的新加入的节点传入了上一个节点
pHead->pNext = p;//头节点指向了当前的新加入节点
q = pHead->pNext;//让q指向当前的节点
}
return pHead;
}
///头插法2
LinkListNode* Create_Front2_LkList(ElemType arr[], int length) {
LinkListNode* pHead, *p, *q;
//p是新加入节点,q是当前节点
int i;
q = NULL;
for (i = length - 1;i >= 0;i--) {
p = (LinkListNode*)malloc(sizeof(LinkListNode));
p->data = arr[i];
p->pNext = q;
q = p;
}
pHead = (LinkListNode*)malloc(sizeof(LinkListNode));
pHead->pNext = q;
return pHead;
}
///头插法建立
LinkListNode* Create_Front3_LkList(ElemType arr[], int length) {
LinkListNode* pHead, *p;
int i;
pHead = (LinkListNode*)malloc(sizeof(LinkListNode));
pHead->pNext = NULL;
for (i = length - 1;i >= 0;i--) {
p = (LinkListNode*)malloc(sizeof(LinkListNode));
p->data = arr[i];
p->pNext = pHead->pNext;
pHead->pNext = p;
}
//之所以我们的方法三可以节省方法一中的一个变量q
//原因是:pHead不发生变化,而pHead中的pNext始终作为当前节点的指针
return pHead;
}
/*
顺序表:12,33,44,76,89,90(逻辑上的顺序表)=>单链表
本例中,我们用数组表示这种顺序表
*/
//插入元素:在指定的位置插入给定的值
//在指定位置之后插入
void Insert_After_LkList(LinkListNode* ptr, ElemType x) {
LinkListNode* s;
s = (LinkListNode*)malloc(sizeof(LinkListNode));
s->data = x;
s->pNext = ptr->pNext;
ptr->pNext = s;
}
//指定位置之前插入
void Insert_Before_LkList(LinkListNode* pHead, LinkListNode* ptr, ElemType x) {
LinkListNode* s, *qPtr;
s = (LinkListNode*)malloc(sizeof(LinkListNode));
s->data = x;
qPtr = pHead;//qPtr是用来代替pHead的移动的,ptr是目标节点
while (qPtr->pNext != ptr)
qPtr = qPtr->pNext;
s->pNext = ptr;
qPtr->pNext = s;
//因为链表是单向的,虽然我知道当前节点是ptr
//但是在语法层面上,我如果想知道ptr的前继节点只能从head遍历而来
//查到了当前节点的前继,才能使用后插的方法完成节点的加入
}
//删除:删除指定位置的值或者是删除给定的值。
//情形一:删除指定节点的后继结点
//情形二:删除第i个节点,假定头节点i=0
//删除返回目标节点的地址,并不涉及到动态空间的回收
//在动态回收空间的要求中,应该遵循的原理是谁污染谁治理
//在顺序表中的删除就是逻辑上的删除,就是说我们的这个节点不再
//存在于当前的顺序表中了
///删除节点:Ptr是需要删除的节点,将删除ptr的后续节点
LinkListNode* Delete_After_LkList(LinkListNode* ptr) {
LinkListNode* fptr;
//假定我们的顺序表A-》B-》C,我们要删除的是A的后续节点B,A-》C
fptr = ptr->pNext;// ptr是A,所以ptr的next是B,所以fptr是B
ptr->pNext = fptr->pNext;//ptr是A,fptr是B,所以fptr的next是C,所以ptr-next就变成C
return fptr;
}
///删除第i个节点
LinkListNode* Delete_i_LkList(LinkListNode* pHead, int i) {
LinkListNode*ptr, *qPtr = NULL;
ptr = GetLinkListNode(pHead, i - 1);//找到i的前继节点
if (ptr != NULL && ptr->pNext != NULL)
qPtr = Delete_After_LkList(ptr);
return qPtr;
}
//遍历
void ShowLkList(LinkListNode* pHead) {
LinkListNode* p = pHead->pNext;
while (p != NULL) {
printf(" %d", p->data);
p = p->pNext;
}
}
int main3(void) {
ElemType MySeq[] = { 1,2,3,4,5 };
LinkListNode* pHead = Create_Rear_LkList(MySeq, 5);
printf("\n********显示当前单链表中的全部元素******\n");
ShowLkList(pHead);
LinkListNode* pPos = GetLinkListNode(pHead, 2);
Insert_After_LkList(pPos, 999);
printf("\n********显示当前单链表中的全部元素******\n");
ShowLkList(pHead);
Insert_Before_LkList(pHead, pPos, 666);
printf("\n********显示当前单链表中的全部元素******\n");
ShowLkList(pHead);
//Delete_After_LkList(pPos);
Delete_i_LkList(pHead, 2);
printf("\n********显示当前单链表中的全部元素******\n");
ShowLkList(pHead);
printf("\nList Size:%d", GetSizeLinkList(pHead));
getchar();
return 0;
}
设有一个顺序表,其数据为a,b,c,d,e,f,g,要求将其就地转置成g,f,e,d,c,b,a
要求逆转表仍然占据原空间
//#include "SeqList.h"
//SequenList* pGlobalSeq;
//
//void RevseSeqList(SequenList* pList) {
// int temp;
// int count, i;
// if (pList->last == 0 || pList->last == 1)
// return;
// count = pList->last / 2;
// for (i = 0;i < count;i++) {
// temp = pList->data[i];
// pList->data[i] = pList->data[pList->last - 1 - i];
// pList->data[pList->last - 1 - i] = temp;
// }
//}
//int main(void) {
// pGlobalSeq=InitSeq();
// for (int i = 0;i < 10;i++) {
// InsertElemSqList(pGlobalSeq, i * 2, i);
// }
// printf("\n**********当前的顺序表元素********\n");
// showSeqList(pGlobalSeq);
// RevseSeqList(pGlobalSeq);
// printf("\n**********当前的顺序表元素********\n");
// showSeqList(pGlobalSeq);
// free(pGlobalSeq);
// getchar();
// return 0;
//}
//Ctrl+a Ctrl+k Ctrl+C
#include "LinkList.h"
LinkListNode* ReverseLkList(LinkListNode* pHead) {
LinkListNode* Pointer, *Next;//Pointer是将来依次获得的当前节点
//Next:将来获得的当前节点的原先的下一个节点
LinkListNode* Back; //原先节点的上一个节点
//step 1: 将原先的next节点的next域变为pointer
//step 2:将原先的pointer的next域变成back
Back = pHead; //原先就是从头节点开始,因此,我们首先将back作为头节点
Pointer = Back->pNext;//通过头节点获得了第一个元素=>pointer指向第一个元素
Next = Pointer->pNext;//此时pointer是第一个元素,因此它的pNext是第二个元素
Pointer->pNext = Back;//pointer->pNext域变成了Back,又因为Back是头节点,所以
//此时原先的第一个元素的后继已经变成了原先的头节点
Back = Pointer;//pointer是第一个元素,因此,此时Back变成了第一个元素
Pointer = Next;//因为在46行,Next已经是第二个元素了,
//因此,此时pointer指向了第二个元素
//在46行,Next变成了原先的第二个元素,有因为在46行-51行,没有在对Next的pNext域
//进行操作,因此,原先链表中的后继信息没有破坏
//47行,pointer作为当前元素指向了原先的前继节点的时候,此时,当前元素把原先的前继元素
//变成了后续节点
//48行,再将Back设为当前元素,49行将Pointer设为下一个元素
while (Pointer->pNext != NULL) {
Next = Pointer->pNext;
Pointer->pNext = Back;
Back = Pointer;
Pointer = Next;
}
Pointer->pNext = Back;
//此时Pointer已经是原先链表中的最后一个元素了,
//因此,必须要把Pointer和原先的前继节点联系起来,而原先的前继节点一定在Back
//此时反转完毕,我们需要重新设置头节点
//原先的pHead没有变,因此原先的pHead->pNext指向的原先的第一个元素
//但是现在我们要让这个元素的pNext域置为空
pHead->pNext->pNext = NULL;
//由于pHead没有变,所以我们依然让它作为反转后链表的头节点
//所以将当前的首元素放置它的pnext域中
pHead->pNext = Pointer;
return pHead;
}
int mainAAA(void) {
LinkListNode* pHead = NULL;
int arr[] = { 0,1,2,3,4,5,6,7,8,9 };
pHead = Create_Rear_LkList(arr, 10);
printf("\n************当前的元素有\n");
ShowLkList(pHead);
pHead = ReverseLkList(pHead);
printf("\n************当前的元素有\n");
ShowLkList(pHead);
getchar();
return 0;
}
#include
#include
typedef struct DNode {
int data;
struct DNode* prior, *next;
}DLinkListNode;
DLinkListNode* Delete_DL(DLinkListNode* ptr) {
ptr->prior->next = ptr->next;
ptr->next->prior = ptr->prior;//在逻辑上,我们再也无法找到这个ptr
return ptr;
}
void Insert_Before_DL(DLinkListNode* p, int x) {
DLinkListNode* s;
s = (DLinkListNode*)malloc(sizeof(DLinkListNode));
s->data = x;
//将s的关系加入到链表
s->prior = p->prior;
if (p->prior != NULL)
p->prior->next = s;
s->next = p;
p->prior = s;
}
int main(void) {
DLinkListNode x;
DLinkListNode *head;
DLinkListNode *ptr;
ptr = &x;
ptr->data = 3;
ptr->prior = NULL;
ptr->next = NULL;
Insert_Before_DL(ptr, 1);
Insert_Before_DL(ptr, 2);
DLinkListNode* p,*q;
p = &x;
while (p != NULL) {
printf("%d\n", p->data);
if (p->prior == NULL)
q = p;//q记录了第一个节点
p = p->prior;
}
while (q != NULL) {
printf("%d\n", q->data);
q = q->next;
}
getchar();
return 0;
}
#include
#include
///循环链表的建立
///输入:顺序表集合,顺序表长度
///输出:循环链表的尾地址
//定义节点
typedef struct node {
int data;
struct node *pNext;
}LinkCircleListNode;
LinkCircleListNode* Create_Circle_LkList(int arr[], int length) {
LinkCircleListNode *head, *p, *q;
int i;
head = (LinkCircleListNode*)malloc(sizeof(LinkCircleListNode));
q = head;
for (i = 0;i < length;i++) {
//p指向了临时申请的空间
p = (LinkCircleListNode*)malloc(sizeof(LinkCircleListNode));
p->data = arr[i];
q->pNext = p;//q在串联p的节点
q = p;//q移动到当前的节点
}
p->pNext = head;
return p;
}
//遍历输出
void ShowCircleLkList(LinkCircleListNode* pRear) {
LinkCircleListNode* p = pRear->pNext;//循环链表建立的尾指针的next域指向的是头节点
//因为遍历的时候,我们希望获得的真正元素,所以我们首先让p移动
p = p->pNext;//此时p指向第一个真正的元素
//while (p->pNext != pRrear->pNext) {//当且仅当p == pRear的时候,循环结束,那么最后一个reare节点是没有输出的
while (p != pRear->pNext) {
printf("%d\n", p->data);
p = p->pNext;
}
}
//两个循环链表合并
//输入为链表a的尾指针,链表b的尾指针
LinkCircleListNode * Connect_Circle_LkList(LinkCircleListNode* ra, LinkCircleListNode *rb) {
LinkCircleListNode* p;
//记录a的头节点
p = ra->pNext;
//将b的第一个元素节点链入a的尾部
ra->pNext = rb->pNext->pNext;
free(rb->pNext);//回收空间,意味着b链表的头节点空间不可达,但是rb->pNext依然是有值的
rb->pNext = p;
//假定rb0x20空间,在ox20空间下有一个next的分量,这个分量是可以存储地址值
//free(rb)才是是的rb->pnext不可用
//free(rb->pnext),rb->pnext中的(data和pnext)分量不可用
//rb->pNext始终指向的是原b链表的头节点
//所以52行执行完毕以后,将b链表的尾指针指向了a链表的头节点
return rb;
}
int mainCCCC(void) {
int arr[] = { 11,22,33,44,55 };
LinkCircleListNode* pRrear = Create_Circle_LkList(arr, 5);
//
//测试合并
int a[] = { 1,3,5 };
int b[] = { 2,4,6 };
LinkCircleListNode *ra, *rb;
ra = Create_Circle_LkList(a, 3);
rb = Create_Circle_LkList(b, 3);
LinkCircleListNode * pRear =Connect_Circle_LkList(ra, rb);
ShowCircleLkList(pRear);
getchar();
return 0;
}
#include
#include
typedef struct node {
int data;
struct node* pNext;
}LinkJoeNode;
//考虑建立约瑟夫环的循环链表
//不带头节点:需要模拟约瑟夫环的工作过程
LinkJoeNode* CreateLkList(int arr[], int length) {
LinkJoeNode *head, *p, *q;
int i;
head = (LinkJoeNode*)malloc(sizeof(LinkJoeNode));
head->data = arr[0];
q = head;
for (i = 1;i < length;i++) {
p = (LinkJoeNode*)malloc(sizeof(LinkJoeNode));
p->data = arr[i];
q->pNext = p;
q = p;
}
p->pNext = head;
return p;
}
//是不是要写show方法:打印输出大法,log
int mainDDDD(void) {
//从位置1开始,初始30个人,剩余15个人
int s = 1;
int m = 9;//每逢9就出圈
int k = 15;//表明出圈者要有15个人
int arr[30];
//构造初始的序列
for (int i = 0;i < 30;i++) {
arr[i] = i + 1;//因为我们为每一个变量的序号设为i+1
}
LinkJoeNode *p, *q;
LinkJoeNode *rear = CreateLkList(arr, 30);
p = rear;//p是遍历指针,只要游戏运行,那么这个p就要移动
while (k > 0) {
//step1:只要人数没有达到15个人,那么就要找出第m-1个,因为它的后继是即将要出圈
for (int j = 0;j < m - 1;j++) {
p = p->pNext;
}
//此时,p停在了m-1处
q = p->pNext;//q指向了第m个元素
printf("第%d个元素出圈\n", q->data);
//让m-1和m+1相连,此时q指向的第m个元素依然存在在内存空间当中,只是逻辑上
//不再存在和m元素相关联的联系
p->pNext = q->pNext;//p->pNext->pNext;
//为了防止内存泄漏
free(q);
k--;
}
getchar();
return 0;
}
#include "stdio.h"
#include "stdlib.h"
//设计数据项的数据结构
typedef struct Polynode {
int coef;//系数
int exp;//指数
Polynode* pNext;
}LinkPolyNode;
//面临算法抽象:补充说明:所有的存储结构按照幂指数升序
//我们需要新增节点,因为有可能在原链表不存在
///新多项式元素的地址
///coef:系数,exp:幂指数,pc:新节点要插入的位置
///返回值:新分配的节点地址
LinkPolyNode* attach(int coef, int exp, LinkPolyNode* pc) {
LinkPolyNode* p;
p = (LinkPolyNode*)malloc(sizeof(LinkPolyNode));
p->coef = coef;
p->exp=exp;
pc->pNext = p;
return p;
}
///将PolyA和PolyB进行相加,将结果放入PolyC中
///函数的输入是PolyA和PolyB的首地址
///函数返回的是PolyC的首地址
LinkPolyNode* MergePoly(LinkPolyNode* headA, LinkPolyNode* headB) {
LinkPolyNode* headC;//需要返回的多项式C的地址
LinkPolyNode *pa, *pb, *pc, *p;
int x;
pa = headA->pNext;
pb = headB->pNext;
headC = (LinkPolyNode*)malloc(sizeof(LinkPolyNode));
pc = headC;//此时将pc做C多项式的头节点
while (pa && pb) {
if (pa->exp == pb->exp) {
x = pa->coef + pb->coef;
if (x != 0)
pc = attach(x, pa->exp, pc);
pa = pa->pNext;
pb = pb->pNext;
continue;
}
if (pa->exp < pb->exp) {
p = pa;pa = pa->pNext;
}
else {
p = pb;pb = pb->pNext;
}
pc = attach(p->coef, p->exp, pc);
}
p = pa;
if (pa == NULL) p = pb;
while (p) {
pc = attach(p->coef, p->exp, pc);
p = p->pNext;
}
pc->pNext = NULL;
return headC;
}
//假定多项式的最低项是常数项,假定所有的元素都是关于X的多项式
//PolyA: 1+2x+3x^2
//PolyB: 3x+x^4
///设计显示的辅助函数
void ShowList(LinkPolyNode* pHead) {
LinkPolyNode* p;
p = pHead->pNext;
while (p != NULL) {
//美化设计显示的内容:设计常数项的显示
if (p->exp == 0) {
printf("%d", p->coef);
p = p->pNext;
continue;
}
//设计一次项的显示
if (p->exp == 1) {
//printf("x")
if (p->coef > 0) {
printf("+%dx",p->coef);
}
else {
printf("%dx", p->coef);
}
p = p->pNext;
continue;
}
//设计高此项的显示
if (p->coef > 0) {
printf("+%dx^%d", p->coef, p->exp);
}
else {
printf("%dx^%d", p->coef, p->exp);
}
p = p->pNext;
}
}
/*程序是调出来的,不是一蹴而就的,只有掌握了原理才能完成*/
int mainBBB(void) {
//PolyA: 1+2x+3x^2
//PolyB: 3x+x^4
LinkPolyNode HeadA,A1,A2,A3;
LinkPolyNode HeadB, B1, B2;
HeadA.pNext = &A1;
A1.pNext = &A2;
A2.pNext = &A3;
A3.pNext = NULL;
HeadB.pNext = &B1;
B1.pNext = &B2;
B2.pNext = NULL;
//建立多项式:PolyA: 1+2x+3x^2
A1.coef = 1;
A1.exp = 0;
A2.coef = 2;
A2.exp = 1;
A3.coef = 3;
A3.exp = 2;
//PolyB: 3x+x^4
B1.coef = 3;
B1.exp = 1;
B2.coef = 1;
B2.exp = 4;
printf("\n*********PolyA********\n");
ShowList(&HeadA);
printf("\n*********PolyB********\n");
ShowList(&HeadB);
LinkPolyNode* pPloyC;
pPloyC = MergePoly(&HeadA, &HeadB);
printf("\n*********PolyC********\n");
ShowList(pPloyC);
getchar();
return 0;
}
#include
#include
#include
using namespace std;
typedef struct student {
int num;
float score;
}node;
//单班人数上限是50
#define LIST_SIZE 50
#define TRUE 1
#define FALSE 0
//定义顺序表的结构
typedef struct {
node data[LIST_SIZE];
int last;//表明最后一个节点的位置
}SeqList;
//获取班级人数
int GetSize(SeqList* pList) {
return pList->last;
}
//遍历输出全体学生信息
void ShowSeqList(SeqList* pList) {
for (int i = 0;i < pList->last;i++) {
printf("学生的学号是%d,成绩是%f\n", pList->data[i].num, pList->data[i].score);
}
}
//初始化
SeqList* InitSeq() {
SeqList* pList = NULL;
pList = (SeqList*)malloc(sizeof(SeqList));
if (pList != NULL)
pList->last = 0;//初始化成功,且长度为0
return pList;
//因为在服务器分配中,连续分配大量空间,往往不容易成功
//所以我们经常在内部就进行判断
}
//插入元素
int InesrtStuSeq(SeqList* pList, node *pNode, int k) {
int j;
/*if (pList->last >= LIST_SIZE - 1)
return FALSE;*/
//移到函数之外,有业务人员维护插入
//如果这个函数被反复调用的开销很大,那么我们会放弃内部校验
//但是,如果这是一个对安全要求很高程序,内部校验依然需要
//如果去掉了内部校验,在实际的公司开发中,会有Team leader做codereview
//在本例中,我们假定k传入就是有效位置。
//永远不要相信调用者传入的数据,但是,在具体开发中,还是具体情况具体分析
for (j = pList->last;j >= k;j--) {
pList->data[j + 1].num = pList->data[j].num;
pList->data[j + 1].score = pList->data[j].score;
}
pList->data[k].num = pNode->num;
pList->data[k].score = pNode->score;
pList->last++;
return TRUE;
}
int DelSeqList(SeqList* pList, int k) {
/*if (k <= 0 || k > pList->last)
return FALSE;*/
if (pList->last == 0)
return FALSE;
for (int j = k;j <= pList->last;j++) {
pList->data[j].num = pList->data[j + 1].num;
pList->data[j].score = pList->data[j + 1].score;
}
pList->last--;
return TRUE;
}
//实现按学号查找的
void DisplayStu(SeqList* pList, int stuNo) {
for (int i = 0;i < pList->last;i++) {
if (pList->data[i].num == stuNo) {
printf("该学生的成绩是%f\n", pList->data[i].score);
return;
}
}
printf("该学生不存在\n");
}
int main222(void) {
SeqList* stuList = InitSeq();
node stu[2];
stu[0].num = 1;
stu[0].score = 99;
stu[1].num = 2;
stu[1].score = 100;
if (stuList) {
for (int i = 0;i < 2;i++) {
InesrtStuSeq(stuList, &stu[i], i);
}
}
ShowSeqList(stuList);
//DelSeqList(stuList, 1);
//ShowSeqList(stuList);
printf("\n************\n");
DisplayStu(stuList, 1);
getchar();
return 0;
}
************************************************************************************************************************************************
#pragma once
//假定处理的是一位数,没有括号
#define stackSize 100
#define TRUE 1
#define FALSE 0
typedef int BOOL;
typedef int ElemType;//元素类型
typedef struct {
ElemType stack[stackSize];
int top;//栈顶指针
}SeqStack;
///栈的初始化
BOOL init(SeqStack* pStack);
///栈的判空
BOOL isEmpty(SeqStack* pStack);
///压栈
///返回值为1表示成功,-1表示错误,
///pStack表示顺序栈,x表示压入元素
BOOL pushStack(SeqStack* pStack, ElemType x);
///出栈
ElemType popStack(SeqStack* pStack);
///获取栈顶元素
///如果栈为空,返回取值不成功,否则直接取出栈顶元素供用户使用
BOOL GetSeqStack(SeqStack* s, ElemType* data);
//判断是否是运算符,如果是运算符,返回true,否则返回false
BOOL Is_Operator(char oper);
//判断优先级:×/ 为2,+,-为1,
int Priority(char oper);
//计算数值:不考虑浮点数,也不考虑除数为0
int two_res(int oper, int opand1, int opand2);
#include
#define stackSize 100
#define TRUE 1
#define FALSE 0
typedef int BOOL;
typedef int ElemType;//元素类型
typedef struct {
ElemType stack[stackSize];
int top;//栈顶指针
}SeqStack;
///栈的初始化
BOOL init(SeqStack* pStack) {
pStack->top = 0;
return 1;
}
///栈的判空
BOOL isEmpty(SeqStack* pStack) {
return (pStack->top == 0);
}
///压栈
///返回值为1表示成功,-1表示错误,
///pStack表示顺序栈,x表示压入元素
BOOL pushStack(SeqStack* pStack, ElemType x) {
if (pStack->top == stackSize)
{
printf("空间溢出\n");
return FALSE;
}
pStack->top = pStack->top + 1;
pStack->stack[pStack->top] = x;
return TRUE;
}
///出栈
ElemType popStack(SeqStack* pStack) {
ElemType tmp;
if (pStack->top == 0) {
printf("当前是空栈\n");
return -1;
}
tmp = pStack->stack[pStack->top];
pStack->top = pStack->top - 1;//逻辑上的出栈
return tmp;
}
void myConv(SeqStack* pStack, int n) {
int e;//每一个元素
while (n) {
pushStack(pStack, n % 8);
n = n / 8;
}
while (!isEmpty(pStack)) {
e = popStack(pStack);
printf("%d", e);
}
}
///获取栈顶元素
///如果栈为空,返回取值不成功,否则直接取出栈顶元素供用户使用
BOOL GetSeqStack(SeqStack* s, ElemType* data) {
if (s->top == 0)
return FALSE;
*data = s->stack[s->top];
return TRUE;
}
int main1(void) {
SeqStack s;
init(&s);
printf("十进制数1348,转为的8进制是:\n");
myConv(&s, 1348);
getchar();
return 0;
}
/*
首先我们必须知道,一旦设立了栈,那么就请按照栈的特点进行操作
“先进后出”
我们都知道,只要知道下标就可以获取数组的元素
stack[0],stack[1],stack[2].....
我们没有能力再直接操作上面的元素
我们只能取栈顶,因为只有这一个函数;其他,要么出栈,要么进栈
这就是数据结构思考问题方式:我们设立一个逻辑结构,就用这个结构控制
程序逻辑
*/
#include
#include
typedef int datatype;
typedef struct node {
datatype data;
struct node * pNext;
}LinkStack;
//入栈
LinkStack* PushLkStack(LinkStack* top, datatype x) {
LinkStack* p;
p = (LinkStack*)malloc(sizeof(LinkStack));
p->data = x;
p->pNext = top; //类似于首先将p链入链表
top = p;//top上移到当前栈顶,指向刚刚加入的p节点,此时top永远指向栈顶的第一个元素
return top;
}
//出栈
LinkStack* PopLkStack(LinkStack* top, datatype* pData) {
LinkStack* p;
//一旦我们出栈,那么我们认为这个元素就不应当维护链表指向的关系了
if (top != NULL) {
*pData = top->data;
p = top;//此时我们将当前的栈顶元素的位置,保存下来了,接下栈顶元素即将脱离
top = p->pNext;
free(p);
}
return top;
}
int main2(void) {
LinkStack* pTop=NULL;
pTop = PushLkStack(pTop, 1);
pTop = PushLkStack(pTop, 1);
getchar();
return 0;
}
#include
#include
#define QUEUE_SIZE 100
typedef int datatype;
#define TRUE 1
#define FALSE 0
typedef int BOOL;
typedef struct queue {
datatype data[QUEUE_SIZE];
int front, rear;
}SeqQueue;
void Init_SqQueue(SeqQueue* sq) {
sq->front = QUEUE_SIZE - 1;
sq->rear = QUEUE_SIZE - 1;
}
BOOL IsEmpty_SqQueue(SeqQueue *sq) {
if (sq->rear == sq->front)
return TRUE;
return FALSE;
}
//返回的应当是数组的角标
int Get_SqQueue(SeqQueue* sq) {
if (!IsEmpty_SqQueue(sq)) {
return (sq->front + 1) % QUEUE_SIZE;
}
return -1;
}
BOOL EnSqQueue(SeqQueue* sq, datatype x) {
if (sq->front == (sq->rear + 1) % QUEUE_SIZE)
return FALSE;
sq->rear = (sq->rear + 1) % QUEUE_SIZE;//队尾指针后移
sq->data[sq->rear] = x;//元素入队
return TRUE;
}
///出队如果队空,返回的是元素的角标记为-1;否则,返回数组角标
int DeSqQueue(SeqQueue* sq) {
if (!IsEmpty_SqQueue(sq)) {
sq->front = (sq->front + 1) % QUEUE_SIZE;
return sq->front;
}
return -1;
}
int mainAA(void) {
return 0;
}
#include
#include
typedef int BOOL;
#define TRUE 1
#define FALSE 0
typedef int datatype;
typedef struct node {
datatype data;
struct node * next;
}LinkListNode;
typedef struct {
LinkListNode* front, *rear;
}LinkQueue;
void Init_LkQueue(LinkQueue* lq) {
lq->front = (LinkListNode*)malloc(sizeof(LinkListNode));
lq->front->next = NULL;
lq->rear = lq->front;
}
BOOL IsEmpty_LkQueue(LinkQueue* lq) {
if (lq->front == lq->rear)
return TRUE;
else
return FALSE;
}
BOOL Get_LkQueue(LinkQueue* lq, datatype *x) {
if (IsEmpty_LkQueue(lq))
return FALSE;
x = &(lq->front->next->data);//因为front始终指向头节点,而队列是先进先出,front的next一定是队头元素
return TRUE;
}
void Insert_LkQueue(LinkQueue* lq, datatype x) {
lq->rear->next = (LinkListNode*)malloc(sizeof(LinkListNode));
//新节点入队尾部
lq->rear = lq->rear->next;
lq->rear->data = x;
lq->rear->next = NULL;
}
LinkListNode* Del_LkQueue(LinkQueue* lq) {
LinkListNode* s;
if (!IsEmpty_LkQueue(lq)) {
s = lq->front->next;
if (s->next == NULL)//队中只有一个节点
lq->rear = lq->front;//队列置空
else
lq->front->next = s->next;//因为lq是我们自己设计记录位置的指针,所以要让指向下一个队头元素
return s;
}
return NULL;
}
void Destroy_LkQueue(LinkQueue* lq) {
//即使销毁队列,也要保持住结构
LinkListNode* s;
while (!IsEmpty_LkQueue(lq)) {
s = Del_LkQueue(lq);
free(s);
}
free(lq->front);//释放头节点
lq->front = NULL;
lq->front = NULL;
}
int main222(void) {
LinkQueue node;
LinkQueue *lpPtr = &node;
LinkListNode* sPtr;
datatype value;
Init_LkQueue(lpPtr);
//0,1,1,0入队
Insert_LkQueue(lpPtr, 0);
Insert_LkQueue(lpPtr, 1);
Insert_LkQueue(lpPtr, 1);
Insert_LkQueue(lpPtr, 0);
int N = 42;
for (int i = 0;i < 42;i++) {
//队头元素出队
sPtr = Del_LkQueue(lpPtr);
if(sPtr!=NULL){
//队头的两个元素,n-1 n 生成新的系数
value = sPtr->data + lpPtr->front->next->data;
if (sPtr->data != 0) {
printf("%d ", sPtr->data);
}
Insert_LkQueue(lpPtr, value);
}
if (lpPtr->front->next->data == 0) {
//队头元素作为分隔符
Insert_LkQueue(lpPtr, 0);
printf("\n");
}
}
getchar();
return 0;
}
#include
#define TRUE 1
#define FALSE 0
int a[9], b[17], c[17],s[9];//用来处理第i行上第j个元素的冲突问题
void eightQueen() {
int i, j;
//因为这样对角线有15条,且i+j从2开始
//初始化好全部的冲突,现在都可以放皇后
for (i = 2;i <= 16;i++) {
if (i >= 2 && i <= 9) {
a[i - 1] = TRUE;
}
b[i] = TRUE;
c[i] = TRUE;
}
i = 1;
j = 1;
//开始使用回溯法进行处理
while (i<=8) {
while (j <= 8) {
//在第i行寻找潜在的第j列
if (a[j] && b[i + j] && c[i - j + 9])
break;
j++;
}
if (j <= 8) {
//找到安全位置
a[j] = FALSE;
b[i + j] = FALSE;
c[i- j + 9] = FALSE;
s[i] = j;
i++;//前进到下一行
j = 1;
}
else {
//当前的第i行已经不能再放入元素了,那么回溯到上一行再寻找
i--;
j = s[i];
a[j] = TRUE;
b[i + j] = TRUE;
c[i - j + 9] = TRUE;
j++;//前进到下一列
}
}
}
int main333333() {
eightQueen();
for (int i = 1;i < 9;i++) {
printf("%d,%d\n", i, s[i]);
}
getchar();
return 0;
}
#include
//使用回溯,每一行放一个,直到不冲突
int c[20], n = 8, cnt = 0;
//找到一个解就是输出,c[]里面存的是可以放的皇后的列
void print() {
for (int i = 0;i < n;++i) {
for (int j = 0;j < n;++j) {
if (j == c[i])
printf("1 "); //1表示皇后占位
else
printf("0 "); //0表示空的位置
}
printf("\n");
}
printf("\n");
}
//用r表示搜索到了第r行
void search(int r) {
if (r == n) {
//说明已经放置成功
print();
++cnt;
return;
}
//什么时候才能进入下一级递归呢?
//只有满足了当前皇后和前面所有的皇后都不互相攻击的时候,才能进入下一级递归
for (int i = 0;i < n;++i) {
c[r] = i;
int ok = 1;
for (int j = 0;j < r;++j) {
if (c[r] == c[j] || r - j == c[r] - c[j] || r - j == c[j] - c[r]) {
ok = 0;
break;
}
}
if (ok)
search(r + 1);
}
}
int mainQQQ(void) {
search(0);
printf("八皇后一共有%d种解法", cnt);
getchar();
return 0;
}
#include
#define TRUE 1
#define FALSE 0
int a[9], b[17], c[17], s[9];//用来处理第i行上第j个元素的冲突问题
void print() {
printf("\n");
for (int i = 1;i < 9;i++) {
printf("%d,%d\n", i, s[i]);
}
}
void move(int i,int j) {
a[j] = TRUE;
b[i + j] = TRUE;
c[i - j + 9] = TRUE;
}
void eightQueenEx() {
int i, j;
//因为这样对角线有15条,且i+j从2开始
//初始化好全部的冲突,现在都可以放皇后
for (i = 2;i <= 16;i++) {
if (i >= 2 && i <= 9) {
a[i - 1] = TRUE;
}
b[i] = TRUE;
c[i] = TRUE;
}
i = 1;
j = 1;
//开始使用回溯法进行处理
while (i <= 8) {
while (j <= 8) {
//在第i行寻找潜在的第j列
if (a[j] && b[i + j] && c[i - j + 9])
break;
j++;
}
if (j <= 8) {
//找到安全位置
a[j] = FALSE;
b[i + j] = FALSE;
c[i - j + 9] = FALSE;
s[i] = j;
if (i == 8) {
//找到一个解
print();
//移除i,j位置上的皇后
move(i, j);
//回溯退栈
i = i - 1;
j = s[i];
move(i, j);
j++;//从上一个的第j+1列再寻找
}
else{
i++;//前进到下一行
j = 1;
}
}
else {
//当前的第i行已经不能再放入元素了,那么回溯到上一行再寻找
i--;
if (i >= 1) {
//如果栈不空,那么移除皇后
j = s[i];
move(i, j);
j++;//前进到下一列
}
}
}
}
int main4444() {
eightQueenEx();
getchar();
return 0;
}
/*
求的一个解,我们就打印,但是,不停止,
我们让我们的皇后移除,返回到上一行的下一个j列,看看能不能找到
如果上一行的j列全部遍历结束,那么再回溯到上上一行,直到到第一行为止
*/
#include
int fun(int n) {
if (n > 1)
return n*fun(n - 1);
if (n == 1)
return 1;
}
int funG(int n) {
int temp = 1;
for (int i = 1;i <= n;i++) {
temp *= i;
}
return temp;
}
int main55555(void) {
printf("5*4*3*2=%d", funG(5));
getchar();
return 0;
}
#include
//1+2+3+4+5....
//递归是我们程序设计入门一个槛
//我们可以使用重复的力量,来解决这个问题
int sum = 0;
int FunGaosi(int value) {
if (value == 1)
return 1;
sum = value + FunGaosi(value - 1);
return sum;
}
/*int go() {
}
int gogo() {
go();
}
int fun() {
gogo();
}*/
int main3(void) {
printf("%d", FunGaosi(4));
getchar();
return 0;
}
//call stack最基本的作用:
/*
就是告诉程序员,你现在停留的指令在什么位置,当你的函数返回时
你将在哪一个函数的指令继续推进你的程序。
只有我们清楚的知道你的程序代码是如何推进,你才知道你的程序怎么运行的。
bug,是程序没有按照我们预定的逻辑进行推进,那么我们就必须知道
在哪里运行的路径不正确。
*/
#include
#include "SeqStack.h"
int main222(void) {
char expression[] = "1562/-3*+#";
int position = 0;
int operand1 = 0;
int operand2 = 0;
int evaluate = 0;//没有所谓的操作符
SeqStack sStack;
init(&sStack);
while (expression[position]!='#')
{
if (Is_Operator(expression[position])) {
operand1 = popStack(&sStack);
operand2 = popStack(&sStack);
pushStack(&sStack, two_res(expression[position], operand1, operand2));
}
else {
pushStack(&sStack, expression[position] - 48);
}
position++;
}
evaluate = popStack(&sStack);
printf("%d ", evaluate);
getchar();
return 0;
}
#include
typedef int BOOL;
#define TRUE 1
#define FALSE 0
#define ROWS 7
#define COLUMNS 10
int MyMaze[][11] =
{ { 1,1,1,1,1,1,1,1,1,1,1 },
{ 1,0,1,0,0,1,1,1,0,0,1 },
{ 1,0,0,0,0,0,1,0,0,1,1 },
{ 1,0,1,1,1,0,0,0,1,1,1 },
{ 1,0,0,0,1,0,1,1,0,1,1 },
{ 1,1,0,0,1,0,1,0,0,0,1 },
{ 1,1,1,0,0,0,0,0,1,0,1 },
{ 1,1,1,1,1,1,1,1,1,1,1 } };
//判断是否是障碍
BOOL Valid(int row, int col) {
BOOL flag = FALSE;
if (row >= 1 && row < ROWS && col >= 1 && col < COLUMNS && MyMaze[row][col] == 0)
flag = TRUE;
return flag;
}
//只要我们相信我们设计的递归函数,严格按照我们设计的指令序列
//依次,运行,那么这个函数本身就是蕴含答案的
//函数的栈帧重复运行将我们设计的如for,while循环的过程隐藏
//所以,直觉上会觉得递归抽象。
BOOL exitMaze(int row, int col) {
BOOL done = FALSE;
if (Valid(row, col)) {
//走过的标记,我们给2
MyMaze[row][col] = 2;
//抵达出口
if (row == (ROWS - 1) && col == (COLUMNS - 1)) {
done = TRUE;
}
else {
//未达到终点,我们就按照E-》S—》W—》N
done = exitMaze(row, col + 1);
if (!done)
done = exitMaze(row + 1, col);
if (!done)
done = exitMaze(row, col - 1);
if (!done)
done = exitMaze(row - 1,col);
}
// 设一个可以找到的表示,我们将数字9表示可以通过的路径
if (done)
MyMaze[row][col] = 9;
}
return done;
}
int main(void) {
BOOL done = exitMaze(1, 1);
if (done) {
for (int i = 0;i < ROWS;i++) {
for (int j = 0;j < COLUMNS;j++) {
printf("%d", MyMaze[i][j]);
}
printf("\n");
}
}
else {
printf("没有找到路径");
}
getchar();
return 0;
}
#include
#include
typedef int BOOL;
#define TRUE 1
#define FALSE 0
typedef struct {
int x; //表示节点的横坐标
int y;//表示节点的纵坐标
int d;//表示节点的方向
}DataType;
typedef struct linknode {
DataType data;
struct linknode* pNext;
}LinkStack;
LinkStack* InitLkStack(void) {
LinkStack* p = NULL;
p = (LinkStack*)malloc(sizeof(LinkStack));
if (p != NULL)
p->pNext = NULL;
return p;
}//建立一个带头节点的链表作为链栈
BOOL IsEmptyLkMazeStack(LinkStack* top) {
return (top->pNext == NULL);
}
LinkStack* PushLkStack(LinkStack* top, DataType elem) {
LinkStack* p;
p = (LinkStack*)malloc(sizeof(LinkStack));
p->data.x = elem.x;
p->data.y = elem.y;
p->data.d = elem.d;
p->pNext = top; //p节点尾插入lkStack
top = p;//top栈顶指针上移
return top;
}
//出栈
LinkStack* PopLkStack(LinkStack* top, DataType *pData) {
LinkStack* p;
if (top != NULL) {
*pData = top->data;
p = top;
top = p->pNext;
free(p);
}
return top;
}
int main1add(void) {
//迷宫
int maze[][11] = {
{1,1,1,1,1,1,1,1,1,1,1 },
{1,0,1,0,0,1,1,1,0,0,1 },
{1,0,0,0,0,0,1,0,0,1,1 },
{1,0,1,1,1,0,0,0,1,1,1 },
{1,0,0,0,1,0,1,1,0,1,1 },
{1,1,0,0,1,0,1,0,0,0,1 },
{1,1,1,0,0,0,0,0,1,0,1 },
{1,1,1,1,1,1,1,1,1,1,1 },
};
//路径移动辅助数组
int direction[4][2] = {
{0,1},
{1,0},
{0,-1},
{-1,0}
};
LinkStack* pTop = NULL;
pTop = InitLkStack();//用来保存路径
DataType element;
element.x = 1;
element.y = 1;
element.d = -1;//保证下一个节点推进是起点方向是0
pTop = PushLkStack(pTop, element);//迷宫入口入栈
int i, j, k;//当前的横坐标,纵坐标以及方向
int g, h;//潜在的下一个方向
while (!IsEmptyLkMazeStack(pTop)) {
//获得当前节点的坐标
i = pTop->data.x;
j = pTop->data.y;
k = pTop->data.d+1;
while (k <= 3) {
g = i + direction[k][0];
h = j + direction[k][1];
if (g == 6 && h == 9 && maze[g][h] == 0) {
printf("找到了\n");
printf("节点位置是:%d,%d\n", i, j);
while (!IsEmptyLkMazeStack(pTop)) {
pTop = PopLkStack(pTop, &element);
printf("节点位置是:%d,%d\n", pTop->data.x, pTop->data.y);
}
getchar();
return;
}
//判断是否可以前进到下一个节点
if (maze[g][h] == 0) {
maze[g][h] = 2;//不要走回头路
//要将节点路径保留,那么就要入栈
element.x = g;
element.y = h;
element.d = -1;
pTop = PushLkStack(pTop, element);
break;
}
k = k + 1;
}
//回溯:k大于3说明,所有的当前节点的4个方向都找过,没有通路,所以要退栈,当上一个节点上
if (k > 3) {
pTop = PopLkStack(pTop, &element);//此时element接住上一个在栈中的节点
}
}
printf("没有找到通路\n");
return 0;
}
//思想:看看我们需要设计的业务中,有那些可以用我们已经学过的数据结构
//进行刻画,将这些业务问题,变成数据结构的组织问题
#include
int mainA(void) {
int n = 50;
int queue[42] = { 0,1,1,0 };//0是换行
int front = 1,rear = 4;//首先将杨辉三角的第一行输入
for (int i = 0;i < n;i++) {
queue[rear] = queue[front - 1] + queue[front];
//将队头的两个元素和插入rear位置
printf("%d ", queue[rear]);
rear++;//准备好新元素的位置
if (queue[front] == 0) {
//添加新的分割
queue[rear] = 0;
rear++;
printf("\n");
}
front++;
}
getchar();
return 0;
}
//front是即将要处理的数据,rear是添加的数据。
#include
#include
#include "SeqStack.h"
///栈的初始化
BOOL init(SeqStack* pStack) {
pStack->top = 0;
return 1;
}
///栈的判空
BOOL isEmpty(SeqStack* pStack) {
return (pStack->top == 0);
}
///压栈
///返回值为1表示成功,-1表示错误,
///pStack表示顺序栈,x表示压入元素
BOOL pushStack(SeqStack* pStack, ElemType x) {
if (pStack->top == stackSize)
{
printf("空间溢出\n");
return FALSE;
}
pStack->top = pStack->top + 1;
pStack->stack[pStack->top] = x;
return TRUE;
}
///出栈
ElemType popStack(SeqStack* pStack) {
ElemType tmp;
if (pStack->top == 0) {
printf("当前是空栈\n");
return -1;
}
tmp = pStack->stack[pStack->top];
pStack->top = pStack->top - 1;//逻辑上的出栈
return tmp;
}
///获取栈顶元素
///如果栈为空,返回取值不成功,否则直接取出栈顶元素供用户使用
BOOL GetSeqStack(SeqStack* s, ElemType* data) {
if (s->top == 0)
return FALSE;
*data = s->stack[s->top];
return TRUE;
}
//判断是否是运算符,如果是运算符,返回true,否则返回false
BOOL Is_Operator(char oper) {
switch (oper)
{
case '+':
case'-':
case '*':
case '/':
return TRUE;
default:
return FALSE;
}
}
//判断优先级:×/ 为2,+,-为1,
int Priority(char oper) {
switch (oper)
{
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default:
return 0;
}
}
//计算数值:不考虑浮点数,也不考虑除数为0
int two_res(int oper, int opand1, int opand2) {
switch (oper)
{
case '+': return (opand2 + opand1);
case '-':return (opand2 - opand1);
case '*':return (opand2 * opand1);
case '/':return (opand2 / opand1);
default:
return 0;
}
}
int main1111(void) {
char expression[] = "8*9-4/2";
int position = 0;//扫描的字符串
int op = 0;//运算符
int operand1 = 0;
int operand2 = 0;
int evaluate = 0;//运算结果
SeqStack sOperator;//操作符栈
init(&sOperator);
SeqStack sOperand;
init(&sOperand);// 操作数栈
//第一步扫描字符串
while (expression[position] != '\0' && expression[position] != '\n') {
if (Is_Operator(expression[position])) {
if (!isEmpty(&sOperator)) {
while (Priority(expression[position])<=
Priority(sOperator.stack[sOperator.top])
&&!isEmpty(&sOperator)) {
operand1 = popStack(&sOperand);
operand2 = popStack(&sOperand);
op = popStack(&sOperator);
pushStack(&sOperand, two_res(op, operand1, operand2));
}
}
pushStack(&sOperator, expression[position]);
}
else {
pushStack(&sOperand, expression[position] - 48);//将Ascii码转成数值
}
position++;
}
//清空操作符栈
while (!isEmpty(&sOperator)) {
op = popStack(&sOperator);
operand1 = popStack(&sOperand);
operand2 = popStack(&sOperand);
pushStack(&sOperand, two_res(op,operand1, operand2));
}
printf("%d", popStack(&sOperand));
getchar();
return 0;
}
#include
#include "SeqStack.h"
//对扩展开放,对修改封闭
//修改一下运算符
int Is_OperatorEx(char op) {
switch (op)
{
case '(':
case ')':
case '+':
case '-':
case '*':
case '/':
return 1;
default:
return 0;
}
}
int PriorityEx(char op) {
switch (op)
{
case '(':return 1;
case '+':
case '-':return 2;
case '*':
case '/':
return 3;
default:
return 0;
}
}
int main21(void) {
char inorder[50] = "1+2-3#"; //"1+((2+3)*4)-5#";//声明中缀(中序)表达式的字符串
char postorder[50];
int op = 0;//运算符
int in_position;//中序表达式的角标
int po_position;//后续表达式的角标
int i;
in_position = 0;
po_position = 0;
for (i = 0;i < 50;i++)
postorder[i] = 0;
SeqStack sOper;
init(&sOper);
while (inorder[in_position]!='#')
{
//todo利用栈进行优先级,去括号的过程
if (Is_OperatorEx(inorder[in_position])) {
if (isEmpty(&sOper) || inorder[in_position] == '(') {
pushStack(&sOper, inorder[in_position]);
}
else {
if (inorder[in_position] == ')') {
//匹配左括号
while (sOper.stack[sOper.top] != '(') {
op = popStack(&sOper);
postorder[po_position++] = op;
}
if (sOper.stack[sOper.top] == '(')
{
popStack(&sOper);
}
}//ctrl+]
else
{
while (PriorityEx(inorder[in_position]) <= PriorityEx(sOper.stack[sOper.top]) && !isEmpty(&sOper)) {
op = popStack(&sOper);
postorder[po_position++] = op;
}
pushStack(&sOper, inorder[in_position]);
}
}
}
else {
postorder[po_position++] = inorder[in_position];
}
in_position++;
}
while (!isEmpty(&sOper)) {
op = popStack(&sOper);
postorder[po_position++] = op;
}
for (int i = 0;i < 50;i++) {
if (postorder[i] == 0)
break;
printf("%c", postorder[i]);
}
getchar();
return 0;
}
************************************************************************************************************************************************
顺序存储的二叉树
#include
//用顺序数组的形式,存储建立一个二叉搜索树
/*
1,我们根据完全二叉树的编号,我们做数组角标1存储输入的第一个元素
2,得到根元素之后,我们开始建立这样的二叉树
若元素的值大于根节点,则将元素往根节点的右子节点移动,若此节点为空
那么,存入,否则,直到找到这个空位置
若元素的值小于根节点,按么则将元素往根节点的左子节点移动,直到找到
空位存储之
注意,如何寻找节点的左右子节点呢?
用左节点为父节点×2,右子节点为父节点×2+1,
根据这个关系,找到角标,存储之。
*/
void create_btree(int b_tree[], int nodelist[], int len) {
int i;
int level;//树的层级,我们用这个level去推进计算将要插入的数字的角标,
//直白的说,就是确定它的树中位置
b_tree[1] = nodelist[1];
for (i = 2;i < len;i++) {
level = 1;//每一个新元素在二叉搜索树的位置都是通过根节点进行搜索
while (b_tree[level] != 0) {//0表示当前的子树位置是空的
if (nodelist[i] < b_tree[level]) {
level = level * 2;
}
else {
level = level * 2 + 1;
}
}
//出了循环,说明新元素在二叉搜索树中的位置就定下了
b_tree[level] = nodelist[i];
}
}
//若一棵树的左子树所有的值都比根节点的值小,右子树的值都比根大
//这样的二叉树,我们成为二叉查找树(Binary search tree)
int main1(void){
int b_tree[16] = { 0 };
int nodelist[16] = { 0, 6,3,8,
5,2,9,4,7,
10,0,0,0,
0,0,0};//根据角标的定义,我们的数组形式不用0开始做编号
create_btree(b_tree, nodelist, 16);
for (int i = 1;i < 16;i++) {
printf("%d,[%d] \n", i, b_tree[i]);
}
getchar();
return 0;
}
二叉链表的存储方式
#include
#include
typedef int datatype ;
typedef struct node {
datatype data;
struct node *left, *right;
}BitTree;
//辅助队列Q,这是用来存关系的
BitTree* Q[16];//这是一个指针数组,它将缓存节点的地址,因为这个地址将以
//left域,或者right域进入二叉链表,它本身不维护i,2i,2i+1的关系
//他的关系通过front,rear来维护
//按照直观的建立,我们首先想到的是层次法
//我们根据层次,来逐一将二叉树建立
//输入的数组是按照完全二叉树的编号规则设立,即
//数组角标反映了节点位置关系(存联系)
//逐个扫描数组,直到所有的节点都存取完毕之后,就结束
//约定,0表示数组当前元素为空,最后一个节点标志是-999
BitTree* CreateBinTree(int arr[]) {
int i = 1;
//只要我们没有扫描完元素,那么这个二叉链表就没有完成
//只要扫描,我们就malloc一个节点,然后把这个节点存入left域或者right域
int front = 1, rear = 0;
BitTree* root = NULL;
BitTree* s;//暂存节点
while (arr[i]!=-999) {
s = NULL;
if (arr[i] != 0) {//意味着这个不是空节点,那么我们就要分配空间
s = (BitTree*)malloc(sizeof(BitTree));
s->data = arr[i];//存数值
s->left = NULL;
s->right = NULL;
}
//要让我们新节点入队,进入缓存,等待分配双亲的left域和right域
Q[++rear] = s;
if (rear == 1)
{
root = s;
}
else {
if (s != NULL && Q[front]) {
if (rear % 2 == 0) {
Q[front]->left = s;
}
else {
Q[front]->right = s;
}
}
if (rear % 2 == 1)
front++;
}
i++;
}
return root;
}
//树遍历问题:非线性结构的输出问题:前序,中序,后序
void inorder(BitTree *t) {
if (t) {
inorder(t->left);
printf("%d ", t->data);
inorder(t->right);
}
}
void preorder(BitTree* t) {
if (t) {
//根左右
printf("%d ", t->data);
preorder(t->left);
preorder(t->right);
}
}
void postorder(BitTree* t) {
if (t) {
//左右根
postorder(t->left);
postorder(t->right);
printf("%d ", t->data);
}
}
int main(void) {
int arr[17] = {0,6,3,8,
2,5,7,9,
0,0,4,0,
0,0,0,10,
-999
};
BitTree *root = CreateBinTree(arr);
inorder(root);
getchar();
return 0;
}
二叉树非递归遍历的经典解法 BinTreeNonRecvImp
#include
#include
typedef int datatype;
typedef struct node {
datatype data;
struct node *left, *right;
}BitTree;
//*************************Begin*************
//添加辅助栈的结构:主要是用来保存树的节点
//简言之,这个就是用来存树节点的栈
typedef BitTree BitTreeNode;
typedef int BOOL;
#define TRUE 1
#define FALSE 0
//-——————————修订V0.01——changed by dingst
//BitTreeNode data;那么一定是侵入式的,为什么=》逐个深拷贝每一个分量
//只要是BitTreeNode* Addr;在32位中,这个值永远是4字节
//保存的都是传入的源节点的地址值的一个副本(c/C++语言,都是指拷贝形式)
typedef struct linknode {
BitTreeNode* _NodeAddrCopy;
struct linknode* pNext;
}LinkStack;
LinkStack* InitLkStack(void) {
LinkStack* p = NULL;
p = (LinkStack*)malloc(sizeof(LinkStack));
if (p != NULL)
p->pNext = NULL;
return p;
}//建立一个带头节点的链表作为链栈
BOOL IsEmptyLkMazeStack(LinkStack* top) {
return (top->pNext == NULL);
}
LinkStack* PushLkStack(LinkStack* top, BitTreeNode* elem) {
LinkStack* p = NULL;
//深拷贝的bug修订,如果传入的是空指针,那么不能访问,修订人丁宋涛
//elem就是将当前树节点的地址值考一份:比如0x00d500578,我们现在
//栈就是把这个0x00d500578拷贝一份下来,放到我们_NodeAddrCopy
//及时栈节点出栈,此时也是我么你的_NodeAddrCopy这个变量被释放
//与原先的树节点没有关系,不会影响
//elem是这个函数的形参,它将调用者的实参拷贝一份放入到elem中
//所以elem就是这个0x00d500578
//我们用p->_NodeAddrCopy = elem;的操作
//就把0x00d500578保存下来了,此时他就是原节点地址的一个副本
if (elem != NULL)
{
p = (LinkStack*)malloc(sizeof(LinkStack));
//todo:我们用新建节点,对传入的二叉树节点做一个深拷贝
//changed by dingst,我们要做非侵入式的设计
/*p->data.data = elem->data;
p->data.left = elem->left;
p->data.right = elem->right;*/
p->_NodeAddrCopy = elem;
p->pNext = top; //p节点尾插入lkStack
top = p;//top栈顶指针上移
}
//我们思考,既然我们允许空指针进入到我们的栈结构,那么我们如何修订
//我们的出栈?
//top为空以为着?
//意味着是否和栈空条件冲突了?
//如果我们让我们的NULL进入栈空间,那么出栈也会造成空指针
//这意味着当前的节点不动
return top;
}
//出栈:pData是传入的一个“临时”空间用来接收出栈的节点信息。
LinkStack* PopLkStack(LinkStack* top, BitTreeNode *pData) {
LinkStack* p;
if (top != NULL) {
//*pData = top->data;
//----changed by dingst
/*pData->data = top->data.data;
pData->left = top->data.left;
pData->right = top->data.right;*/
pData = top->_NodeAddrCopy;
//pData实际上深拷贝了一份节点信息,所以释放栈中节点,不会影响
//节点数据
p = top;
top = p->pNext;
free(p);
}
return top;
}
//*************************End***************
//辅助队列Q,这是用来存关系的
BitTree* Q[16];//这是一个指针数组,它将缓存节点的地址,因为这个地址将以
//left域,或者right域进入二叉链表,它本身不维护i,2i,2i+1的关系
//他的关系通过front,rear来维护
//按照直观的建立,我们首先想到的是层次法
//我们根据层次,来逐一将二叉树建立
//输入的数组是按照完全二叉树的编号规则设立,即
//数组角标反映了节点位置关系(存联系)
//逐个扫描数组,直到所有的节点都存取完毕之后,就结束
//约定,0表示数组当前元素为空,最后一个节点标志是-999
BitTree* CreateBinTree(int arr[]) {
int i = 1;
//只要我们没有扫描完元素,那么这个二叉链表就没有完成
//只要扫描,我们就malloc一个节点,然后把这个节点存入left域或者right域
int front = 1, rear = 0;
BitTree* root = NULL;
BitTree* s;//暂存节点
while (arr[i] != -999) {
s = NULL;
if (arr[i] != 0) {//意味着这个不是空节点,那么我们就要分配空间
s = (BitTree*)malloc(sizeof(BitTree));
s->data = arr[i];//存数值
s->left = NULL;
s->right = NULL;
}
//要让我们新节点入队,进入缓存,等待分配双亲的left域和right域
Q[++rear] = s;
if (rear == 1)
{
root = s;
}
else {
if (s != NULL && Q[front]) {
if (rear % 2 == 0) {
Q[front]->left = s;
}
else {
Q[front]->right = s;
}
}
if (rear % 2 == 1)
front++;
}
i++;
}
return root;
}
//树遍历问题:非线性结构的输出问题:前序,中序,后序
void preorder(BitTree* t) {
if (t) {
//根左右
printf("%d ", t->data);
preorder(t->left);
preorder(t->right);
}
}
void NonRecrvPreOrder(BitTree* root) {
LinkStack* pTop = NULL;
//BitTreeNode TempNode;//用来接栈中对应的二叉树节点的
//-----change by dingst
BitTreeNode* pNode; //我要让pNode推进树遍历,而且pNode就是
//真实地址的副本
pTop = InitLkStack();
//pTop = PushLkStack(pTop, root);
//---change by dingst
pNode = root;
pTop = PushLkStack(pTop, pNode);
while (!IsEmptyLkMazeStack(pTop)) {
pNode = pTop->_NodeAddrCopy;//178行的这个赋值操作,就将真实的节点地址赋给了pNode这个函数的局部变量
pTop = PopLkStack(pTop, pNode);
if (pNode != NULL) {
printf("%d ",pNode->data);
//对右子树压栈
pTop = PushLkStack(pTop, pNode->right);
pTop = PushLkStack(pTop, pNode->left);
}
}
}
void inorder(BitTree *t) {
if (t) {
inorder(t->left);
printf("%d ", t->data);
inorder(t->right);
}
}
/*
中序就是左根右,这就意味着,当我们从根节点出发,应当首先走向左孩子
,而根的左孩子,是根的左子树的根节点,因此
又必须,继续访问其左孩子,直到左孩子为空
当这个节点访问之后,按照相同的规则,访问其右子树
我们借助的栈,就应该按照左根右来压栈
对于任意节点p
1 如果其左孩子不为空,则将p入栈,然后将p的左孩子置为当前的p,然后
再对p进行相同的处理
2 若左孩子为空,则取栈顶元素进行出栈操作,访问当前栈顶节点,然后
将当前的p置为栈顶节点的右孩子
3 直到p为NULL为止
*/
void NonRecvInorder(BitTree *root) {
LinkStack* pTop = NULL;
BitTreeNode TempNode;//用来接收栈中的对应的二叉树的节点
pTop = InitLkStack();
BitTree *p = root;
while (p != NULL || !IsEmptyLkMazeStack(pTop)) {
while (p != NULL) {
pTop = PushLkStack(pTop, p);
p = p->left;
}
if (!IsEmptyLkMazeStack(pTop)) {
//因为此时我们在输出的节点信息,就一定要从栈中
//取出元素
//这个是取出的元素的_NodeAddrCopy分量就是树中节点的地址
//因此对这个节点使用->就可以获得真实的数据
printf("%d ", pTop->_NodeAddrCopy->data);
p = pTop->_NodeAddrCopy; //因为我们设计的p就是要走完root全部节点,因此
//p必须获得的是树节点的真实地址
pTop = PopLkStack(pTop, &TempNode);//当我们把左子树的左叶子节点走完以后,
//此时栈顶一定是这个左孩子的根,所以根据左根右,这个根要出栈
//----change by dingst
//p = &TempNode; 因为tmpenode是bitnode的对象,
//所以tmpenode的地址值可以赋值给p这个指针变量,但是这个tempnode的这个地址值
//是肯定不等于真实树节点的地址值的
p = p->right;//走向根的右孩子
}
}
}
void postorder(BitTree* t) {
if (t) {
//左右根
postorder(t->left);
postorder(t->right);
printf("%d ", t->data);
}
}
/*
后序:左右根
根节点只有在左孩子和右孩子都访问以后才能访问
因此,对于任何一个节点,都将其入栈,如果p不存在左孩子和右孩子,直接访问
或者p存在左孩子或者右孩子,但是他的左孩子和右孩子都已经被访问过了
同样的,这个节点也可以直接访问.
如果,上述条件都不满足,就要将这个p的右孩子,左孩子依次入栈
这样就能保证,每次取栈顶元素的时候,左孩子都在右孩子之前被访问,
左右孩子访问之后,根才被访问
*/
void NonRecvPostorder(BitTree* root) {
BitTree* cur;//当前节点==>cur 保存的就是树节点的地址
BitTree* pre = NULL;//前一次访问的节点
LinkStack* pTop = NULL;
BitTreeNode TempNode;//注意我们就是用tempnode来接里面的内容,他是不能参与地址比较的,他的地址一定和我们栈中的地址不一样
pTop = InitLkStack();
pTop = PushLkStack(pTop, root);
while (!IsEmptyLkMazeStack(pTop)) {
cur = pTop->_NodeAddrCopy;//拿到栈中深拷贝获得的节点
//在访问中,由于我们是深拷贝树的节点,因此,pre和cur的地址不一样,我们只能比较器元素内容
//小技巧:利用短路,确保程序的可靠性
if ((cur->left == NULL && cur->right == NULL) ||
(pre != NULL && (pre == cur->left|| pre == cur->right))
) {
printf("%d ", cur->data);
pTop = PopLkStack(pTop, &TempNode);
pre = cur;
}
else {
if (cur->right != NULL)
pTop = PushLkStack(pTop, cur->right);
if (cur->left != NULL)
pTop = PushLkStack(pTop, cur->left);
}
}
}
//求叶子节点:树的遍历是一种非线性遍历,在业务编程中,从实现角度上
//用递归遍历三个方法之一,判断节点属性,就可以完成暴力搜索树
int LeafCount = 0;
void LeafCount_DLR(BitTree* t) {
if (t) {
if(t->left == NULL && t->right == NULL){
printf("%d ", t->data);
LeafCount++;
}
LeafCount_DLR(t->left);
LeafCount_DLR(t->right);
}
}
//因为我们现在能够不重复,不遗漏获取每一个节点,只有前中后序3种方法,所以,我们首先先写出
//先序递归获取树的深度
int hight = 0;//它可以在多个函数之间共享
//前序是根左右,我们把每一个树从root出发的树,可以看出左右两个子树
//无论我们如何遍历,我们前进到每一个节点都是潜在的根节点。
//我们可以认为每到一个新节点,就是到了一个新树,
//如果说,我们对新节点的发现,我们就认为到了一个新层,那么我们累加
//记录就可以了
//我用level作为当前树的高度
//当我用root,0传入的时候,就意味着已经有第一层的计数起始器
//我们用打擂台的思路,用h比对,就可以完成记录
/*
找一组数中的最大值
for(){
if(max < a[i])
max =a[i]
}
*/
int TreeDepth_DLR(BitTree *pNode, int level) {
if (pNode) {
level++;
if (level > hight)
hight = level;//这一就意味伴随着level的不断深入,我们的hight始终获得的是树中最深的层次
printf("%d ", pNode->data);
//从327开始到333行,我们认为这个函数的终止条件完成了
//根据我们前面的观点,递归函数本身就是答案
//因此hight就应该接递归函数的返回值
hight = TreeDepth_DLR(pNode->left, level);
hight = TreeDepth_DLR(pNode->right, level);//因为所有节点的遍历都是跟左右,所以和当前树节点传入的同时,它当前做在的层数我们要传入
}
return hight;
}
//根据前序、中序重建二叉树
BitTree* reConstructBinTree(int pre[], int startPre, int endPre,
int in[], int startIn, int endIn) {
//如果起始的下标大于结束的下标,那么就退出
if (startPre > endPre || startIn > endIn) {
return NULL;
}
//前序找到根节点
BitTree* pNode = (BitTree*)malloc(sizeof(BitTree));
pNode->left = NULL;
pNode->right = NULL;
pNode->data = pre[startPre];//前根当中的首元素一定是当前子树的根节点
for (int i = startIn;i <= endIn;i++) {
if (in[i] == pre[startPre]) {
//i-startIn就是左子树节点的个数
//i -1就是中序遍历左子树的终点
pNode->left = reConstructBinTree(pre, startPre + 1, startPre + i - startIn, in, startIn, i - 1);
//前序右子树的遍历起始值:startPre+i-startIn+1
//中序遍历右子树的起始值:i+1,endIn(i理解成你第几次切刀)
pNode->right = reConstructBinTree(pre, i - startIn + startPre + 1, endPre, in, i + 1, endIn);
}
}
return pNode;
}
//求根到所有叶子节点的路径
BitTree* Paths[10] = { 0 };
void OutPutPath(){
int i = 0;
while (Paths[i] != NULL) {
printf("%d ", Paths[i]->data);
i++;
}
printf("\n");
}
//求路径的函数
void LeavesPath(BitTree* tree, int level) {
if (tree == NULL)
return;
Paths[level] = tree;//这句话就意味着,只要走到这里,这个子树的根就被记录下来
//求路径,意味着找到叶子节点,就输出
if ((tree->left == NULL) && (tree->right == NULL)) {
//当我确定到已经从树根节点root走到了一个叶子节点,那么它以前所有的根节点都存在paths里面
Paths[level + 1] = NULL;//通过level传递了路线信息
OutPutPath();
return;
}
LeavesPath(tree->left, level + 1);
LeavesPath(tree->right, level + 1);
}
//判断两个二叉树是否相等
//提问如果两个二叉树的前序遍历相等,能否说明,这两个树相等?
//答案是否定的,只有这两个树的 A前序=B前序,A中序=B中序才可以。
BOOL isEqualTree(BitTree* t1, BitTree* t2) {
if (t1 == NULL && t2 == NULL)
return TRUE;
if (!t1 || !t2)//t1,t2一个空一个不空,肯定不相同
return FALSE;
if (t1->data == t2->data)
return isEqualTree(t1->left, t2->left) && isEqualTree(t1->right, t2->right);
else
return FALSE;
}
//使用二叉链表建立二叉搜索树:注意,我们目前这个树不支持相同元素
BitTree* insertIntoBinSearchTree(BitTree* root, int node) {
BitTree* newNode;
BitTree* currentNode;
BitTree* parentNode;
newNode = (BitTree*)malloc(sizeof(BitTree));
newNode->data = node;
newNode->left = NULL;
newNode->right = NULL;
if (root == NULL)
return newNode;
else {
currentNode = root;//然后我们对当前节点进行定位
//注意,传入root是根节点,我们要根据根节点,按照左小右大的逻辑找到节点位置
//首先通过while找到新节点的位置
while (currentNode != NULL) {
parentNode = currentNode;
if (currentNode->data > node) {
currentNode = currentNode->left;
}
else {
currentNode = currentNode->right;
}
}
//其次,我们将父节点和子节点做连接
if (parentNode->data > node) {
parentNode->left = newNode;
}
else {
parentNode->right = newNode;
}
}
return root;
}
BitTree* create_LkBinTree(int data[], int length) {
BitTree* root=NULL;
int i;
for (i = 0;i < length;i++) {
root = insertIntoBinSearchTree(root, data[i]);
}
return root;
}
//二叉树镜像:交换两个子树
void SwapTree(BitTree* tree) {
BitTree* pTemp;
pTemp = tree->left;
tree->left = tree->right;
tree->right = pTemp;
}
void ExchangeSubTree(BitTree* tree) {
if (tree == NULL)
return;
else {
SwapTree(tree);
ExchangeSubTree(tree->left);
ExchangeSubTree(tree->right);
}
}
int main(void) {
int arr[17] = { 0,6,3,8,
2,5,7,9,
0,0,4,0,
0,0,0,10,
-999
};
BitTree *root = CreateBinTree(arr);
/*printf("递归形式的先跟遍历\n");
preorder(root);
printf("\n非递归形式的先跟遍历\n");
NonRecrvPreOrder(root);*/
//NonRecvInorder(root);
/*printf("递归形式的后根遍历\n");
postorder(root);
printf("\n非递归形式的后根遍历\n");
NonRecvPostorder(root);*/
//******************BEGIN:树的节点与深度****************
/*LeafCount_DLR(root);
printf("\n当前书总共有%d个叶子节点", LeafCount);*/
//printf("\n当前树有%d层", TreeDepth_DLR(root, 0));
给定一个二叉树,我要分别得到它的左子树的深度和右子树的深度
我们用复用的思想,很容易就得到了内容
注意,虽然复用的思想是好的,当时要注意全局变量的副作用
要对全局变量清零
//hight = 0;
//printf("\n当前树的左子树有%d层\n", TreeDepth_DLR(root->left, 0));
//hight = 0;
//printf("\n当前树的右子树有%d层\n", TreeDepth_DLR(root->right, 0));
当我们在使用递归遍历中,利用全局变量进行传递的时候
函数的复用应当注意全局变量的置0
//******************END 树的节点与深度****************
//************Beign 二叉树重建
//前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
/*int pre[] = { 1,2,4,7,3,5,6,8 };
int in[] = { 4,7,2,1,5,3,8,6 };
BitTree* rootNew;
rootNew = reConstructBinTree(pre, 0, 7, in, 0, 7);
preorder(rootNew);
printf("\n");
inorder(rootNew);*/
//*************End 二叉树重建
//***********Begin 获取根节点到叶子节点
//LeavesPath(root, 0);//0表示层级的传递,只要根据level延伸就能找到每一棵子树的根节点
//************END获取根节点到叶子节点
//***************Begin 判断两颗二叉树是否一致
//如果,输入的数字序列前后不一致,那么使用二叉搜索树建立的也不是同一棵树
/*int arrary[] = { 1,2,3 };
BitTree* tree1 = create_LkBinTree(arrary, 3);
int brr[] = { 1,2,3 };
BitTree* tree2 = create_LkBinTree(brr, 3);
printf("\n");
inorder(tree1);
printf("\n");
inorder(tree2);
printf("\n%d", isEqualTree(tree1, tree2));
*/
//***************End 判断两颗二叉树是否一致
//*************Begin 二叉树镜像:交换一个二叉树的左右子树
int arrary[] = { 5,4,7,2,3,6,8 };
BitTree* tree1 = create_LkBinTree(arrary, 7);
printf("\n");
inorder(tree1);
ExchangeSubTree(tree1);
printf("\n");
inorder(tree1);
//*************End 二叉树镜像:交换一个二叉树的左右子树
getchar();
return 0;
}
二叉树的非递归遍历算法 BitTreeApp
#include
#include
typedef int datatype;
typedef struct node {
datatype data;
struct node *left, *right;
}BitTree;
//*************************Begin*************
//添加辅助栈的结构:主要是用来保存树的节点
//简言之,这个就是用来存树节点的栈
typedef BitTree BitTreeNode;
typedef int BOOL;
#define TRUE 1
#define FALSE 0
typedef struct linknode {
BitTreeNode data;
struct linknode* pNext;
}LinkStack;
LinkStack* InitLkStack(void) {
LinkStack* p = NULL;
p = (LinkStack*)malloc(sizeof(LinkStack));
if (p != NULL)
p->pNext = NULL;
return p;
}//建立一个带头节点的链表作为链栈
BOOL IsEmptyLkMazeStack(LinkStack* top) {
return (top->pNext == NULL);
}
LinkStack* PushLkStack(LinkStack* top, BitTreeNode* elem) {
LinkStack* p=NULL;
//深拷贝的bug修订,如果传入的是空指针,那么不能访问,修订人丁宋涛
if (elem != NULL)
{
p = (LinkStack*)malloc(sizeof(LinkStack));
//todo:我们用新建节点,对传入的二叉树节点做一个深拷贝
p->data.data = elem->data;
p->data.left = elem->left;
p->data.right = elem->right;
p->pNext = top; //p节点尾插入lkStack
top = p;//top栈顶指针上移
}
//我们思考,既然我们允许空指针进入到我们的栈结构,那么我们如何修订
//我们的出栈?
//top为空以为着?
//意味着是否和栈空条件冲突了?
//如果我们让我们的NULL进入栈空间,那么出栈也会造成空指针
//这意味着当前的节点不动
return top;
}
//出栈:pData是传入的一个“临时”空间用来接收出栈的节点信息。
LinkStack* PopLkStack(LinkStack* top, BitTreeNode *pData) {
LinkStack* p;
if (top != NULL) {
//*pData = top->data;
pData->data = top->data.data;
pData->left = top->data.left;
pData->right = top->data.right;
//pData实际上深拷贝了一份节点信息,所以释放栈中节点,不会影响
//节点数据
p = top;
top = p->pNext;
free(p);
}
return top;
}
//*************************End***************
//辅助队列Q,这是用来存关系的
BitTree* Q[16];//这是一个指针数组,它将缓存节点的地址,因为这个地址将以
//left域,或者right域进入二叉链表,它本身不维护i,2i,2i+1的关系
//他的关系通过front,rear来维护
//按照直观的建立,我们首先想到的是层次法
//我们根据层次,来逐一将二叉树建立
//输入的数组是按照完全二叉树的编号规则设立,即
//数组角标反映了节点位置关系(存联系)
//逐个扫描数组,直到所有的节点都存取完毕之后,就结束
//约定,0表示数组当前元素为空,最后一个节点标志是-999
BitTree* CreateBinTree(int arr[]) {
int i = 1;
//只要我们没有扫描完元素,那么这个二叉链表就没有完成
//只要扫描,我们就malloc一个节点,然后把这个节点存入left域或者right域
int front = 1, rear = 0;
BitTree* root = NULL;
BitTree* s;//暂存节点
while (arr[i] != -999) {
s = NULL;
if (arr[i] != 0) {//意味着这个不是空节点,那么我们就要分配空间
s = (BitTree*)malloc(sizeof(BitTree));
s->data = arr[i];//存数值
s->left = NULL;
s->right = NULL;
}
//要让我们新节点入队,进入缓存,等待分配双亲的left域和right域
Q[++rear] = s;
if (rear == 1)
{
root = s;
}
else {
if (s != NULL && Q[front]) {
if (rear % 2 == 0) {
Q[front]->left = s;
}
else {
Q[front]->right = s;
}
}
if (rear % 2 == 1)
front++;
}
i++;
}
return root;
}
//树遍历问题:非线性结构的输出问题:前序,中序,后序
void preorder(BitTree* t) {
if (t) {
//根左右
printf("%d ", t->data);
preorder(t->left);
preorder(t->right);
}
}
void NonRecrvPreOrder(BitTree* root) {
LinkStack* pTop = NULL;
BitTreeNode TempNode;//用来接栈中对应的二叉树节点的
pTop = InitLkStack();
pTop = PushLkStack(pTop, root);
while (!IsEmptyLkMazeStack(pTop)) {
pTop = PopLkStack(pTop, &TempNode);
if (&TempNode != NULL) {
printf("%d ", TempNode.data);
//对右子树压栈
pTop = PushLkStack(pTop, TempNode.right);
pTop = PushLkStack(pTop, TempNode.left);
}
}
}
void inorder(BitTree *t) {
if (t) {
inorder(t->left);
printf("%d ", t->data);
inorder(t->right);
}
}
/*
中序就是左根右,这就意味着,当我们从根节点出发,应当首先走向左孩子
,而根的左孩子,是根的左子树的根节点,因此
又必须,继续访问其左孩子,直到左孩子为空
当这个节点访问之后,按照相同的规则,访问其右子树
我们借助的栈,就应该按照左根右来压栈
对于任意节点p
1 如果其左孩子不为空,则将p入栈,然后将p的左孩子置为当前的p,然后
再对p进行相同的处理
2 若左孩子为空,则取栈顶元素进行出栈操作,访问当前栈顶节点,然后
将当前的p置为栈顶节点的右孩子
3 直到p为NULL为止
*/
void NonRecvInorder(BitTree *root) {
LinkStack* pTop = NULL;
BitTreeNode TempNode;//用来接收栈中的对应的二叉树的节点
pTop = InitLkStack();
BitTree *p = root;
while (p != NULL || !IsEmptyLkMazeStack(pTop)) {
while (p != NULL) {
pTop = PushLkStack(pTop, p);
p = p->left;
}
if (!IsEmptyLkMazeStack(pTop)) {
printf("%d ", pTop->data.data);
pTop = PopLkStack(pTop, &TempNode);//当我们把左子树的左叶子节点走完以后,
//此时栈顶一定是这个左孩子的根,所以根据左根右,这个根要出栈
p = &TempNode;
p = p->right;//走向根的右孩子
}
}
}
void postorder(BitTree* t) {
if (t) {
//左右根
postorder(t->left);
postorder(t->right);
printf("%d ", t->data);
}
}
/*
后序:左右根
根节点只有在左孩子和右孩子都访问以后才能访问
因此,对于任何一个节点,都将其入栈,如果p不存在左孩子和右孩子,直接访问
或者p存在左孩子或者右孩子,但是他的左孩子和右孩子都已经被访问过了
同样的,这个节点也可以直接访问.
如果,上述条件都不满足,就要将这个p的右孩子,左孩子依次入栈
这样就能保证,每次取栈顶元素的时候,左孩子都在右孩子之前被访问,
左右孩子访问之后,根才被访问
*/
void NonRecvPostorder(BitTree* root) {
BitTree* cur;//当前节点
BitTree* pre = NULL;//前一次访问的节点
LinkStack* pTop = NULL;
BitTreeNode TempNode;
pTop = InitLkStack();
pTop = PushLkStack(pTop, root);
while (!IsEmptyLkMazeStack(pTop)) {
cur = &pTop->data;//拿到栈中深拷贝获得的节点
//在访问中,由于我们是深拷贝树的节点,因此,pre和cur的地址不一样,我们只能比较器元素内容
//小技巧:利用短路,确保程序的可靠性
if ((cur->left == NULL && cur->right == NULL) ||
(pre != NULL && ((cur->left && pre->data == cur->left->data) || (cur->right && pre->data == cur->right->data)))
) {
printf("%d ", cur->data);
pTop = PopLkStack(pTop, &TempNode);
pre = &TempNode;
}
else {
if (cur->right != NULL)
pTop = PushLkStack(pTop, cur->right);
if (cur->left != NULL)
pTop = PushLkStack(pTop, cur->left);
}
}
}
int main(void) {
int arr[17] = { 0,6,3,8,
2,5,7,9,
0,0,4,0,
0,0,0,10,
-999
};
BitTree *root = CreateBinTree(arr);
/*printf("递归形式的先跟遍历\n");
preorder(root);
printf("\n非递归形式的先跟遍历\n");
NonRecrvPreOrder(root);*/
//NonRecvInorder(root);
printf("递归形式的后根遍历\n");
postorder(root);
printf("\n非递归形式的后根遍历\n");
NonRecvPostorder(root);
getchar();
return 0;
}
HuffmanTree
#include
#include
typedef int ElemType;
typedef struct BTreeNode {
ElemType data;
struct BTreeNode* left, *right;
}BTreeNode;
//根据传入的数组a,其中n个元素作为其权值,构建一颗哈夫曼树,返回根节点
BTreeNode* CreateHuffman(ElemType a[], int n) {
int i, j;
BTreeNode ** b, *q;
b = (BTreeNode **)malloc(n * sizeof(BTreeNode));
for (i = 0;i < n;i++) {
b[i] = (BTreeNode*)malloc(sizeof(BTreeNode));
b[i]->data = a[i];
b[i]->left = b[i]->right = NULL;
}
//以上通过构建连续存储空间,拿到了需要存储的n个huffman节点,然后根据
//逐个将节点加入的过程,完成哈夫曼树
for (i = 1;i < n;i++) {
//k1:森林中具有最小权值的树根节点的下标,k2为次小下标
int k1 = -1, k2;
//让k1指向第一棵树,k2指向第二棵
for (j = 0;j < n;j++) {
if (b[j] != NULL && k1 == -1) {
k1 = j;
continue;
}
if (b[j] != NULL) {
k2 = j;
break;
}
}
//从当前森林中求出最小权值树、次小的
for (j = k2;j < n;j++) {
if (b[j] != NULL) {
if (b[j]->data < b[k1]->data) {
k2 = k1;
k1 = j;
}
else {
if (b[j]->data < b[k2]->data)
k2 = j;
}
}
}
//由k1,k2拼树,q指向树根节点
q =(BTreeNode*) malloc(sizeof(BTreeNode));
q->data = b[k1]->data + b[k2]->data;
q->left = b[k1];
q->right = b[k2];
b[k1] = q;//将新树节点放回原来b申请的数组k1的位置
b[k2] = NULL;
}
free(b);
return q;//返回整个Huffman树的根节点
}
//求Huffman 树的路径
ElemType WeightPathLength(BTreeNode* FBT,int len){
if (FBT == NULL)
return 0;
else
{
if (FBT->left == NULL && FBT->right == NULL) {
//到叶子节点
return FBT->data * len;
}
else {
//非叶子节点,递归,返回左右子树带权路径长度的和,len要递增
return WeightPathLength(FBT->left, len + 1) + WeightPathLength(FBT->right, len + 1);
}
}
}
//求Huffman编码
void HuffmanCoding(BTreeNode* FBT, int len) {
static int a[10];//定义一个静态数组,保存每一个叶子节点的编码
if (FBT != NULL) {
if (FBT->left == NULL && FBT->right == NULL) {
//进入到了叶子节点
int i;
printf("节点权值为%d的编码是:", FBT->data);
for (i = 0;i < len;i++) {
printf("%d", a[i]);
}
printf("\n");
}
else {
//访问到的是非叶子节点,那么就要按照分支中,左0,右1的方式递归调用,存入a数组中
a[len] = 0;
HuffmanCoding(FBT->left, len + 1);
a[len] = 1;
HuffmanCoding(FBT->right, len + 1);
}
}
}
int main() {
int n = 6, i;
BTreeNode* fbt;
int arr[] = { 3,9,5,12,6,15 };
fbt = CreateHuffman(arr, n);
printf("带权路径长度%d\n", WeightPathLength(fbt, 0));
HuffmanCoding(fbt, 0);
getchar();
return 0;
}