找回密码
 立即注册
首页 业界区 安全 C语言之数据结构与算法

C语言之数据结构与算法

扈怀易 6 天前
一、数据结构与算法:线性表

1、顺序表

实现代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. typedef int E;  //定义顺序表存储的数据为int
  4. struct List
  5. {
  6.     E *array;    //实现顺序表的底层数组
  7.     int capacity;   //表示底层数组的容量
  8.     int size;   //已存多少数据
  9. };
  10. //插入元素
  11. _Bool insertList(struct List *list, E element, int index){
  12.     if (index < 1 || index > list->size + 1) return 0;  //index可能非法
  13.     if(list->size == list->capacity){   //判断顺序表是否满了,若满,则扩容。
  14.         int newCapacity = list->capacity + (list->capacity >> 1);   //>>1 相当于/2
  15.         E * newList = realloc(list->array, newCapacity*sizeof(E));
  16.         if(newList == NULL) return 0;
  17.         list->array = newList;
  18.         list->capacity = newCapacity;
  19.     }
  20.     for (int i = list->size; i>=index; --i){
  21.         list->array[i] = list->array[i-1];
  22.     }
  23.     list->array[index - 1] = element;
  24.     list->size++;
  25.     return 1;
  26. }
  27. //删除元素
  28. _Bool deleteList(struct List *list,int index){
  29.     if(index < 1 || index > list->size) return 0;
  30.     for(int i = index - 1; i < list->size - 1; ++i){
  31.         list->array[i] = list->array[i+1];
  32.     }
  33.     list->size--;
  34. }
  35. //活得顺序表大小
  36. int sizeList(struct List *list){
  37.     return list->size;
  38. }
  39. //获得元素
  40. E * getList(struct List *list, int index){
  41.     if(index < 1 || index > list->size) return NULL;
  42.     return &list->array[index-1];
  43. }
  44. //查找元素
  45. int findList(struct List *list,E element){
  46.     for(int i = 0; i < list->size; i++){
  47.         if(list->array[i] == element) return i + 1;
  48.     }
  49.     return -1;
  50. }
  51. /*
  52. **
  53. **
  54. */
  55. _Bool initList(struct List *list ){
  56.     list->array = malloc(sizeof(E)*10); //malloc开辟的内存在堆区,函数生命周期结束后还存在(需要手动释放或程序结束后由系统释放)。
  57.     if (list->array == NULL) return 0;  //若申请内存空间失败,则返回0.
  58.     list->capacity = 10;
  59.     list->size = 0;
  60.     return 1;
  61. }
  62. void printList(struct List *list){
  63.     for(int i = 0; i<list->size; ++i){
  64.         printf("%d ", list->array[i]);
  65.     }
  66.     printf("\n");
  67. }
  68. int main(int argc,int* argv)
  69. {
  70.     struct List * list = malloc(sizeof(struct List *));
  71.     /*结构体指针初始化,首先不能 “= NULL”,因为指针指向一个安全的区域,不能解析。
  72.     **也不能,不初始化,因为指针可能指向未知地址,对其操作造成的后果是未知的,
  73.     **初始化方式有:一、在堆区开辟一个空间;二、先定义一个结构体,用指针指向他;
  74.     */
  75.     if(initList(list)){
  76.         for(int i = 0; i<10; ++i){
  77.             insertList(list,i*10,i+1);
  78.         }
  79.         deleteList(list,2);
  80.         printList(list);
  81.         printf("%d \n",*getList(list,2));
  82.         printf("%d",findList(list,30));
  83.     }
  84.     else{
  85.         printf("shibai");
  86.     }
  87.     free(list);
  88. }
复制代码
链表表是一种顺序访问的存储结构。
3、双向链表

4、循环链表w

5、堆栈(Stack)

先进后出
6、队列(Queue)

先进先出
实战1、反转链表

