《啊哈!算法》-第 2 章:栈、队列、链表

浏览: 28 发布日期: 2017-07-18 分类: c

队列

概念

队列是一种特殊的线性结构,它只允许在队列的首部(head)进行删除,这称为“出队”,而在队列的尾部(tail)进行插入操作,这称为“入队”。当队列中没有元素时(即head == tail),称为空队列。

队列具有“先进先出”(Frist In Frist Out, FIFO)原则。

代码实现

struct queue {
  int data[101];
  int head;
  int tail;
};

概念

栈是一种后进先出的数据结构。限定为只能在一段进行插入和删除的操作。

举例说明

比如说有一个小桶,小桶的直径只能放置一个小球,现在小桶内依次放入2、1、3 号小球。假如现在需要拿出 2 号小球,那就必须先将 3 号小球和 1 号小球拿出来,最后才能拿到 2 号小球。在取小球的过程中,最先放进去的最后才能拿出来,最后放进去的却可以最先拿出来。

链表

解决问题

在存储一大波数的时候,通常使用数组,但有时候数组显得不够灵活,比如:

有一串已经从小到大排序好的数。现在需要往这窜数种插入一个数字使其得到的新序列仍符合从小到大排列。

动态存储

例如在程序中存储一个整数 10,除了使用 int a 这种方式在内存中申请一块区域来存储,还有另外一种动态存储方法:

malloc(4);

不确定类型是多少个字节的话,可以使用 sizeof() 来获取,例如:

malloc(sizeof(int));

代码实现

每一个结点由两部分组成。一部分用来存放具体的数值,另外一个部分需要用来存储下一个结点的地址。例如:

// 链表结点
struct node {
  int data;
  struct node *next;
};
#include <stdio.h>
#include <stdlib.h>

// 链表结点
struct node {
  int data;
  struct node *next;
};

void insert(struct node *head, int n) {
  struct node *p, *t;
  
  t = head;

  while (t != NULL) {
    if (t->next == NULL || t->next->data > n) {
      // 如果当前结点是最后一个节点或者下一个结点的值大于待插入数的时候插入
      p = (struct node*)malloc(sizeof(struct node));
      p->data = n;
      p->next = t->next;
      t->next = p;
      break;
    }

    t = t->next;
  }
}

int main(void) {
  struct node *head, *p, *q, *t;
  int i, n, a;
  
  scanf("%d", &n);

  // 初始化头指针为空
  head = NULL;

  for (i = 0; i < n; i++) {
    scanf("%d", &a);

    // 动态申请一个空间,用来存放一个结点,并且用临时指针 p 指向这个结点
    p = (struct node *)malloc(sizeof(struct node));
    p->data = a;
    p->next = NULL;

    if (head != NULL) {
      // 头指针不为空,则说明已经有结点了,插入那个结点的尾部
      q->next = p;
    } else {
      // 头指针为空,则说明没有结点,头指针指向结点
      head = p;
    }

    // 替换之前的结点
    // q 用于存放当前结点
    q = p;
  }

  scanf("%d", &n);

  insert(head, n);
  
  t = head;

  while (t != NULL) {
    printf("%d ", t->data);
    t = t->next;
  }

  printf("\n");

  return 0;
}

数组实现-模拟链表

实现方式

申明两个变量,分别是整数数组 data 和整数数组 right。data 用来存放序列种具体的数字,right 用来存放当前序列种每一个元素右边在数组 data 中位置,没有则为 0。

代码实现

#include <stdio.h>
#define NUM 100

int main(void) {
  int data[NUM], right[NUM], i, n, len = 1;

  for (i = 0; i < NUM; i++) {
    data[i] = 0;
    right[i] = 0;
  }

  scanf("%d", &n);

  for (i = 1; i <= n; i++) {
    scanf("%d", &data[i]);

    right[len] = len + 1;
    len++;
  }

  // 插入
  scanf("%d", &data[len]);

  i = 1;

  while (i != 0) {
    if (data[right[i]] > data[len]) {
      // 如果当前结点下一个结点的值大于待插入数,将数插入到中间
      right[len] = right[i];ight[len] = right[i];
      right[i] = len;
      break;
    }
    i = right[i];
  }

  i = 1;

  while (i != 0) {
    printf("%d ", data[i]);
    i = right[i];
  }

  printf("\n");

  return 0;
}

纸牌游戏-小猫钓鱼

#include <stdio.h>

// 队列
struct queue {
  int data[101];
  int head;
  int tail;
} q1, q2;

// 栈
struct stack {
  int data[101];
  int top;
} cards;

// 模拟手牌
int c1[101] = {2, 4, 1, 2, 5, 6};
int c2[101] = {3, 1, 3, 5, 6, 4};


// 第一种做法
void play(struct queue *q1) {
  // 出牌
  int i, flag = 0, t = q1->data[q1->head];
  q1->head++;

  // 匹配
  for (i = 0; i < cards.top; i++) {
    if (cards.data[i] == t) {
      flag = 1;
      break;
    }
  }

  if (flag == 1) {
    // 匹配成功
    while (cards.data[cards.top - 1] != t) {
      q1->data[q1->tail++] = cards.data[cards.top - 1];
      cards.top--;
    }

    q1->data[q1->tail++] = t;
  } else {
    // 匹配失败
    // 把打出的牌放入牌堆
    cards.data[cards.top++] = t;
  }
}

// 第二种

int main(void) {
  // 初始化牌堆
  cards.top = 0;
  // 初始化选手
  int i;
  q1.head = 0;
  q1.tail = 0;
  q2.head = 0;
  q2.tail = 0;
  for (i = 0; i < 6; i++) {
    q1.data[i] = c1[i];
    q1.tail++;
    q2.data[i] = c2[i];
    q2.tail++;    
  }

  while (q1.head < q1.tail && q2.head < q2.tail) {
    play(&q1);
    play(&q2);
  }

  if (q1.head == q1.tail) {
    printf("winer is q2\n");
  } else {
    printf("winer is q1\n");    
  }

  printf("q1:");
  for (i = q1.head; i < q1.tail; i++) {
    printf("%d ", q1.data[i]);
  }
  printf("\nq2:");  
  for (i = q2.head; i < q2.tail; i++) {
    printf("%d ", q2.data[i]);
  }
  printf("\n");  
  for (i = 0; i < cards.top; i++) {
    printf("%d ", cards.data[i]);
  }

  return 0;
}
返回顶部