【1】线性表基本题型整理

一、线性表(包括栈,队列)

1、备注
  • 链表的基本操作(遍历,删除,插入),都离不开pre,current,r(或者更多指针)的同步移动问题,主要考察针线活的细心熟练程度。
2、节点定义
Ⅰ、链表节点定义
typedef struct LNode
{
    int data;
    struct LNode *next;
} LNode;
Ⅱ、栈节点定义
//栈
typedef struct Stack
{
    int data[maxsize];
    int top;
} Stack;


void InitStack(Stack *stack);
void push(Stack *stack, int x);
int pop(Stack *stack);
bool isEmpty(Stack *stack);

void InitStack(Stack *stack)
{
    stack->top = -1;
}

void push(Stack *stack, int x)
{
    stack->data[++stack->top] = x;
}

int pop(Stack *stack)
{
    return stack->data[stack->top--];
}

bool isEmpty(Stack *stack){
    if(stack->top == -1){
        return true;
    }
    return false;
}
Ⅲ、队列结点定义
  • 非循环队列(可能会溢出)
typedef struct Queue
{
    ElemType *data[maxsize]; //指针数组
    int front, rear;
} Queue;


void InitQueue(Queue *queue);
void Enqueue(Queue *queue, ElemType *x);
ElemType *Dequeue(Queue *queue);
bool isQueueEmpty(Queue *queue);

void InitQueue(Queue *queue)
{
    queue->front = -1;
    queue->rear = -1;
}

void Enqueue(Queue *queue, ElemType *x)
{
    queue->data[++queue->rear] = x;
}

ElemType *Dequeue(Queue *queue)
{
    return queue->data[++queue->front];
}

bool isQueueEmpty(Queue *queue)
{
    if (queue->rear == queue->front)
    {
        return true;
    }
    return false;
}

  • 循环队列
#define maxsize 6
typedef struct{
	ElemType data[maxsize];
	int rear,front;
}Quene;

void InitQueue(Queue *queue){
	queue->front=0;
	queue->rear=0;
}

void Enqueue(Queue *queue,ElemType x){
	if(!isQueueFull(queue)){
		queue->rear = (queue -> rear + 1) % maxsize;
		queue->data[queue->rear] = x;
	}
}

ElemType Dequeue(Queue *queue){
  if(!isQueueEmpty){
    queue->front = (queue->front + 1) % maxsize;
    return queue->data[queue->front];
  }
}

bool isQueueFull(Queue *queue){
   if((q->rear + 1) % maxsize == q->front){
       return true;
   }
   return false;
}

bool isQueueEmpty(Queue *queue){
  if(queue->first == queue->rear){
    	return true;
  }
  return false;
}
3、遍历操作:
Ⅰ、Demo 1:反向输出

1)描述:

  • 设L为带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值

2)算法思想:

  • 将链表中的值压入栈中,最后反向输出
void reversePrint(LNode *head)
{

    if (head == NULL)
    {
        return;
    }

    Stack stack;
    InitStack(&stack);

    LNode *current = head->next;

    while (current != NULL)
    {
        push(&stack, current->data);
        current = current->next;
    }

    while(!isEmpty(&stack)){
        printf("%d ",pop(&stack));
    }
    printf("\n");
}
int main()
{
    int i;
    LNode *r = NULL; //指向链表队尾的指针
    LNode *head = (LNode *)malloc(sizeof(LNode));
    r = head;

    for (i = 1; i < 3; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = 1;
            r->next = node;
            r = node;
        }
    }

    for (i = 1; i < 3; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = 4;
            r->next = node;
            r = node;
        }
    }

    for (i = 1; i < 4; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = 9;
            r->next = node;
            r = node;
        }
    }

    r->next = NULL;

    r = head->next;
    // 遍历链表
    while (r != NULL)
    {
        printf("%d ", r->data);
        r = r->next;
    }
    printf("\n");

    //反向输出链表
    reversePrint(head);

    printf("\n");
    system("pause");
}

Ⅱ、Demo 2:找公共节点