题目描述:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
解法一
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. typedef int E;  //定义顺序表存储的数据为int
  4. struct ListNode{
  5.     E element;
  6.     struct ListNode *next;
  7. };
  8. typedef struct ListNode* Node;
  9. void initList(Node node){
  10.     node->next = NULL;
  11. }
  12. _Bool insertList(Node head, E element, int index){
  13.     if(index < 0) return 0;
  14.     while(--index){
  15.         head = head->next;
  16.         if(head == NULL) return 0;
  17.     }
  18.     Node node = malloc(sizeof(struct ListNode));
  19.     if(node == NULL) return 0;
  20.     node->element = element;
  21.     node->next = head->next;
  22.     head->next = node;
  23.     return 1;
  24. }
  25. _Bool deleteList(Node head, int index){
  26.     if(index < 1) return 0;
  27.     while(--index){
  28.         head = head->next;
  29.         if(head == NULL) return 0;
  30.     }
  31.     if(head->next == NULL) return 0;
  32.     Node node = head->next;
  33.     head->next = head->next->next;
  34.     free(node);
  35.     return 1;
  36. }
  37. //获得元素;
  38. E *getList(Node head, int index){
  39.     if(index < 1) return 0;
  40.     if (head->next == NULL) return NULL;    //若为空表,则返回为空;
  41.     do{
  42.         head = head->next;
  43.         if(head == NULL) return NULL;
  44.     }while(--index);
  45.     return &head->element;
  46. }
  47. //寻找元素下标
  48. int findList(Node head, E element){
  49.     int i = 1;
  50.     if(head->next == NULL) return -1;   //判断是否为空表
  51.     do{
  52.         head = head->next;
  53.         if(head->element == element) return i;
  54.         i++;
  55.     }while(head->next);
  56.     return -1;
  57. }
  58. int sizeList(Node head){
  59.     int i = 0;
  60.     while(head->next){
  61.         i++;
  62.         head = head->next;
  63.     }
  64.     return i;
  65. }
  66. //函数都是值传递,传值,值不变;传指针,指针不变;传指针,值会变
  67. //对head->element或者head->next操作会改变值
  68. void printfList(Node head){
  69.     while(head->next){
  70.         head = head->next;
  71.         printf("%d ",head->element);
  72.     }
  73.     printf("\n");
  74. }
  75. int main()
  76. {
  77.     Node p1;
  78.     struct ListNode head;
  79.     initList(&head);
  80.     for(int i = 0; i < 3; ++i){
  81.         insertList(&head,i*10, i+1);
  82.     }
  83.     printfList(&head);
  84.     printf("%d",sizeList(&head));
  85.    
  86. }
复制代码
解法二:递归
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. typedef int E;  //定义顺序表存储的数据为int
  4. struct ListNode{
  5.     int val;
  6.     struct ListNode *next;
  7. };
  8. struct ListNode* reverseList(struct ListNode* head)
  9. {
  10.     struct ListNode *tmp,*newHead = NULL;
  11.     while (head)
  12.     {
  13.         //假设前面已被反转。
  14.         tmp = head->next;        //保存第二个节点,用于当作下一个节点的头结点。
  15.         head->next = newHead;        //指向前节点
  16.         newHead = head;        //更新前节点
  17.         head = tmp;        //新链表
  18.     }
  19.     return newHead;
  20. }
复制代码
实战2、匹配字符串

给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:

  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。
  • 每个右括号都有一个对应的相同类型的左括号。
方法:栈的应用

方法1:自己的
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. typedef int E;  //定义顺序表存储的数据为int
  4. struct ListNode{
  5.     int val;
  6.     struct ListNode *next;
  7. };
  8. struct ListNode* reverseList(struct ListNode* head) {
  9.     if (head == NULL || head->next == NULL) {
  10.         return head;
  11.     }
  12.     struct ListNode* newHead = reverseList(head->next);
  13.     head->next->next = head;
  14.     head->next = NULL;
  15.     return newHead;
  16. }
