删除首元结点的算法步骤

昨天研究了链队列的入队操作,那么现在再来看看链队列的出队操作吧。

  • 出队操作时,就是头结点的后继结点出队,将头结点的后继改为它后面的结点,若链表除头结点外只剩一个元素时,则需将rear指向头结点。还是画个图理解一下吧。

一般情况下,链队列的出队图示:老品牌娱乐城

如果链队列只剩下一个元素的时候,出队则如下图:

具体步骤如下:

  1. 如图中,要删除掉a1结点,思路很简单,就是让头结点Q->front的后继next直接指向a2。但是a2如何标识呢?
  2. 假设a1结点为p结点,那么a2就是p->next了。如何让a1结点存到p呢?
  3. 直接让头结点的后继指向p就行,p=Q->front->next;
  4. 假如队尾已经是p结点的话(Q->rear==p),队尾指针需要指向头结点Q->rear=Q->front;
  5. 最后别忘了把p free掉。

链队列的出队操作函数设计为:

/* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
Status DeQueue(LinkQueue *Q,QElemType *e)
{
	QueuePtr p;
	if(Q->front==Q->rear)
		return ERROR;
	p=Q->front->next;		/* 将欲删除的队头结点暂存给p */
	*e=p->data;				/* 将欲删除的队头结点的值赋值给e */
	Q->front->next=p->next;/* 将原队头结点的后继p->next赋值给头结点后继 */
	if(Q->rear==p)		/* 若队头就是队尾,则删除后将rear指向头结点 */
		Q->rear=Q->front;
	free(p);
	return OK;
}

下面是完整的可执行程序:

#include "stdio.h"
#include "stdlib.h"
#include "io.h"
#include "math.h"
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /* 存储空间初始分配量 */

typedef int Status;
/* QElemType类型根据实际情况而定,这里假设为int */
typedef int QElemType;

typedef struct QNode	/* 结点结构 */
{
    QElemType data;
    struct QNode *next;
} QNode,*QueuePtr;

typedef struct			/* 队列的链表结构 */
{
    QueuePtr front,rear; /* 队头、队尾指针 */
} LinkQueue;

/* 构造一个空队列Q */
Status InitQueue(LinkQueue *Q)
{
    Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));
    if(!Q->front)
        exit(OVERFLOW);
    Q->front->next=NULL;
    return OK;
}

/* 从队头到队尾依次对队列Q中每个元素输出 */
Status QueueTraverse(LinkQueue Q)
{
    QueuePtr p;
    p=Q.front->next;
    while(p)
    {
        visit(p->data);
        p=p->next;
    }
    printf("\n");
    return OK;
}

Status visit(QElemType c)
{
    printf("%d ",c);
    return OK;
}

/* 插入元素e为Q的新的队尾元素 */
Status EnQueue(LinkQueue *Q,QElemType e)
{
    QueuePtr s=(QueuePtr)malloc(sizeof(QNode));
    if(!s) /* 存储分配失败 */
        exit(OVERFLOW);
    s->data=e;
    s->next=NULL;
    Q->rear->next=s;	/* 把拥有元素e的新结点s赋值给原队尾结点的后继,见图中① */
    Q->rear=s;		/* 把当前的s设置为队尾结点,rear指向s,见图中② */
    return OK;
}

/* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
Status DeQueue(LinkQueue *Q,QElemType *e)
{
	QueuePtr p;
	if(Q->front==Q->rear)
		return ERROR;
	p=Q->front->next;		/* 将欲删除的队头结点暂存给p,见图中① */
	*e=p->data;				/* 将欲删除的队头结点的值赋值给e */
	Q->front->next=p->next;/* 将原队头结点的后继p->next赋值给头结点后继,见图中② */
	if(Q->rear==p)		/* 若队头就是队尾,则删除后将rear指向头结点,见图中③ */
		Q->rear=Q->front;
	free(p);
	return OK;
}

int main()
{
    int i, j, opp;
    QElemType d;
    LinkQueue q;
    InitQueue(&q);

    printf("\n1.给队列赋初始值 \n2.遍历队列 \n3.入队 \n4.出队");
    printf("\n0.退出 \n请选择你的操作:\n");
    while(opp != ‘0‘)
    {
        scanf("%d",&opp);
        switch(opp)
        {
        case 1:
            srand(time(0));
            for(j=1; j<=10; j++)
            {
                d = rand()%100+1;
                EnQueue(&q,d);
            }
            QueueTraverse(q);
            break;

        case 2:
            QueueTraverse(q);
            break;

        case 3:
            printf("请输入需要入队的元素:");
            scanf("%d", &d);
            EnQueue(&q,d);
            QueueTraverse(q);
            break;

        case 4:
            DeQueue(&q,&d);
            printf("删除的元素值为%d\n",d);
            break;

        case 0:
            exit(0);
        }
    }

    return 0;
}
时间: 2024-11-02 06:22:39

删除首元结点的算法步骤的相关文章

单链表的头指针、头结点与首元结点