1)描述:

  • 给定两个单链表,编写算法找出两个链表的公共结点

2)算法思想:

  • 先比较两个链表A,B的长度为lengthA,lengthB
  • 长的链表需要比短的链表多走|lengthA - lengthB|,之后再同步走
  • 若遇到同一个结点,则结束
LNode *search_Common(LNode *head1, LNode *head2)
{

    if (head1 == NULL || head2 == NULL)
    {
        return NULL;
    }

    int lengthA = 0, lengthB = 0;
    LNode *p1 = head1, *p2 = head2;
    //计算两链表的长度
    while (p1 != NULL)
    {
        lengthA += 1;
        p1 = p1->next;
    }
    while (p2 != NULL)
    {
        lengthB += 1;
        p2 = p2->next;
    }

    p1 = head1, p2 = head2;
    int substract = abs(lengthA - lengthB);
    if (lengthA > lengthB)
    {
        while (substract > 0)
        {
            p1 = p1->next;
            substract--;
        }
    }
    if (lengthB > lengthA)
    {
        while (substract > 0)
        {
            p2 = p2->next;
            substract--;
        }
    }

    //p1,p2同时走
    while (p1 != p2)
    {
        p1 = p1->next;
        p2 = p2->next;
    }

    return p1;
}
int main()
{
    int i;
    LNode *r1 = NULL, *r2 = NULL; //指向链表队尾的指针
    LNode *head1 = (LNode *)malloc(sizeof(LNode));
    LNode *head2 = (LNode *)malloc(sizeof(LNode));
    r1 = head1, r2 = head2;

    //建立链表A
    LNode *node1 = (LNode *)malloc(sizeof(LNode));
    node1->data = 1;
    LNode *node2 = (LNode *)malloc(sizeof(LNode));
    node2->data = 2;
    LNode *node3 = (LNode *)malloc(sizeof(LNode));
    node3->data = 3;
    LNode *node4 = (LNode *)malloc(sizeof(LNode));
    node4->data = 4;
    LNode *node5 = (LNode *)malloc(sizeof(LNode));
    node5->data = 5;
    head1->next = node1;
    node1->next = node2;
    node2->next = node3;
    node3->next = node4;
    node4->next = node5;
    node5->next = NULL;

    //建立链表B
    LNode *node6 = (LNode *)malloc(sizeof(LNode));
    node6->data = 6;
    LNode *node7 = (LNode *)malloc(sizeof(LNode));
    node7->data = 7;
    LNode *node8 = (LNode *)malloc(sizeof(LNode));
    node8->data = 8;
    LNode *node9 = (LNode *)malloc(sizeof(LNode));
    node9->data = 9;
    LNode *node10 = (LNode *)malloc(sizeof(LNode));
    node10->data = 10;
    head2->next = node6;
    node6->next = node7;
    node7->next = node8;
    node8->next = node9;
    node9->next = node10;
    node10->next = node3;

    r1 = head1->next, r2 = head2->next;
    //遍历链表
    while (r1 != NULL)
    {
        printf("%d ", r1->data);
        r1 = r1->next;
    }
    printf("\n");
    // 遍历链表
    while (r2 != NULL)
    {
        printf("%d ", r2->data);
        r2 = r2->next;
    }
    printf("\n");

    LNode *node = search_Common(head1, head2);
    printf("%d\n", node->data);

    system("pause");
}
4、删除操作:
Ⅰ、Demo 1:递归删除x

1)描述:

  • 设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点

2)算法思想:

  • 定义一个current,pre,pre一直指向current
  • 结束条件:如果到了链尾,则return
  • 递归主体:如果找到x,则通过pre指针删除current结点,
  • 并将pre结点传递给下一层函数