复制代码
方法2:更快
  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<stdlib.h>>
  4. #define true 1
  5. #define false 0
  6. typedef char E;
  7. struct LNode {
  8.     E val;
  9.     struct LNode *next;
  10. };
  11. typedef struct LNode* Node;
  12. void initStack(Node head){
  13.     head->next = NULL;
  14. }
  15. void printStack(Node head){
  16.     printf("| ");
  17.     head = head->next;
  18.     while (head){
  19.         printf("%d ", head->val);
  20.         head = head->next;
  21.     }
  22.     printf("\n");
  23. }
  24. //入栈
  25. _Bool pushStack(Node head, E val){
  26.     Node node = malloc(sizeof(struct LNode));
  27.     if(node == NULL) return 0;
  28.     node->next = head->next;
  29.     node->val = val;
  30.     head->next = node;
  31.     return 1;
  32. }
  33. //出栈
  34. E popStack(Node head){
  35.     if(head->next == NULL) return 0;
  36.     Node node;
  37.     node = head->next;
  38.     E val = node->val;
  39.     head->next = head->next->next;
  40.     free(node);
  41.     return val;
  42. }
  43.    
  44. _Bool isValid(char* s) {
  45.     struct LNode head;
  46.     initStack(&head);
  47.     unsigned int len = strlen(s);
  48.     if(len % 2 == 1) return false;
  49.     pushStack(&head,s[0]);
  50.     for(int i = 1; i < len; i++){
  51.         E top = popStack(&head);
  52.         if(top != 0)pushStack(&head,top);
  53.         if(top == '('){
  54.             if(s[i] == ')') popStack(&head);
  55.             else pushStack(&head,s[i]);
  56.         }
  57.         else if(top == '['){
  58.             if(s[i] == ']') popStack(&head);
  59.             else pushStack(&head,s[i]);
  60.         }
  61.         else if(top == '{'){
  62.             if(s[i] == '}') popStack(&head);
  63.             else pushStack(&head,s[i]);
  64.         }
  65.         else  pushStack(&head,s[i]);
  66.     }
  67.     if(head.next == NULL) return true;
  68.     else return false;
  69. }
  70. int main(){
  71.     char *s = "()[]{}";
  72.     printf("%d ",isValid(s));
  73. }
复制代码
方法三:更快
  1. #include <stdlib.h>
  2. #include <stdbool.h>
  3. #include <string.h>
  4. typedef char E;
  5. struct LNode {
  6.     E element;
  7.     struct LNode * next;
  8. };
  9. typedef struct LNode * Node;
  10. void initStack(Node head){
  11.     head->next = NULL;
  12. }
  13. _Bool pushStack(Node head, E element){
  14.     Node node = malloc(sizeof(struct LNode));
  15.     if(node == NULL) return 0;
  16.     node->next = head->next;
  17.     node->element = element;
  18.     head->next = node;
  19.     return 1;
  20. }
  21. _Bool isEmpty(Node head){
  22.     return head->next == NULL;
  23. }
  24. E popStack(Node head){
  25.     Node top = head->next;
  26.     head->next = head->next->next;
  27.     E e = top->element;
  28.     free(top);
  29.     return e;
  30. }
  31. bool isValid(char * s){
  32.     unsigned long len = strlen(s);
  33.     if(len % 2 == 1) return false;  //如果长度不是偶数,那么一定不能成功匹配
  34.     struct LNode head;
  35.     initStack(&head);
  36.     for (int i = 0; i < len; ++i) {
  37.         char c = s[i];
  38.         if(c == '(' || c == '[' || c == '{') {
  39.             pushStack(&head, c);
  40.         }else {
  41.             if(isEmpty(&head)) return false;
  42.             if(c == ')') {
  43.                 if(popStack(&head) != '(') return false;
  44.             } else if(c == ']') {
  45.                 if(popStack(&head) != '[') return false;
  46.             } else {
  47.                 if(popStack(&head) != '{') return false;
  48.             }
  49.         }
  50.     }
  51.     return isEmpty(&head);
  52. }
复制代码
二、数据结构与算法:树

