数据结构(新手向)顺序,链表,栈,队列,二叉树的定义和操作,图的构造与遍历,查找算法,排序算法

一-顺序表

运行结果:

输入6个整型数据:
1
2
3
4
5
6
您输入的数据为:1 2 3 4 5 6

选择进行的操作:1.插入数据    2.删除数据    3.退出程序
1
输入插入的位置:2
输入数据:100
插入成功
1   100   2   3   4   5   6
选择进行的操作:1.插入数据    2.删除数据    3.退出程序
1
输入插入的位置:10
输入数据:100
插入失败
1   100   2   3   4   5   6
选择进行的操作:1.插入数据    2.删除数据    3.退出程序
2
输入删除的位置:4
删除成功
1   100   2   4   5   6
选择进行的操作:1.插入数据    2.删除数据    3.退出程序
3
退出程序
请按任意键继续. . .

源代码:

#include <stdio.h>
#include <stdlib.h>

#define MaxSize 6
#define LIST_TNCREMENT 2
typedef int ElenType;

typedef struct
{
    ElenType *data; // 每个元素的数据类型
    int length;     // 一共有多少个元素
    int listsize;   // 整个顺序表的长度
} SqList;

// 初始化一个顺序表

int initList(SqList *L)
{
    // 1.申请一个空间
    L->data = (ElenType *)malloc(MaxSize * sizeof(ElenType));

    // 2.判断是否拿到了空间内存
    if (!L->data)
        exit(-1);

    // 3.如果拿到了内存空间,就需要初始化顺序表
    L->length = 0;
    L->listsize = MaxSize;

    return 1;
}

// 放入数据
void data_ttt(SqList *L)
{
    int a;
    printf("输入6个整型数据:\n");
    for (int i = 0; i < 6; i++)
    {
        scanf("%d", &a);

        L->data[i] = a;
        L->length++;
    }
    printf("您输入的数据为:%d %d %d %d %d %d\n", L->data[0], L->data[1], L->data[2], L->data[3], L->data[4], L->data[5]);
}

// 扩大数组的长度+2
int extantList(SqList *L)
{
    // 重新申请内存
    ElenType *p = (ElenType *)realloc(L->data, (L->listsize + LIST_TNCREMENT) * sizeof(ElenType));
    // 判断是否申请到了内存
    if (!p)
        exit(-1);
    // 如果申请到了内存就要更新顺序表的信息
    L->data = p;
    L->listsize += LIST_TNCREMENT;
    return 1;
}

// 插入数据
int insert(SqList *L)
{
    int i, j;
    // int a;
    printf("输入插入的位置:");
    scanf("%d", &i);
    printf("输入数据:");
    scanf("%d", &j);
    if ((i < 1) || (i > L->length + 1))
    {
        printf("插入失败\n");
        return 1;
    }

    // 判断表是否有空余空间,如果没有扩大表长
    if (L->length >= L->listsize)
        extantList(L);

    for (int a = L->length - 1; a >= i - 1; a--)
        L->data[a + 1] = L->data[a];
    L->data[i - 1] = j;
    L->length++;
    printf("插入成功\n");
    return 0;
}
// 删除数据
int deletedata(SqList *L)
{
    int i, j;
    printf("输入删除的位置:");
    scanf("%d", &i);
    if ((i < 1) || (i > L->length))
    {
        printf("删除失败\n");
        return 1;
    }
    for (j = i; j <= L->length - 1; j++)
        L->data[j - 1] = L->data[j];
    L->length--;
    printf("删除成功\n");
    return 0;
}

// 遍历顺序表
void findAllList(SqList *L)
{
    int i;
    for (i = 0; i < L->length; i++)
    {
        printf("%d   ", L->data[i]);
    }
}

// 销毁顺序表
int deleteList(SqList *L)
{
    // 判断顺序表是否存在
    if (L->data == NULL)
        return 0;

    // 如果存在,则释放对应的内存
    free(L->data);
    // 释放内存之后,要恢复表的初始值
    L->length = 0;
    L->listsize = 0;

    return 1;
}

int main()
{
    int a;
    int b;
    SqList L;
    initList(&L); // 初始化
    data_ttt(&L); // 放入数据
    while (1)
    {
        printf("\n");
        printf("选择进行的操作:");
        printf("1.插入数据    2.删除数据    3.退出程序\n");
        scanf("%d", &a);
        switch (a)
        {
        case 1:
            insert(&L);      // 插入数据
            findAllList(&L); // 遍历顺序表
            break;
        case 2:
            deletedata(&L);
            findAllList(&L); // 遍历顺序表
            break;
        case 3:
            // 退出循环
            printf("退出程序\n");
            deleteList(&L); // 释放顺序表的内存
            system("pause");
            exit(-1);
        default:
            printf("无效的选项,请重新选择\n");
        }
    }

    // 释放顺序表的空间
    deleteList(&L);
    system("pause");
    return 0;
}

二-单链表

运行结果:

输入5个单链表的数据:
1
2
3
4
5
成功创建链表:
  1  2  3  4  5

*****1.单链表的插入******
*****2.单链表的删除******
*****3.单链表的查找******
*****4.        退出******

输入选项:
1
输入插入数据的位置:2
插入成功!输入插入数据的值:6
插入后的链表为:  1  6  2  3  4  5

*****1.单链表的插入******
*****2.单链表的删除******
*****3.单链表的查找******
*****4.        退出******

输入选项:1
输入插入数据的位置:9
插入失败!请重新输入
*****1.单链表的插入******
*****2.单链表的删除******
*****3.单链表的查找******
*****4.        退出******

输入选项:2
输入删除数据的位置:6
  1  6  2  3  4

*****1.单链表的插入******
*****2.单链表的删除******
*****3.单链表的查找******
*****4.        退出******

输入选项:3
输入查找数据的位置:4
查找的元素为:3

*****1.单链表的插入******
*****2.单链表的删除******
*****3.单链表的查找******
*****4.        退出******

输入选项:0
无效的选项,请重新选择