void delete_x_recursion(LNode *list, int x)
{

    if (list == NULL)
    {
        return;
    }

    else
    {
        LNode *current, *pre;
        pre = list;
        current = pre->next;
        if (current != NULL && current->data == x)
        {
            pre->next = current->next;
            free(current);
            return delete_x_recursion(pre, x);
        }else{
            return delete_x_recursion(current, x);
        }
    }
}
int main()
{
    int i;
    LNode *r = NULL; //指向链表队尾的指针
    LNode *node1 = (LNode *)malloc(sizeof(LNode));
    node1 -> data = 0;
    r = node1;

    for (i = 1; i < 3; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = 1;
            r->next = node;
            r = node;
        }
    }

    for (i = 1; i < 3; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = 4;
            r->next = node;
            r = node;
        }
    }

    for (i = 1; i < 4; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = 9;
            r->next = node;
            r = node;
        }
    }

    r->next = NULL;
    r = node1;

    // 遍历链表
    while (r != NULL)
    {
        printf("%d ", r->data);
        r = r->next;
    }
    printf("\n");

    //删除值为x结点
    delete_x_recursion(node1, 4);

    r = node1;
    // 遍历链表
    while (r != NULL)
    {
        printf("%d ", r->data);
        r = r->next;
    }

    printf("\n");
    system("pause");
}
Ⅱ、Demo 2:删除所有x

1)描述:

  • 在带头结点的单链表L中,删除所有值为x的结点,并释放空间,假设值为x的结点不唯一

2)算法思想:

  • 定义一个current,pre,pre一直指向current
  • 删除结点时,通过pre来删除current结点
void delete_x_NO_RECUR(LNode *head, int x)
{
    if (head == NULL)
    {
        return;
    }

    LNode *pre = head,*current = pre->next,*q;

    while (current != NULL)
    {
        if (current->data == x)
        {
            q = current;
            current = current->next;
            pre->next = current;
            free(q);
        }
        else
        {
            pre = current;
            current = current->next;
        }
    }
}
int main()
{
    int i;
    LNode *r = NULL; //指向链表队尾的指针
    LNode *head = (LNode *)malloc(sizeof(LNode));
    r = head;

   for (i = 1; i < 3; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = 1;
            r->next = node;
            r = node;
        }
    }

    for (i = 1; i < 3; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = 4;
            r->next = node;
            r = node;
        }
    }

    for (i = 1; i < 4; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = 9;
            r->next = node;
            r = node;
        }
    }

    r->next = NULL;
    
    r = head -> next;
    // 遍历链表
    while (r != NULL)
    {
        printf("%d ", r->data);
        r = r->next;
    }
    printf("\n");

    //删除值为x结点
    delete_x_NO_RECUR(head, 4);

    r = head -> next;
    // 遍历链表
    while (r != NULL)
    {
        printf("%d ", r->data);
        r = r->next;
    }

    printf("\n");
    system("pause");
}
Ⅲ、Demo 3:删除最小值

1)描述:

  • 在带头结点的单链表L中,删除一个最小值结点的高效算法(假设最小值结点唯一)

2)算法思想:

  • 定义一个current,pre,pre一直指向current
  • 定义一个min,minpre,minpre一直指向min
  • 删除最小结点时,通过minpre来删除min结点
void delete_min(LNode *head)
{

    if (head == NULL)
    {
        return;
    }

    LNode *pre = head, *current = pre->next;
    LNode *minPre = pre, *min = current;

    //找最小值
    while (current != NULL)
    {
        if (current->data < min->data)
        {
            minPre = pre;
            min = current;
        }

        pre = current;
        current = current->next;
    }
    minPre -> next = min->next;
    free(min);
}
int main()
{
    int i;
    LNode *r = NULL; //指向链表队尾的指针
    LNode *head = (LNode *)malloc(sizeof(LNode));
    r = head;

    for (i = 1; i < 3; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = 1;
            r->next = node;
            r = node;
        }
    }

    for (i = 1; i < 2; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = -1;
            r->next = node;
            r = node;
        }
    }

    for (i = 1; i < 4; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = 9;
            r->next = node;
            r = node;
        }
    }

    r->next = NULL;

    r = head->next;
    // 遍历链表
    while (r != NULL)
    {
        printf("%d ", r->data);
        r = r->next;
    }
    printf("\n");

    //删除值为x结点
    delete_min(head);

    r = head->next;
    // 遍历链表
    while (r != NULL)
    {
        printf("%d ", r->data);
        r = r->next;
    }

    printf("\n");
    system("pause");
}
5、插入操作(头插/尾插)
Ⅰ、Demo 1:就地逆置