1、树:理论


  • 我们一般称位于最上方的结点为树的根结点(Root);
  • 每个结点连接的子结点数目(分支的数目),我们称为结点的(Degree),而各个结点度的最大值称为树的度
  • 每个结点延伸下去的下一个结点都可以称为一棵子树(SubTree);
  • 每个结点的层次(Level)按照从上往下的顺序,树的根结点为1,每向下一层+1,比如G的层次就是3,整棵树中所有结点的最大层次,就是这颗树的深度(Depth);
  • 与当前结点直接向下相连的结点,我们称为子结点(Child);相反即为父节点
  • 如果某个节点没有任何的子结点(结点度为0时)那么我们称这个结点为叶子结点
  • 如果两个结点的父结点是同一个,那么称这两个节点为兄弟结点(Sibling);
  • 从根结点开始一直到某个结点的整条路径的所有结点,都是这个结点的祖先结点(Ancestor);
2、二叉树的性质


  • 性质一: 对于一棵二叉树,第i层的最大结点数量为 个2^i - 1;
  • 一棵深度为k的二叉树最大结点数量为 n = 2^k*−1,顺便得出,结点的边数为 E = n - 1。
  • 于任何一棵二叉树,如果其叶子结点个数为 n0,度为2的结点个数为 n2 ,那么两者满足以下公式:n0 = n2+1;
  • n个结点的完全二叉树深度为 k = log2^n + 1 ;

3、二叉树遍历:前序、中序、后序遍历

1.png

前序遍历结果为:ABDECF;
中序遍历结果为:DBEACF;
后序遍历结果为:DEBFCA;
  1. char pairs(char a) {
  2.     if (a == '}') return '{';
  3.     if (a == ']') return '[';
  4.     if (a == ')') return '(';
  5.     return 0;
  6. }
  7. bool isValid(char* s) {
  8.     int n = strlen(s);
  9.     if (n % 2 == 1) {
  10.         return false;
  11.     }
  12.     int stk[n + 1], top = 0;
  13.     for (int i = 0; i < n; i++) {
  14.         char ch = pairs(s[i]);
  15.         if (ch) {
  16.             if (top == 0 || stk[top - 1] != ch) {
  17.                 return false;
  18.             }
  19.             top--;
  20.         } else {
  21.             stk[top++] = s[i];
  22.         }
  23.     }
  24.     return top == 0;
  25. }
复制代码
4、二叉树遍历:层序遍历
  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<stdlib.h>>
  4. typedef char E;
  5. struct TreeNode{
  6.     E element;
  7.     struct TreeNode *left;
  8.     struct TreeNode *right;
  9. };
  10. typedef struct TreeNode* Node;
  11. //前序递归,利用函数栈的特性,不断出栈入栈
  12. void preOrder(Node root){
  13.     if(root == NULL) return;   
  14.     printf("%c", root->element);
  15.     preOrder(root->left);
  16.     preOrder(root->right);
  17. }
  18. //中序遍历
  19. void inOrder(Node root){
  20.     if(root == NULL) return;
  21.     inOrder(root->left);
  22.     printf("%c",root->element);
  23.     inOrder(root->right);
  24. }
  25. //后序遍历
  26. void afOrder(Node root){
  27.     if(root == NULL) return;
  28.     afOrder(root->left);
  29.     afOrder(root->right);
  30.     printf("%c",root->element);
  31. }
  32. int main(){
  33.     Node a = malloc(sizeof(struct TreeNode));
  34.     Node b = malloc(sizeof(struct TreeNode));
  35.     Node c = malloc(sizeof(struct TreeNode));
  36.     Node d = malloc(sizeof(struct TreeNode));
  37.     Node e = malloc(sizeof(struct TreeNode));
  38.     Node f = malloc(sizeof(struct TreeNode));
  39.     a->element = 'A';
  40.     b->element = 'B';
  41.     c->element = 'C';
  42.     d->element = 'D';
  43.     e->element = 'E';
  44.     f->element = 'F';
  45.     a->left = b;
  46.     a->right = c;
  47.     b->left = d;
  48.     b->right = e;
  49.     c->right = f;
  50.     c->left = NULL;
  51.     d->left = e->right = NULL;
  52.     e->left = e->right = NULL;
  53.     f->left = f->right = NULL;
  54.     afOrder(a);
  55. }