*****1.单链表的插入******
*****2.单链表的删除******
*****3.单链表的查找******
*****4.        退出******

输入选项:4
退出程序
请按任意键继续. . .

源代码:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>

typedef int ElemType;
// 定义链表节点结构体
typedef struct Node
{
    ElemType data;     // 数据域
    struct Node *next; // 指针域,指向下一个节点
} Node, *LinkedList;

// 建立菜单
void menu()
{
    printf("*****1.单链表的插入******\n");
    printf("*****2.单链表的删除******\n");
    printf("*****3.单链表的查找******\n");
    printf("*****4.        退出******\n");
}

// 初始化链表函数,将链表头指针设为NULL
LinkedList LinkListInit()
{
    Node *L;
    L = (Node *)malloc(sizeof(Node));
    if (L == NULL)
    {
        printf("申请内存空间失败");
    }
    L->next = NULL; // 将链表头指针设为NULL
    return L;       // 返回初始化成功
}

// 单链表的建立(头插法)
LinkedList ListCreatH()
{
    Node *L;
    L = (Node *)malloc(sizeof(Node));
    L->next = NULL;
    int i = 0;
    ElemType x;
    while (i < 10)
    {
        Node *p;
        p = (Node *)malloc(sizeof(Node));
        scanf("%d", &x);
        p->data = x;
        p->next = L->next;
        L->next = p;
        ;
        i++;
    }
    return L;
}

LinkedList List_creatT(LinkedList &L)
{
    Node *list;
    list = (Node *)malloc(sizeof(Node));
    list->next = NULL;
    L = list;
    Node *r;
    r = L;
    int i = 0;
    for (i = 0; i < 5; i++)
    {
        Node *p;
        p = (Node *)malloc(sizeof(Node));
        scanf("%d", &p->data);
        r->next = p;
        r = p;
    }
    r->next = NULL;
    return L;
}

// 在链表中插入元素的函数,将元素e插入到链表的第i个位置
bool ListInsert(LinkedList &L, int i, int x)
{
    if (i < 1) // 如果插入位置小于1,插入失败,返回false
        return false;
    Node *p;   // 定义指针p,用于遍历链表
    int j = 0; // 定义计数器j,用于记录当前遍历到的位置
    p = L;     // 将指针p指向链表头指针
    while (p != NULL && j < i - 1)
    {                  // 遍历链表,直到找到第i-1个位置或到达链表尾部
        p = p->next;   // 将指针p指向下一个节点
        j++;           // 计数器j加1
        if (p == NULL) // 如果到达链表尾部,插入失败,返回false
            return false;
    }
    Node *s = (Node *)malloc(sizeof(Node)); // 分配内存空间,创建新节点s
    s->data = x;                            // 将新节点的数据域赋值为e
    s->next = p->next;                      // 将新节点的指针域指向原第i个节点的下一个节点
    p->next = s;                            // 将原第i个节点的指针域指向新节点s
    return true;                            // 插入成功,返回true
}

// 删除链表中第i个元素,并将该元素的值赋给e
bool ListDelete(LinkedList &L, int i, ElemType &x)
{
    // 如果i小于1,返回false
    if (i < 1)
        return false;
    // 初始化指针p指向头结点
    Node *p = L;
    // 初始化计数器j为0
    int j = 0;
    // 循环找到第i-1个结点
    while (p != NULL && j < i - 1)
    {
        p = p->next;
        j++;
    }
    // 如果p为NULL或者p->next为NULL,说明i值不合法,返回false
    if (p == NULL || p->next == NULL)
        return false;
    // 初始化指针q指向被删除结点的下一个结点
    Node *q = p->next;
    // 将被删除结点的值为赋给x
    x = q->data;
    // 将p的next指向被删除结点的下一个结点
    p->next = q->next;
    // 释放被删除结点的内存空间
    free(q);
    // 删除成功,返回true
    return true;
}


// 按位查找,返回第 i个元素(带头结点)
Node *SetElem(LinkedList L, int i)
{
    if (i <= 0)
    { // 如果i小于等于0,返回NULL
        return NULL;
    }
    Node *p = L; // 指针p指向当前扫描到的结点
    int j = 0;   // 当前p指向的是第几个结点
    while (p != NULL && j < i)
    { // 循环找到第i个结点
        p = p->next;
        j++;
    }
    if (j == i)
    {             // 如果找到了第i个结点
        return p; // 返回该结点
    }
    else
    {
        return NULL; // 如果没有找到第i个结点,返回NULL
    }
}

// 链表的销毁
void freeLink(Node *head)
{
    // 判断链表是否为空,如果为空 ,则返回
    if (head == NULL)
        return;
    // 如果非空,则逐个结点释放
    Node *p, *q;
    p = head;
    while (p->next != NULL)
    {
        q = p->next;
        p->next = q->next;
        free(q);
    }
    free(head);
}

int main()
{
    LinkedList List, start;
    printf("输入5个单链表的数据:\n");
    List = List_creatT(List);
    printf("成功创建链表:\n");
    for (start = List->next; start != NULL; start = start->next)
    {
        printf("  %d", start->data);
    }
    printf("\n");
    int i, option;
    int x;

    while (1)
    {
        printf("\n");
        menu();
        printf("\n");
        printf("输入选项:");
        scanf("%d", &option);
        switch (option)
        {
        case 1:
        {
            printf("输入插入数据的位置:");
            scanf("%d", &i);
            if (i > 0 && i < 6)
            {
                printf("插入成功!");
            }
            else
            {
                printf("插入失败!请重新输入");
                break;
            }
            printf("输入插入数据的值:");
            scanf("%d", &x);
            ListInsert(List, i, x);
            printf("插入后的链表为:");
            for (start = List->next; start != NULL; start = start->next)
            {
                printf("  %d", start->data);
            }
            printf("\n");
            break;
        }

        case 2:
        {
            printf("输入删除数据的位置:");
            scanf("%d", &i);
            ElemType e;

            ListDelete(List, i, e);

            for (start = List->next; start != NULL; start = start->next)
            {
                printf("  %d", start->data);
            }
            printf("\n");
            break;
        }

        case 3:
        {
            int i;
            printf("输入查找数据的位置:");
            scanf("%d", &i);

            Node *result = SetElem(List, i);

            if (result != NULL)
            {
                printf("查找的元素为:%d\n", result->data);
            }
            else
            {
                printf("未找到元素或输入位置无效。\n");
            }
            break;
        }

        case 4:
        {
            printf("退出程序\n");
            freeLink(List);
            return 0;
        }
        default:
            printf("无效的选项,请重新选择\n");
        }
    }
    system("pause");
    return 0;
}