1)描述:

  • 将带头结点的单链表就地逆置,辅助空间为O(1)

2)算法思想:

  • 初始时头指针和第一个结点作为一个整体
  • 定义一个current,r指针,将该结点通过头插法插入
void reverse_List(LNode *head)
{

    if (head == NULL)
    {
        return;
    }

    //若只有一个结点,无需逆置
    if(head -> next == NULL || head -> next -> next == NULL){
        return;
    }

    LNode *current = head -> next -> next; //current初始时指向第二个结点
    LNode *r; //current的下一个结点
    head->next -> next = NULL;

    while (current != NULL)
    {
        r = current -> next;
        current->next = head->next;
        head->next = current;
        current = r;
    }
}
int main()
{
    int i;
    LNode *r = NULL; //指向链表队尾的指针
    LNode *head = (LNode *)malloc(sizeof(LNode));
    r = head;

    for (i = 1; i < 3; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = 1;
            r->next = node;
            r = node;
        }
    }

    for (i = 1; i < 2; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = -1;
            r->next = node;
            r = node;
        }
    }

    for (i = 1; i < 4; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = 9;
            r->next = node;
            r = node;
        }
    }

    r->next = NULL;

    r = head->next;
    // 遍历链表
    while (r != NULL)
    {
        printf("%d ", r->data);
        r = r->next;
    }
    printf("\n");

    //删除值为x结点
    reverse_List(head);

    r = head->next;
    // 遍历链表
    while (r != NULL)
    {
        printf("%d ", r->data);
        r = r->next;
    }

    printf("\n");
    system("pause");
}
Ⅱ、Demo 2:元素递增

1)描述:

  • 有一个带头结点的单链表L,设计一个算法使其元素递增有序

2)算法思想:

  • 使用头插法实现插入排序,具体步骤如下
  • 初始时头节点和第一个结点构成有序序列A,其余部分为无序序列B
  • 定义一个index,每次将B中的第一个结点插入到A中的index位置
  • 直至遍历完B中所有结点则结束
void InsertSort(LNode *head)
{

    if (head == NULL)
    {
        return;
    }

    //若只有一个结点,无需排序
    if (head->next == NULL || head->next->next == NULL)
    {
        return;
    }

    LNode *pre = head -> next;  //current的前一个结点,及A的尾结点
    LNode *current = head->next->next; //current初始时指向第二个结点
    LNode *r;                          //current的下一个结点
    pre ->next = NULL;

    LNode *index; //插入的位置
    while (current != NULL)
    {
        r = current->next;
        index = head;
        //B的第一个结点比A尾结点小,遍历A
        if(current -> data < pre -> data){
            
            while(index != NULL){
                if(current -> data < index -> next -> data){
                    break;
                }
                index = index -> next;
            }

            current -> next = index -> next;
            index -> next = current;
        }
        //B的第一个结点比A尾结点大,不用遍历A,直接将B接到A尾部
        else{
            pre -> next = current;
            current -> next = NULL;
        }
        pre = current;  //注:不要忘了三个指针的同步
        current = r;
    }
}
int main()
{
    int i;
    LNode *r = NULL; //指向链表队尾的指针
    LNode *head = (LNode *)malloc(sizeof(LNode));
    r = head;

    // for (i = 10; i > 0; --i)
    // {
    //     LNode *node = (LNode *)malloc(sizeof(LNode));
    //     if (node != NULL)
    //     {
    //         node->data = i;
    //         r->next = node;
    //         r = node;
    //     }
    // }
    for (i = 1; i <= 10; ++i)
    {
        LNode *node = (LNode *)malloc(sizeof(LNode));
        if (node != NULL)
        {
            node->data = i;
            r->next = node;
            r = node;
        }
    }
    r->next = NULL;

    r = head->next;
    // 遍历链表
    while (r != NULL)
    {
        printf("%d ", r->data);
        r = r->next;
    }
    printf("\n");

    //删除值为x结点
    InsertSort(head);

    r = head->next;
    // 遍历链表
    while (r != NULL)
    {
        printf("%d ", r->data);
        r = r->next;
    }

    printf("\n");
    system("pause");
}
Ⅲ、Demo 3:两链表交集