复制代码
5、二叉树的线索化(以前序为例)
  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<stdlib.h>
  4. typedef char E;
  5. typedef struct TreeNode {
  6.     E element;    //存放元素
  7.     struct TreeNode * left;   //指向左子树的指针
  8.     struct TreeNode * right;   //指向右子树的指针
  9. } *Node;
  10. typedef struct initNode{   //定义队列初始节点
  11.     Node element;
  12.     struct initNode *next;
  13. } *INode;
  14. struct Queue{   //队列头尾指针
  15.     INode front,rear;
  16. };
  17. typedef struct Queue* LinkedQueue;
  18. _Bool initQueue(LinkedQueue queue){
  19.     INode node = malloc(sizeof(struct initNode));
  20.     if(node == NULL) return 0;
  21.     node->next = NULL;
  22.     queue->front = queue->rear = node;
  23. }
  24. //入队
  25. _Bool enQueue(LinkedQueue quene, Node element){
  26.     INode node = malloc(sizeof(struct initNode));
  27.     if(node == NULL) return 0;
  28.     node->next = NULL;
  29.     node->element = element;
  30.     quene->rear->next = node;
  31.     quene->rear = node;
  32.     return 1;
  33. }
  34. // 出队
  35. Node deQueue(LinkedQueue queue){
  36.     Node val = queue->front->next->element;
  37.     INode node;
  38.     node = queue->front->next;
  39.     queue->front->next = queue->front->next->next;
  40.     if(queue->rear == node) queue->rear = queue->front;
  41.     free(node);
  42.     return val;
  43. }
  44. _Bool isEmpty(LinkedQueue queue){
  45.     return (queue->front == queue->rear);
  46. }
  47. void levelQueue(Node root){
  48.     struct Queue queue;
  49.     initQueue(&queue);
  50.     enQueue(&queue,root);
  51.     while(!isEmpty(&queue)){
  52.         Node node = deQueue(&queue);
  53.         printf("%c",node->element);
  54.         if(node->left) enQueue(&queue,node->left);
  55.         if(node->right) enQueue(&queue,node->right);
  56.     }
  57. }
  58. int main(){
  59.     Node a = malloc(sizeof(struct TreeNode));
  60.     Node b = malloc(sizeof(struct TreeNode));
  61.     Node c = malloc(sizeof(struct TreeNode));
  62.     Node d = malloc(sizeof(struct TreeNode));
  63.     Node e = malloc(sizeof(struct TreeNode));
  64.     Node f = malloc(sizeof(struct TreeNode));
  65.     a->element = 'A';
  66.     b->element = 'B';
  67.     c->element = 'C';
  68.     d->element = 'D';
  69.     e->element = 'E';
  70.     f->element = 'F';
  71.     a->left = b;
  72.     a->right = c;
  73.     b->left = d;
  74.     b->right = e;
  75.     c->right = f;
  76.     c->left = NULL;
  77.     d->left = e->right = NULL;
  78.     e->left = e->right = NULL;
  79.     f->left = f->right = NULL;
  80.     levelQueue(a);
  81. }
复制代码
六、二叉搜索树(二叉查找树)

七、平衡二叉树

三、数据结构与算法:哈希表