三-顺序栈

运行结果:

******************
** 1.入栈
** 2.求栈顶元素
** 3.出栈
** 4.清空栈
** 5.遍历栈
** 0.退出程序
*****************

1
请输入入栈元素个数:8
请依次输入元素:
1
2
3
4
5
6
7
8
添加成功
顺序栈的元素如下:(从栈底到栈顶)

  1  2  3  4  5  6  7  8

栈的长度为:8

******************
** 1.入栈
** 2.求栈顶元素
** 3.出栈
** 4.清空栈
** 5.遍历栈
** 0.退出程序
*****************

2
栈顶元素为8

******************
** 1.入栈
** 2.求栈顶元素
** 3.出栈
** 4.清空栈
** 5.遍历栈
** 0.退出程序
*****************

3
请输入出栈元素个数:4
成功弹出元素:8

成功弹出元素:7

成功弹出元素:6

成功弹出元素:5

顺序栈的元素如下:(从栈底到栈顶)

  1  2  3  4

栈的长度为:4

******************
** 1.入栈
** 2.求栈顶元素
** 3.出栈
** 4.清空栈
** 5.遍历栈
** 0.退出程序
*****************

5
顺序栈的元素如下:(从栈底到栈顶)

  1  2  3  4

栈的长度为:4

******************
** 1.入栈
** 2.求栈顶元素
** 3.出栈
** 4.清空栈
** 5.遍历栈
** 0.退出程序
*****************

4
成功清空

******************
** 1.入栈
** 2.求栈顶元素
** 3.出栈
** 4.清空栈
** 5.遍历栈
** 0.退出程序
*****************

5
顺序栈为空


栈的长度为:0

******************
** 1.入栈
** 2.求栈顶元素
** 3.出栈
** 4.清空栈
** 5.遍历栈
** 0.退出程序
*****************

0
成功退出!

成功销毁

 请按任意键继续. . .

源代码:

// 用C实现顺序栈
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 100
typedef struct
{
	int *top;
	int *base;
	int stackSize;

} Stack;

// 初始化栈
void initStack(Stack &s)
{
	s.base = new int[MaxSize]; // 动态分配内存
	if (!s.base)
		exit(0);
	s.top = s.base;
	s.stackSize = MaxSize;
}

// 判断栈是否为空
int isEmpty(Stack s)
{
	if (s.base == s.top)
		return 1;
	return 0;
}
// 求栈的长度
int stackLength(Stack s)
{
	return s.top - s.base;
}

// 遍历栈
void displayStack(Stack s)

{
	int length = stackLength(s);
	if (length > 0)
	{
		printf("顺序栈的元素如下:(从栈底到栈顶)\n\n");
		for (int i = 0; i < length; i++)
		{
			printf("  %d", s.base[i]);
		}
		printf("\n");
	}
	else
	{
		printf("顺序栈为空\n\n");
	}
	printf("\n");
	printf("栈的长度为:%d\n\n", stackLength(s));
}

// 清空栈
void CleanStack(Stack &s)
{
	if (s.base)
	{
		s.base = s.top;
		printf("成功清空\n\n");
	}
	else
	{
		printf("栈已被销毁 ,无需清空\n\n");
	}
}

// 销毁栈
void DestoryStack(Stack &s)
{
	if (s.base != NULL)
	{

		s.stackSize = 0;
		s.base = NULL;
		s.top = NULL;
		delete s.base;
		printf("成功销毁\n\n ");
	}
	else
	{
		printf("栈已被销毁 ,无需销毁\n\n");
	}
}

// 入栈
void push(Stack &s, int e)
{
	int n;
	printf("请输入入栈元素个数:");
	scanf("%d", &n);
	printf("请依次输入元素:\n");
	if ((s.top - s.base) == s.stackSize)
	{
		printf("栈满了,无法添加新元素!\n\n");
	}
	else
	{
		// 用for循环实现连续入栈
		for (int i = 0; i < n; i++)
		{
			scanf("%d", &e);
			*s.top++ = e;
		}
		printf("添加成功\n");
		displayStack(s);
	}
}

// 出栈
int pop(Stack &s, int &e)
{

	int n;
	printf("请输入出栈元素个数:");
	scanf("%d", &n);
	if (isEmpty(s))
	{
		printf("栈为空,无法弹出!\n\n");
		return -1;
	}
	else
	{
		// 使用for循环连续出栈
		for (int i = 0; i < n; i++)
		{
			e = *(s.top);
			s.top--;
			printf("成功弹出元素:%d\n\n", *(s.top));
		}
		displayStack(s);
		return 1;
	}
	return 1;
}

// 求栈顶元素
int top(Stack s)
{
	if (isEmpty(s))
	{
		printf("栈为空,没有栈顶元素!\n\n");
		return 0;
	}
	else
	{
		s.top--;
		return *(s.top);
	}
}

// 菜单
void menu()
{
	printf("******************\n");
	printf("** 1.入栈         \n");
	printf("** 2.求栈顶元素    \n");
	printf("** 3.出栈         \n");
	printf("** 4.清空栈        \n");
	printf("** 5.遍历栈        \n");
	printf("** 0.退出程序      \n");
	printf("*****************\n\n");
}