继续我们昨天所说的单链表.单链表也是一种线性表,所以总得有个头有个尾.链表中第一个结点的存储位置叫做头指针,那么整个链表的存取就必须是从头指针开始进行了.之后的每一个结点,其实就是上一个的后继指针指向的位置.雅加达娱乐城 这里有个地方要注意,就是对头指针概念的理解,这个很重要.“链表中第一个结点的存储位置叫做头指针”,如果链表有头结点,那么头指针就是指向头结点数据域的指针.画一个图吧. 这个图看起来很清晰了.比如说头结点,我们就可以这么描述了: 头结点是为了操作的统一与方便而设立的,放在第一个元

链表总的首元结点、头结点、头指针的区别

前言,:今天看书的时候,又复习了一下链表的知识点,但是标题上这个知识点老是弄混淆,所以接下来做一个小小的总结,给自己加深理解. 一.三者的基本概念; 1.首元结点:就是指链表中存储第一个数据元素a1的结点,如下表格所示结点ZHAO就是首元结点: L-----> 数据域和指针域-----> ZHAO+指针域---->   2.头结点:它是在首元结点之前附设的一个节点,其指针域指向首元结点.头结点的数据域可以不存储任何信息,也可以存储与数据元素类型的其他附加信息,例如,当数据元素为整数型时,

软考题目之头结点、头指针和首元节点

遇到一个让人迷惑的题目. 以下关于线性表采用链式存储时删除节点运算的描述,正确的是() A.带头结点的线性链表删除结点时,不需要更改头指针. B.带头结点的线性链表删除第一个结点时,需要更改头指针. C.不带头结点的线性链表删除结点时,需要更改头指针. D.不带头结点的线性链表删除第一个结点时,不需要更改头指针. 首先,明确几个概念. 首元结点:指链表中存储第一个数据元素a1的结点. 头结点:是为了操作方便在首元结点前复设的结点. 头指针:指向链表中第一个结点(或为头结点或为首元结点)的指针.

【LeetCode-面试算法经典-Java实现】【083-Remove Duplicates from Sorted List(排序的单链表中删除重复的结点)】

[083-Remove Duplicates from Sorted List(排序的单链表中删除重复的结点)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given a sorted linked list, delete all duplicates such that each element appear only once. For example, Given 1->1->2, return 1->2. Given 1->1->2

第1章第2节练习题4 删除指定区间结点

问题描述 设一个带表头结点的单链表中所有元素结点的数据值无序,试编写一个函数,删除表中所有其值在给定值s与t之间(包含s和t,要求s<t)的所有结点 算法思想 因为链表逻辑上无序,删除指定区间结点的前提是找到这些指定区间结点.因此从头节点开始对整个链表进行一次遍历,若找到满足题意的结点,删除即可. 算法描述 void Delts(LNode* head, ElemType t, ElemType s) { LNode *pre=head; LNode *p=head->next; while(

两种删除单链表结点的实现,一种O(n),一种O(1)

常规的删除单链表结点的做法是挨个查找到该结点的前一个结点,然后去掉要删除的这个结点,回收内存.这个需要O(n)的时间. 有一种比较快速的删除掉链表指定一个节点的方法,就是把下一个结点的内容复制到当前这个结点,然后把下一次结点删除掉,这个需要考虑当要删除的结点是最后一个结点的情况. 如果刚好是最后一个结点,则需要O(n)的时间,如果不是最后一个结点,可以在O(1)时间内完成删除操作. 1 // 2 // main.c 3 // SingleListDeleteNode 4 // 5 // Crea

时间复杂度分别为 O(n)和 O(1)的删除单链表结点的方法

有一个单链表,提供了头指针和一个结点指针,设计一个函数,在 O(1)时间内删除该结点指针指向的结点. 众所周知,链表无法随机存储,只能从头到尾去遍历整个链表,遇到目标节点之后删除之,这是最常规的思路和做法. 如图所示,删除结点 i,那么只需找到 i 的前驱 h,然后连 h 到 j,再销毁i 即可.虽然可以安全的删除 i 结点,但是是顺序查找找到 i,之后删除,时间复杂度是 O(n)级别的.具体做法就是:顺序查找整个单链表,找到要删除结点 i 的直接前驱 h,把 h额 next 指向i 的 nex

在O(1)时间内删除单链表结点

// 在O(1)时间内删除单链表结点 /* 思考: 很显然链表是一个节点地址不连续的存储结构 删除节点一般很容易会想到是修改p节点的前一个节点的next为p->next 然而除非是双向链表,否则无法在常量级的时间里找到p的前节点 转变思路: 既然改变不了p前节点的next 只能在p 本身动手脚 那可以考虑修改p->data 使得p->data的值为p->next->data的值,同样可以达到效果 */ #include <iostream> #include &l

SQL Server触发器创建、删除、修改、查看示例步骤

SQL Server触发器创建.删除.修改.查看示例步骤 一﹕ 触发器是一种特殊的存储过程﹐它不能被显式地调用﹐而是在往表中插入记录﹑更新记录或者删除记录时被自动地激活.所以触发器可以用来实现对表实施复杂的完整性约`束. 二﹕ SQL Server为每个触发器都创建了两个专用表﹕Inserted表和Deleted表.这两个表. 一﹕ 触发器是一种特殊的存储过程﹐它不能被显式地调用﹐而是在往表中插入记录﹑更新记录或者删除记录时被自动地激活.所以触发器可以用来实现对表实施复杂的完整性约`束.