1、哈希表
  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<stdlib.h>
  4. typedef char E;
  5. typedef struct TreeNode {
  6.     E element;    //存放元素
  7.     struct TreeNode * left;   //指向左子树的指针
  8.     struct TreeNode * right;   //指向右子树的指针
  9.     char leftFlag,rightFlag     //线索化标志位
  10. } *Node;
  11. Node pre = NULL;  //这里我们需要一个pre来保存后续结点的指向
  12. void treeOrdered(Node root){
  13.     if(root == NULL) return;
  14.     //线索化规则:结点的左指针,指向其当前遍历顺序的前驱结点;结点的右指针,指向其当前遍历顺序的后继结点。
  15.     if(root->left == NULL){ //判断当前节点的左节点是否为空,若为空,则指向上一个节点。
  16.         root->leftFlag = 1;
  17.         root->left = pre;
  18.     }
  19.     if(pre && pre->right == NULL){  //判断上一个节点的右节点是否为空,若为空,则指向当前节点
  20.         pre->right = root;
  21.         pre->rightFlag = 1;
  22.     }
  23.     pre = root;
  24.     if(root->leftFlag == 0) treeOrdered(root->left);    //判断左节点是否是线索化的,若不是,才能继续。
  25.     if(root->rightFlag == 0) treeOrdered(root->right);  //判断可略,因为,我们对右节点的线索化,是在后面执行的
  26. }
  27. void preOrder(Node root){
  28.     while (root) {   //到头为止
  29.         printf("%c", root->element);   //因为是前序遍历,所以直接按顺序打印就行了
  30.         if(root->leftFlag == 0)
  31.             root = root->left;   //如果是左孩子,那么就走左边
  32.         else
  33.             root = root->right;   //如果左边指向是线索,那么就直接走右边。
  34.     }
  35. }
  36. Node createNode(E element){   //单独写了个函数来创建结点
  37.     Node node = malloc(sizeof(struct TreeNode));
  38.     node->left = node->right = NULL;
  39.     node->rightFlag = node->leftFlag = 0;
  40.     node->element = element;
  41.     return node;
  42. }
  43. int main() {
  44.     Node a = createNode('A');
  45.     Node b = createNode('B');
  46.     Node c = createNode('C');
  47.     Node d = createNode('D');
  48.     Node e = createNode('E');
  49.     a->left = b;
  50.     b->left = d;
  51.     a->right = c;
  52.     b->right = e;
  53.     treeOrdered(a);
  54.     preOrder(a);
  55. }
复制代码
2、哈希冲突(链地址法)
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #define SIZE 9
  4. //结构体指针,直接用E->key访问,避免用*E访问
  5. typedef struct Element {   //这里用一个Element将值包装一下
  6.     int key;    //这里元素设定为int
  7. } * E;
  8. typedef struct HashTable{   //这里把数组封装为一个哈希表
  9.     E * table;
  10. } * HashTable;
  11. int hash(int key){   //哈希函数
  12.     return key % SIZE;
  13. }
  14. void init(HashTable hashTable){   //初始化函数
  15.     hashTable->table = malloc(sizeof(struct Element) * SIZE);
  16.     for (int i = 0; i < SIZE; ++i)
  17.         hashTable->table[i] = NULL;
  18. }
  19. void insert(HashTable hashTable, E element){   //插入操作,为了方便就不考虑装满的情况了
  20.     int hashCode = hash(element->key);   //首先计算元素的哈希值
  21.     hashTable->table[hashCode] = element;   //对号入座
  22. }
  23. _Bool find(HashTable hashTable, int key){
  24.     int hashCode = hash(key);   //首先计算元素的哈希值
  25.     if(!hashTable->table[hashCode]) return 0;   //如果为NULL那就说明没有
  26.     return hashTable->table[hashCode]->key == key;  //如果有,直接看是不是就完事
  27. }
  28. E create(int key){    //创建一个新的元素
  29.     E e = malloc(sizeof(struct Element));
  30.     e->key = key;
  31.     return e;
  32. }
  33. int main() {
  34.     struct HashTable hashTable;
  35.     init(&hashTable);
  36.     insert(&hashTable, create(10));
  37.     insert(&hashTable, create(7));
  38.     insert(&hashTable, create(13));
  39.     insert(&hashTable, create(29));
  40.     printf("%d\n", find(&hashTable, 1));
  41.     printf("%d\n", find(&hashTable, 13));
  42. }
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册