int main()
{
	char choice;
	Stack s;
	initStack(s); // 初始化栈
	int e1, e2;

	while (1)
	{
		menu();
		scanf("%d", &choice);
		switch (choice)
		{

		case 1:
			push(s, e1);
			break;

		case 2:
			if (top(s) != -1)
				printf("栈顶元素为%d\n\n", top(s));

			break;
		case 3:
			pop(s, e2);

			break;
		case 4:
			CleanStack(s);

			break;
		case 5: // 遍历栈
			displayStack(s);

			break;
		case 0:
			printf("成功退出!\n\n");
			DestoryStack(s); // 销毁栈
			exit(0);
			break;
		default:
			printf("输入有误,请重新输入\n\n");
			break;
		}
	}
	system("pause");
	return 0;
}

四-顺序循环队列

运行结果:

******************
** 1.入队
** 2.取队头元素
** 3.出队
** 4.清空队列
** 0.退出程序
*****************

请选择:
1
请输入入队元素个数:8
请依次输入元素:
1
2
3
4
5
6
7
8
添加成功
 1  2  3  4  5  6  7  8
队列的长度为:8

请选择:
2
队头元素为:1
请选择:
3
请输入出队元素个数:4
成功弹出元素:1
成功弹出元素:2
成功弹出元素:3
成功弹出元素:4
 5  6  7  8
队列的长度为:4

请选择:
4
清空队列
队列为空!
请选择:
0
成功退出!

请按任意键继续. . .

源代码:

// 用c实现顺序队列
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100 // 队列可能达到的最大长度
typedef int QElemType;
typedef struct
{
    QElemType *base;
    // QElemType data[MAXSIZE];
    int front;
    int rear;
} SqQueue;

// 循环队列的初始化
void InitQueue(SqQueue &Q)
{
    Q.base = new int[MAXSIZE];
    if (!Q.base)
    {
        printf("内存分配失败!\n");
        exit(1);
    }
    Q.front = Q.rear = 0;
}

// 判断队列是否为空
bool QueueEmpty(SqQueue Q)
{
    if (Q.front == Q.rear)
        return true;
    else
        return false;
}

// 求队列的长度
int QueueLength(SqQueue Q)
{
    // 返回Q的元素个数,即队列的长度
    return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}

// 遍历队列
void QueueTraverse(SqQueue Q)
{
    int i;
    if (QueueEmpty(Q))
    {
        printf("队列为空!\n");
        return;
    }
    i = Q.front;
    while (i != Q.rear)
    {
        printf(" %d ", Q.base[i]);
        i = (i + 1) % MAXSIZE;
    }
    printf("\n");
    printf("队列的长度为:%d\n\n", QueueLength(Q));
}

// 清空队列

void eClearQueu(SqQueue &Q)
{
    Q.front = Q.rear = 0;
    QueueTraverse(Q);
}

// 销毁队列
void DestroyQueue(SqQueue &Q)
{

    free(Q.base);
    Q.base = NULL;
    Q.front = Q.rear = 0;
}

// 循环队列的入队
void EnQueue(SqQueue &Q, QElemType e)
{
    int n;
    printf("请输入入队元素个数:");
    scanf("%d", &n);
    printf("请依次输入元素:\n");
    if ((Q.rear + 1) % MAXSIZE == Q.front) // 若尾指针在循环意义上加1后等于头指针,表队列满
    {
        printf("队列已满!\n");
        return;
    }
    else
    {
        // 用for循环实现连续入队
        for (int i = 0; i < n; i++)
        {

            scanf("%d", &e);
            Q.base[Q.rear] = e;              // 新元素插入队尾
            Q.rear = (Q.rear + 1) % MAXSIZE; // 队尾指针加1
        }
        printf("添加成功\n");
        QueueTraverse(Q);
        return;
    }
}

// 循环队列的出队
void DeQueue(SqQueue &Q, QElemType &e)
{
    int n;
    printf("请输入出队元素个数:");
    scanf("%d", &n);
    if (Q.front == Q.rear)
    {
        printf("队列已空!\n");
        exit(1);
    }
    else
    {
        // 使用for循环连续出栈
        for (int i = 0; i < n; i++)
        {
            e = Q.base[Q.front];
            Q.front = (Q.front + 1) % MAXSIZE;
            printf("成功弹出元素:%d\n", e);
        }
        QueueTraverse(Q);
        return;
    }
}

// 取队头元素
QElemType GetHead(SqQueue Q)
{
    if (Q.front != Q.rear)
    {
        return Q.base[Q.front]; // 返回队列头元素的值,队列头指针不变
    }
    else
    {
        printf("队列为空!\n");
        exit(1);
    }
}

// 菜单
void menu()
{
    printf("******************\n");
    printf("** 1.入队         \n");
    printf("** 2.取队头元素    \n");
    printf("** 3.出队         \n");
    printf("** 4.清空队列        \n");
    printf("** 0.退出程序      \n");
    printf("*****************\n\n");
}

int main()
{
    char choice;
    int e;
    SqQueue Q;
    menu();
    InitQueue(Q);
    while (1)
    {
        printf("请选择:\n");
        scanf("%d", &choice);
        switch (choice)
        {

        case 1:
            EnQueue(Q, e);
            break;

        case 2:
            printf("队头元素为:%d\n", GetHead(Q));
            break;
        case 3:
            // 出队
            DeQueue(Q, e);
            break;
        case 4:
            printf("清空队列\n");
            eClearQueu(Q);
            break;
        case 0:
            printf("成功退出!\n\n");
            // 销毁队列
            DestroyQueue(Q);
            system("pause");
            exit(-1);
            // return 0;

            break;
        default:
            printf("输入有误,请重新输入\n\n");
            break;
        }
    }
    system("pause");
    return 0;
}

五-先序遍历建立二叉链表及前中后序遍历

 运行结果:

********************************
*****    1.先序遍历建立二叉链表
*****    2.遍历函数
*****    3.显示二叉树信息
*****    4.退出
********************************
请选择:1
是否有左子树或者右子树,如果有,输入1 ,否则输入0
1
请输入结点的三个值
1
1
1
请输入结点标记:
A
是否有左子树或者右子树,如果有,输入1 ,否则输入0
1
请输入结点的三个值
2
2
2
请输入结点标记:
B
是否有左子树或者右子树,如果有,输入1 ,否则输入0
0
是否有左子树或者右子树,如果有,输入1 ,否则输入0
0
是否有左子树或者右子树,如果有,输入1 ,否则输入0
1
请输入结点的三个值
3
3
3
请输入结点标记:
C
是否有左子树或者右子树,如果有,输入1 ,否则输入0
0
是否有左子树或者右子树,如果有,输入1 ,否则输入0
0
创建成功!!!

********************************
*****    1.先序遍历建立二叉链表
*****    2.遍历函数
*****    3.显示二叉树信息
*****    4.退出
********************************
请选择:2
请选择遍历方式:
1.先序遍历
2.中序遍历
3.后序遍历

1
先序遍历结果:
A结点
一值:1    ,二值:1    ,三值:1.000000
B结点
一值:2    ,二值:2    ,三值:2.000000
C结点
一值:3    ,二值:3    ,三值:3.000000

********************************
*****    1.先序遍历建立二叉链表
*****    2.遍历函数
*****    3.显示二叉树信息
*****    4.退出
********************************
请选择:2
请选择遍历方式:
1.先序遍历
2.中序遍历
3.后序遍历

2
中序遍历结果:
B结点
一值:2    ,二值:2    ,三值:2.000000
A结点
一值:1    ,二值:1    ,三值:1.000000
C结点
一值:3    ,二值:3    ,三值:3.000000

********************************
*****    1.先序遍历建立二叉链表
*****    2.遍历函数
*****    3.显示二叉树信息
*****    4.退出
********************************
请选择:2
请选择遍历方式:
1.先序遍历
2.中序遍历
3.后序遍历

3
后序遍历结果:
B结点
一值:2    ,二值:2    ,三值:2.000000
C结点
一值:3    ,二值:3    ,三值:3.000000
A结点
一值:1    ,二值:1    ,三值:1.000000

********************************
*****    1.先序遍历建立二叉链表
*****    2.遍历函数
*****    3.显示二叉树信息
*****    4.退出
********************************
请选择:3

二叉树结点个数:3
二叉树左子树结点个数:1
二叉树右子树结点个数:1
二叉树叶子结点个数:2
二叉树的深度:2
二叉树度为1的结点个数:0

********************************
*****    1.先序遍历建立二叉链表
*****    2.遍历函数
*****    3.显示二叉树信息
*****    4.退出
********************************
请选择:4
二叉链表已销毁!谢谢使用!请按任意键继续. . .

源代码:

// 二叉树的实现

#include <stdio.h>
#include <stdlib.h>

// 链式存储
typedef struct
{
    int dataA;
    int dataB;
    double dataC;
} Student; // 结点类型

typedef struct node
{
    Student stu;                  // 数据域
    char ch;                      // 标记
    struct node *lchild, *rchild; // 指针域
} NOOE;                           // 结点类型

// 为结点的数据域输入值
void inputValue(Student *stu)
{
    if (!stu)
        return;
    printf("请输入结点的三个值\n");
    scanf("%d%d%lf", &stu->dataA, &stu->dataB, &stu->dataC);
}

// 创建结点
NOOE *createNode(Student *stu)
{
    // 需要判断一下是否有stu
    if (!stu)
        return NULL;
    // 创建结点
    NOOE *newNode = (NOOE *)malloc(sizeof(NOOE));
    // 判断是否拿到内存
    if (!newNode)
        return NULL;
    // 将输入的参数赋值给新拿到的内存空间
    newNode->stu = *stu;
    printf("请输入结点标记:\n");
    fflush(stdin); // standard input
    scanf("%c", &newNode->ch);
    newNode->lchild = newNode->rchild = NULL;
    // 返回创建好的结点
    return newNode;
}

// 初始化一个二叉树
NOOE *initTree(NOOE *root)
{
    // 1。设置一个标记,告诉程序是否继续添加结点
    int flag = 0;
    printf("是否有左子树或者右子树,如果有,输入1 ,否则输入0\n");
    scanf("%d", &flag);
    // 2,如果继续添加结点,需要给结点初始化
    if (flag == 1)
    {
        Student stu;
        inputValue(&stu);
        root = createNode(&stu);
        // 3,继续左子树,继续添加右子树
        root->lchild = initTree(root->lchild);
        root->rchild = initTree(root->rchild); // 先序遍历
    }

    // 4,要返回创建的子树
    return root;
}

// 销毁二叉树
void destroyTree(NOOE *root)
{
    // 1,如果根结点为空,直接返回
    if (root == NULL)
        return;
    // 2,如果根结点不为空,则需要销毁根结点
    destroyTree(root->lchild);
    destroyTree(root->rchild);
    // 3,销毁根结点
    free(root);
}

// 打印结点信息
void outputValue(Student *stu)
{
    if (stu == NULL)
        return;
    printf("一值:%-5d,二值:%-5d,三值:%-5lf\n", stu->dataA, stu->dataB, stu->dataC);
}

// 遍历二叉树
// 先序遍历
void preOrder(NOOE *tree)
{
    if (tree != NULL)
    {
        printf("%c结点\n", tree->ch);
        outputValue(&tree->stu);
        
        preOrder(tree->lchild);
        preOrder(tree->rchild);
    }
}