1)描述:

  • 已知两个链表A,B分别为两个集合,其元素递增排列,编制函数
  • 求A与B的交集,并存于A链表中

2)算法思想:

  • 定义指针p,q,初始时分别指向A,B的表头第一个结点
  • p,q先比较值的大小,小的结点指针先移动,大的结点指针固定
  • 若p,q在比较过程中值相等,则头插法插入A中
  • 若有一个链表到头了,则结束
LNode *getUnion(LNode *headA, LNode *headB)
{

    if (headA == NULL || headB == NULL)
    {
        return NULL;
    }

    if (headA->next == NULL || headB->next == NULL)
    {
        return NULL;
    }

    LNode *p = headA->next, *q = headB->next;
    LNode *r = q->next; //q的后一个结点,方便q插入到A中
    LNode *u; //用来删除A或B中移动后的结点
    headA->next = NULL;
    free(headB);
    while (p != NULL && q != NULL)
    {
        //B结点头插法到A
        if (p->data == q->data)
        {
            q->next = headA->next;
            headA->next = q;
            q = r;
            //这里q和r要保持同步!!!
            if (r != NULL)
            {
                r = r->next;
            }
        }
        //A结点小,p移动
        else if (p->data < q-> data)
        {
            u = p;
            p = p->next;
            free(u);
        }
        //B结点小,q移动
        else
        {
            u = q;
            q = r;
            if (r != NULL)
            {
                r = r->next;
            }
            free(u);
        }
    }

    return headA;
}

int main()
{
    int i;
    LNode *r1 = NULL, *r2 = NULL; //指向链表队尾的指针
    LNode *head1 = (LNode *)malloc(sizeof(LNode));
    LNode *head2 = (LNode *)malloc(sizeof(LNode));
    r1 = head1, r2 = head2;

    //建立链表A
    LNode *node1 = (LNode *)malloc(sizeof(LNode));
    node1->data = 1;
    LNode *node2 = (LNode *)malloc(sizeof(LNode));
    node2->data = 2;
    LNode *node3 = (LNode *)malloc(sizeof(LNode));
    node3->data = 4;
    LNode *node4 = (LNode *)malloc(sizeof(LNode));
    node4->data = 6;
    LNode *node5 = (LNode *)malloc(sizeof(LNode));
    node5->data = 9;
    head1->next = node1;
    node1->next = node2;
    node2->next = node3;
    node3->next = node4;
    node4->next = node5;
    node5->next = NULL;

    //建立链表B
    LNode *node6 = (LNode *)malloc(sizeof(LNode));
    node6->data = 6;
    LNode *node7 = (LNode *)malloc(sizeof(LNode));
    node7->data = 7;
    LNode *node8 = (LNode *)malloc(sizeof(LNode));
    node8->data = 8;
    LNode *node9 = (LNode *)malloc(sizeof(LNode));
    node9->data = 9;
    LNode *node10 = (LNode *)malloc(sizeof(LNode));
    node10->data = 10;
    head2->next = node6;
    node6->next = node7;
    node7->next = node8;
    node8->next = node9;
    node9->next = node10;
    node10->next = NULL;

    r1 = head1->next, r2 = head2->next;
    //遍历链表
    while (r1 != NULL)
    {
        printf("%d ", r1->data);
        r1 = r1->next;
    }
    printf("\n");
    // 遍历链表
    while (r2 != NULL)
    {
        printf("%d ", r2->data);
        r2 = r2->next;
    }
    printf("\n");

    r1 = getUnion(head1, head2);
    // 遍历链表
    while (r1 -> next!= NULL)
    {
        r1 = r1->next;
        printf("%d ", r1->data);
    }
    printf("\n");

    system("pause");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值