// 中序遍历
void inOrder(NOOE *tree)
{
    if (tree != NULL)
    {
        inOrder(tree->lchild);
        printf("%c结点\n", tree->ch);
        outputValue(&tree->stu);
        inOrder(tree->rchild);
    }
}
// 后序遍历
void postOrder(NOOE *tree)
{
    if (tree != NULL)
    {
        postOrder(tree->lchild);
        postOrder(tree->rchild);
        printf("%c结点\n", tree->ch);
        outputValue(&tree->stu);
    }
}
// 统计二叉树中的结点个数
int countTreeNode(NOOE *tree)
{
    if (tree == NULL)
        return 0;
    return countTreeNode(tree->lchild) + countTreeNode(tree->rchild) + 1;
}
// 统计叶子结点个数
int countTreeLeaf(NOOE *tree)
{
    if (tree == NULL)
        return 0;
    if (tree->lchild == NULL && tree->rchild == NULL)
        return 1;
    return countTreeLeaf(tree->lchild) + countTreeLeaf(tree->rchild);
}
// 计算二叉树的深度
int countTreeDepth(NOOE *tree)
{
    if (tree == NULL)
        return 0;
    int lDepth = countTreeDepth(tree->lchild);
    int rDepth = countTreeDepth(tree->rchild);
    return lDepth > rDepth ? lDepth + 1 : rDepth + 1;
}
// 统计二叉树的度为1的结点个数
int countTreeDegree1(NOOE *tree)
{
    if (tree == NULL)
        return 0;
    if (tree->lchild == NULL && tree->rchild == NULL)
        return 0;
    if (tree->lchild == NULL)
        return 1 + countTreeDegree1(tree->rchild);
    if (tree->rchild == NULL)
        return 1 + countTreeDegree1(tree->lchild);
    return countTreeDegree1(tree->lchild) + countTreeDegree1(tree->rchild);
}

// 显示二叉树信息函数
void showTreeInfo(NOOE *tree)
{
    printf("\n");
    int num = countTreeNode(tree);
    printf("二叉树结点个数:%d\n", num);
    printf("二叉树左子树结点个数:%d\n", countTreeNode(tree->lchild));
    printf("二叉树右子树结点个数:%d\n", countTreeNode(tree->rchild));
    printf("二叉树叶子结点个数:%d\n", countTreeLeaf(tree));
    printf("二叉树的深度:%d\n", countTreeDepth(tree));
    printf("二叉树度为1的结点个数:%d\n", countTreeDegree1(tree));
    printf("\n");
}
// 综合遍历函数
void showTree(NOOE *tree)
{
    // 用户通过选择遍历方式打印二叉树
    int choose;
    printf("请选择遍历方式:\n");
    printf("1.先序遍历\n");
    printf("2.中序遍历\n");
    printf("3.后序遍历\n");
    printf("\n");
    scanf("%d", &choose);
    switch (choose)
    {
    case 1:
        printf("先序遍历结果:\n");
        preOrder(tree);
        printf("\n");
        break;
    case 2:
        printf("中序遍历结果:\n");
        inOrder(tree);
        printf("\n");
        break;
    case 3:
        printf("后序遍历结果:\n");
        postOrder(tree);
        printf("\n");
        break;
    }
}

// 菜单函数
void menu()
{
    printf("********************************\n");
    printf("*****    1.先序遍历建立二叉链表   \n");
    printf("*****    2.遍历函数              \n");
    printf("*****    3.显示二叉树信息        \n");
    printf("*****    4.退出                 \n");
    printf("********************************\n");
}

int main()
{
    NOOE *tree = NULL;
   
    while (1)
    {
        menu();
        int choose;
        printf("请选择:");
        scanf("%d", &choose);
        switch (choose)
        {
        case 1:
            tree = initTree(tree);
            printf("创建成功!!!\n\n");
            break;
        case 2:
            showTree(tree);
            break;
        case 3:
            showTreeInfo(tree);
            break;
        case 4:
            printf("二叉链表已销毁!");
            destroyTree(tree);
            printf("谢谢使用!");
            system("pause");
            exit(0);
            break;

        default:
            printf("输入错误,请重新输入!");
            break;
        }
    }
    system("pause");
    return 0;
}

六-无向图的邻接矩阵构造与深度广度遍历

运行结果:

请输入图的总顶点数和总边数:
8
9
输入邻接矩阵各个顶点的信息:
1
2
3
4
5
6
7
8
输入边(Vi, Vj)上的下标Vi和Vj及权值w:
0
1
1
边(V0, V1)的权值为1
0
2
1
边(V0, V2)的权值为1
1
3
1
边(V1, V3)的权值为1
1
4
1
边(V1, V4)的权值为1
3
7
1
边(V3, V7)的权值为1
4
7
1
边(V4, V7)的权值为1
2
5
1
边(V2, V5)的权值为1
2
6
1
边(V2, V6)的权值为1
5
6
1
边(V5, V6)的权值为1

无向图邻接矩阵输出如下:
0  1  1  0  0  0  0  0
1  0  0  1  1  0  0  0
1  0  0  0  0  1  1  0
0  1  0  0  0  0  0  1
0  1  0  0  0  0  0  1
0  0  1  0  0  0  1  0
0  0  1  0  0  1  0  0
0  0  0  1  1  0  0  0

深度优先遍历DFS:
 1  2  4  8  5  3  6  7
广度优先遍历BFS:
 1  2  3  4  5  6  7  8
请按任意键继续. . .

源代码:

// C实现图
// 构造无向连通图,采用邻接矩阵作为图的存储结构,输出邻接矩阵,完成图的 DFS (深度优先遍历)和 BFS (广度优先遍历)的操作。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// 图的邻接矩阵存储表示
#define MaxInt 32767 // 表示极大值和队列可能达到的最大长度
// 最大顶点数
#define MVNum 100
// 深度优先遍历标记符
bool flag[MVNum];
// 广度优先遍历标记符
bool visited[MVNum];
// 假设顶点的数据类型为字符型
typedef char VerTexType;
// 假设边的权值类型为整型
typedef int OtherInfo;
typedef struct
{
    VerTexType vexs[MVNum]; // 顶点表
    int arcs[MVNum][MVNum]; // 邻接矩阵
    int vexnum, arcnum;     // 图的当前顶点数和边数
} AMGraph;
// 为广度优先遍历构造队列
typedef int QElemType;
typedef struct
{
    QElemType *base; // 初始化的动态分配存储空间
    int front;       // 头指针,若队列不空,指向队列头元素
    int rear;        // 尾指针,若队列不空,指向队列尾元素的下一个位置
} SqQueue;
void InitQueue(SqQueue &Q)
{
    // 构造一个空队列Q
    Q.base = new QElemType[MVNum];
    if (!Q.base)
        exit(-1);
    Q.front = Q.rear = 0;
}
bool QueueEmpty(SqQueue Q)
{
    // 判断队列是否为空,若为空返回true,否则返回false
    if (Q.front == Q.rear)
        return true;
    else
        return false;
}
// 入队
void EnQueue(SqQueue &Q, QElemType e)
{
    // 插入元素e为Q的新的队尾元素
    if ((Q.rear + 1) % MVNum == Q.front)
        exit(-1);
    Q.base[Q.rear] = e;
    Q.rear = (Q.rear + 1) % MVNum;
}
// 出队
bool DeQueue(SqQueue &Q, QElemType &e)
{
    // 若队列不空,则删除Q的队头元素,用e返回其值,并返回true,否则返回false
    if (Q.front == Q.rear)
        return false;
    e = Q.base[Q.front];
    Q.front = (Q.front + 1) % MVNum;
    return true;
}
// 确定v1和v2在G中的位置
int LocateVEX(AMGraph &G, VerTexType v)
{
    int i;
    for (i = 0; i < G.vexnum; i++)
    {
        if (G.vexs[i] == v)
            return i;
    }
    return -1;
}
// 采用邻接矩阵表示法创建无向网
// 若要建立无向图,一是初始化邻接矩阵时,将边的权值均初始化化为0,二是在构造邻接矩阵时,将权值w改为常量1即可。
AMGraph CreateUDN(AMGraph &G)
{
    int i, j, k;
    int v1, v2;
    OtherInfo w;
    printf("请输入图的总顶点数和总边数:\n");
    scanf("%d%d", &G.vexnum, &G.arcnum);
    // 依次输入点的信息
    printf("输入邻接矩阵各个顶点的信息: \n");
    for (i = 0; i < G.vexnum; i++)
    {
        getchar();
        scanf("%c", &G.vexs[i]);
    }
    // 初始化邻接矩阵,边的权值均置为极大值MaxInt
    for (i = 0; i < G.vexnum; i++)
        for (j = 0; j < G.vexnum; ++j)
            // G.arcs[i][j] = MaxInt;
            G.arcs[i][j] = 0;
    // 构造邻接矩阵
    printf("输入边(Vi, Vj)上的下标Vi和Vj及权值w:\n");
    for (k = 0; k < G.arcnum; k++)
    {
        // 输入一条边依附的顶点及权值
        scanf("%d%d%d", &v1, &v2, &w);
        printf("边(V%d, V%d)的权值为%d\n", v1, v2, w);
        // 确定v1和v2在G中的位置,即顶点数组的下标
        i = LocateVEX(G, G.vexs[v1]);
        j = LocateVEX(G, G.vexs[v2]);
        G.arcs[i][j];
        // 将<v1,v2>的权值设置为w
        //  G.arcs[i][j] = w;
        G.arcs[i][j] = 1;
        // 无向图的邻接矩阵是对称矩阵,即将<v2,v1>的权值设置为w
        G.arcs[j][i] = G.arcs[i][j];
    }
    printf("\n无向图邻接矩阵输出如下:\n");
    for (i = 0; i < G.vexnum; i++)
    {
        for (j = 0; j < G.vexnum; j++)
            printf("%-3d", G.arcs[i][j]);
        printf("\n");
    }
    printf("\n");
    return G;
}
// 深度优先遍历无向连通图
void DFS(AMGraph G, int v)
{
    // 从第v个顶点出发递归地深度优先遍历图G
    // 访问第v个顶点,并置访问标志数组相应分量值为true
    printf("%-3c", G.vexs[v]);
    flag[v] = true;
    // 判断是否存在邻接点
    if (G.arcs[v][0] != MaxInt)
        // 依次检查v所有邻接点w
        for (int w = 0; w < G.vexnum; w++)
            if (G.arcs[v][w] == 1 && flag[w] == false)
            {
                flag[w] = true; // 修正:将访问标志置为true
                DFS(G, w);      // 对v的尚未访问的邻接顶点w递归调用DFS()
            }
}
// 广度优先遍历无向连通图
void BFS(AMGraph G)
{
    int u, v;
    SqQueue Q;

    // 初始化所有顶点的访问标记为false
    for (v = 0; v < G.vexnum; v++)
        visited[v] = false;

    // 初始化队列
    InitQueue(Q);

    // 从每个未访问的顶点开始进行BFS
    for (u = 0; u < G.vexnum; u++)
    {
        if (!visited[u])
        {
            // 标记当前顶点为已访问,并输出
            visited[u] = true;
            printf("%-3c", G.vexs[u]);
            // 将当前顶点入队
            EnQueue(Q, u);

            // 开始BFS
            while (!QueueEmpty(Q))
            {
                // 出队一个顶点
                DeQueue(Q, u);
                // 遍历u的所有邻接顶点
                for (v = 0; v < G.vexnum; v++)
                {
                    // 如果u和v相邻且v未被访问过
                    if (G.arcs[u][v] != 0 && G.arcs[u][v] != MaxInt && !visited[v])
                    {
                        // 标记v为已访问,并输出
                        printf("%-3c", G.vexs[v]);
                        visited[v] = true;
                        // 将v入队,以便继续访问其邻接顶点
                        EnQueue(Q, v);
                    }
                }
            }
        }
    }
}
int main()
{
    int i;
    // 创建无向图邻接矩阵
    AMGraph G;
    CreateUDN(G);
    // 深度优先遍历图G
    printf("深度优先遍历DFS:\n ");
    DFS(G, i);
    printf("\n");
    printf("广度优先遍历BFS:\n ");
    BFS(G);
    printf("\n");
    system("pause");
    return 0;
}

七-查找算法(顺序,折半,分块)

运行结果:

请输入查找表的长度:
8
输入表中的数据元素:
1
2
3
4
5
6
7
8
请输入要查找的关键字:
4
***********************
* 请选择要查找的方式
* 1.顺序查找
* 2.折半查找
* 3.分块查找
* 0.退出
***********************
1
顺序查找成功!关键字4的位置为4
查找次数为4
***********************
* 请选择要查找的方式
* 1.顺序查找
* 2.折半查找
* 3.分块查找
* 0.退出
***********************
2
折半查找成功!关键字4的位置为4
查找次数为1
***********************
* 请选择要查找的方式
* 1.顺序查找
* 2.折半查找
* 3.分块查找
* 0.退出
***********************
3
分块查找成功!关键字4的位置为4
查找次数为4
***********************
* 请选择要查找的方式
* 1.顺序查找
* 2.折半查找
* 3.分块查找
* 0.退出
***********************
0
谢谢使用!请按任意键继续. . .

源代码:

// 顺序查找的C实现
#include <stdio.h>
#include <stdlib.h>

typedef int KeyType;
typedef struct
{
    KeyType key; // 关键字域
} ElemType;
typedef struct
{
    ElemType *elem; // 数据元素存储基址,动态分配数组
    int length;     // 表长度
} SSTable;

// 创建查找表
SSTable *Create(int length)
{
    SSTable *st = (SSTable *)malloc(sizeof(SSTable));
    st->length = length;
    st->elem = (ElemType *)malloc((length + 1) * sizeof(ElemType)); // 数组下标从1开始
    printf("输入表中的数据元素:\n");

    for (int i = 1; i <= length; i++)
    {
        scanf("%d", &(st->elem[i].key));
    }

    return st;
}
// 销毁查找表
void Destroy(SSTable *st)
{
    free(st->elem); // 释放数据元素存储空间
    free(st);       // 释放查找表存储空间
}

// 在顺序表st中顺序查找其关键字等于Key的数据元素。若找到,则函数值为该元素在表中的位置,否则为0
int Search_Seq(SSTable *st, KeyType Key, int *searchCount)
{
    int i;
    *searchCount = 0;      // 初始化查找次数为0
    st->elem[0].key = Key; // 将关键字作为一个数据元素存放到查找表的第一个位置,起监视哨的作用

    for (i = st->length; st->elem[i].key != Key; --i)
    {
        (*searchCount)++; // 增加查找次数
        if (i == 0)
        {
            return 0;
        }
    }

    return i;
}

// 折半查找
int Search_Bin(SSTable *st, KeyType Key, int *searchCount)
{
    int low = 1;
    int high = st->length;
    int mid;

    *searchCount = 0; // 初始化查找次数为0

    while (low <= high)
    {
        mid = low + (high - low) / 2;
        (*searchCount)++; // 增加查找次数
        if (st->elem[mid].key == Key)
        {
            return mid; // 找到了,返回位置
        }
        else if (st->elem[mid].key < Key)
        {
            low = mid + 1; // 在右半边查找
        }
        else
        {
            high = mid - 1; // 在左半边查找
        }
    }

    return 0; // 没有找到,返回0
}

// 分块查找
int Search_Block(SSTable *st, KeyType Key, int *searchCount)
{
    int i, j;
    *searchCount = 0; // 初始化查找次数为0

    // 设置块的大小,这里假设块的个数为 length/3
    int blockSize = st->length / 3;

    // 在块的索引表中查找关键字所在的块
    for (i = 0; i < st->length / blockSize; i++)
    {
        (*searchCount)++; // 增加查找次数
        if (Key <= st->elem[(i + 1) * blockSize].key)
        {
            // 在找到的块内进行顺序查找
            for (j = i * blockSize + 1; j <= (i + 1) * blockSize; j++)
            {
                (*searchCount)++; // 增加查找次数
                if (st->elem[j].key == Key)
                {
                    return j; // 找到了,返回位置
                }
            }
            break; // 查找结束,跳出循环
        }
    }

    return 0; // 没有找到,返回0
}

// 显示菜单
void menu()
{
    printf("***********************\n");
    printf("* 请选择要查找的方式      \n");
    printf("* 1.顺序查找           \n");
    printf("* 2.折半查找            \n");
    printf("* 3.分块查找             \n");
    printf("* 0.退出                 \n");
    printf("***********************\n");
}

int main()
{
    SSTable *st;
    printf("请输入查找表的长度:\n");
    int length;
    scanf("%d", &length);
    st = Create(length);
    printf("请输入要查找的关键字:\n");
    KeyType Key;
    scanf("%d", &Key);

    while (1)
    {
        menu();
        int choose;
        int pos, pos1, pos2;
        int searchCount;
        scanf("%d", &choose);
        switch (choose)
        {
        case 1:
            pos = Search_Seq(st, Key, &searchCount);
            if (pos != 0)
            {
                printf("顺序查找成功!关键字%d的位置为%d\n", Key, pos);
                printf("查找次数为%d\n", searchCount);
            }
            else
            {
                printf("查找失败,没有关键字为%d的数据元素\n", Key);
            }
            break;
        case 2:
            pos1 = Search_Bin(st, Key, &searchCount);
            if (pos1 != 0)
            {
                printf("折半查找成功!关键字%d的位置为%d\n", Key, pos1);
                printf("查找次数为%d\n", searchCount);
            }
            else
            {
                printf("查找失败,没有关键字为%d的数据元素\n", Key);
            }

            break;
        case 3:
            pos2 = Search_Block(st, Key, &searchCount);
            if (pos2 != 0)
            {
                printf("分块查找成功!关键字%d的位置为%d\n", Key, pos2);
                printf("查找次数为%d\n", searchCount);
            }
            else
            {
                printf("查找失败,没有关键字为%d的数据元素\n", Key);
            }
            break;

        case 0:
            Destroy(st); // 销毁查找表
            printf("谢谢使用!");
            system("pause");
            exit(0);
            break;

        default:
            printf("输入错误,请重新输入!");
            break;
        }
    }

    system("pause");
    return 0;
}

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0_54204465

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值