Datenstruktur – Grundkonzept und Anwendung der Warteschlange

​ Stapel und Warteschlangen sind zwei wichtige lineare Strukturen. Aus Sicht der Datenstruktur sind Stapel und Warteschlangen ebenfalls lineare Tabellen. Die Besonderheit besteht darin, dass die Grundoperationen von Stapeln und Warteschlangen eine Teilmenge linearer Tabellenoperationen sind. Es handelt sich um lineare Tabellen mit begrenzten Operationen. Daher können sie als begrenzt bezeichnet werden Daten. Struktur.

​ Andererseits sind Stapel und Warteschlangen aus Sicht der Datentypen zwei wichtige abstrakte Datentypen, die sich deutlich von linearen Tabellen unterscheiden. Und Stapel und Warteschlangen werden aufgrund ihrer Eigenschaften häufig in verschiedenen Softwaresystemen verwendet, und das Erlernen dieser Eigenschaften ist für uns eine große Hilfe. Daher werden in diesem Artikel nicht nur die Definition, Darstellung und Implementierung von Stapeln und Warteschlangen erläutert, sondern auch einige Anwendungsbeispiele aufgeführt.

Im vorherigen Artikel haben wir das Konzept des Stapels besprochen. In diesem Artikel werden wir uns weiterhin mit der Warteschlange befassen.

1. Das Grundkonzept der Warteschlange

​Definition der Warteschlange : Eine Warteschlange wird kurz Team genannt und ist auch eine lineare Tabelle mit eingeschränkten Operationen. Sie ist darauf beschränkt, nur das Einfügen an einem Ende der Tabelle und das Löschen am anderen Ende der Tabelle zuzulassen. Das Ende, das eingefügt werden kann, wird als Schwanz (Hinten) bezeichnet, und das Ende, das gelöscht werden kann, wird als Vorderseite (Vorderseite) bezeichnet.

Ressourcenzuteilungskarte

​Eigenschaften der Warteschlange : Die Eigenschaften der Warteschlange können als First in First out (FIFO) zusammengefasst werden.

​ Warteschlangen kommen in unserem Leben häufiger vor. Beispielsweise stehen wir oft Schlange, um Dinge zu kaufen, und warten auf die Warteschlange für den Ticketkauf 12306; wenn ein Zug in einen Tunnel einfährt, ist jeder Wagen ein Teil des Teams und der erste Wagen dazu enter ist immer der erste, der den Tunnel verlässt.

Ressourcenzuteilungskarte

2. Die Speicherstruktur der Warteschlange

Es gibt zwei Hauptspeicherstrukturen für Warteschlangen: sequentielle Warteschlangen und Kettenwarteschlangen. Die Definition der sequentiellen Warteschlange lautet wie folgt: Es ist ersichtlich, dass der Kern der sequentiellen Warteschlange ein kontinuierlicher Speicherplatz ist, der hier mithilfe eines Arrays implementiert wird.

typedef struct {
    
    
  //用于存放队列中的元素
  int data[maxSize];
  //队首指针
  int front;
  //队尾指针
  int rear;
} SqQueue;		

​ Das Kettenteam ist wie folgt definiert: Es ist ersichtlich, dass das Kettenteam eine verknüpfte Liste zum Speichern des Stapels verwendet und die Tail-Insert-Methode zum Erstellen eines Teams verwendet. Die Definition des Kettenteams ist komplizierter und gliedert sich in zwei Teile: Teamknoten und Kettenteam:

//队结点
typedef struct QNode {
    
    
  //数据域
  int data;
  //指针域
  struct QNode * next;
} QNode;

//链队类型
typedef struct {
    
    
  //队头指针
  struct QNode * front;
  //队尾指针
  struct QNode * rear;
} LiQueue;
Ressourcenzuteilungskarte

Für Warteschlangen gibt es auch zwei Speicherstrukturen. Im Allgemeinen wählen wir auch sequentielle Warteschlangen.

Hinweis: An einigen Stellen wird beim Definieren der Warteschlange aus Gründen der Speicherfreundlichkeit ein Kopfknoten zum Kettenteam hinzugefügt, und der Kopfzeiger zeigt auf den Kopfknoten . Zu diesem Zeitpunkt lautet die Beurteilungsbedingung der leeren Warteschlange, dass sowohl der Kopfzeiger als auch der Schwanzzeiger auf den Kopfknoten zeigen (der Schwanzzeiger zeigt auf den Kopfknoten, da der vordere Punkt unverändert bleibt). Die Speicherstruktur ist in der folgenden Abbildung dargestellt:

Ressourcenzuteilungskarte

3. Definition und Grundoperationen sequentieller Warteschlangen

3.1 Zirkuläre Warteschlange

Ähnlich wie beim sequentiellen Stapel gibt es in der sequentiellen Speicherstruktur der Warteschlange zusätzlich zur Verwendung einer Gruppe von Speichereinheiten mit fortlaufenden Adressen zum sequentiellen Speichern der Elemente vom Kopf der Warteschlange bis zum Ende der Warteschlange zwei Zeiger vorne und hinten müssen angehängt werden, um die Elemente an der Spitze der Warteschlange bzw. die Position des Endelements der Warteschlange anzuzeigen. Zur Vereinfachung der Beschreibung in der C-Sprache stimmen wir hier überein: Bei der Initialisierung einer leeren Warteschlange sei front=rear=0, jedes Mal, wenn ein neues Warteschlangenendelement eingefügt wird, wird der „Endzeiger um 1 erhöht“; jedes Mal, wenn ein Warteschlangenkopfelement eingefügt wird gelöscht wird, „der Kopfzeiger wird um 1 erhöht“. Daher zeigt in einer nicht leeren Warteschlange der Kopfzeiger immer auf das Kopfelement der Warteschlange und der Endzeiger immer auf die
nächste Position des Endelements der Warteschlange, wie in der folgenden Abbildung dargestellt.

Ressourcenzuteilungskarte

Unter der Annahme, dass der der Warteschlange derzeit maximal zugewiesene Speicherplatz 6 beträgt, können keine neuen Elemente am Ende der Warteschlange eingefügt werden, wenn sich die Warteschlange im obigen Zustand (d) befindet, da andernfalls eine Ausnahme außerhalb der Grenzen auftritt aufgrund eines Arrays außerhalb der Grenzen. Zu diesem Zeitpunkt ist es jedoch nicht angebracht, den Speicher neu zu verteilen, um den Array-Speicherplatz wie beim sequentiellen Stapel zu erweitern, da der tatsächlich verfügbare Speicherplatz der Warteschlange nicht voll ist. Eine raffiniertere Möglichkeit besteht darin, die sequentielle Warteschlange als kreisförmigen Raum zu konstruieren, wie in der folgenden Abbildung gezeigt, der als kreisförmige Warteschlange bezeichnet wird .

Ressourcenzuteilungskarte

​ Stellen Sie sich vor, das Array „verwandelt“ sich in einen Ring und lässt die Vorder- und Rückseite entlang des Rings laufen, sodass es niemals zu einer Situation kommt, in der die beiden das Ende des Arrays erreichen und nicht weiter nach unten gehen können. Dies ist ein Kreis Warteschlange. Die kreisförmige Warteschlange ist eine verbesserte sequentielle Warteschlange. Der Ein- und Ausgang von Elementen ist in der folgenden Abbildung dargestellt:

Ressourcenzuteilungskarte

​ In der obigen Abbildung sind der Fortschritt der Warteschlange und die Änderung der Warteschlange wie folgt:

① Geben Sie zwei Elemente aus dem leeren Team ein. Zu diesem Zeitpunkt zeigt die Vorderseite auf 0 und die Rückseite auf 2.

② Geben Sie 4 Elemente ein und lassen Sie 3 Elemente übrig. Zu diesem Zeitpunkt zeigt die Vorderseite auf 3 und die Rückseite auf 6.

③ 2 Elemente betreten die Warteschlange und 4 Elemente verlassen die Warteschlange. Zu diesem Zeitpunkt zeigt die Vorderseite auf 7 und die Rückseite auf 0.

​ Aus dem Änderungsprozess von ① zu ③ ist ersichtlich, dass nach dem Ein- und Austritt von Elementen die Elemente weiterhin fortgesetzt werden können, auch wenn die Rückseite und die Vorderseite das Ende des Arrays erreicht haben (wie in ③ in der Abbildung dargestellt). um in die Warteschlange einzutreten, da die beiden Zeiger nicht entlang einer geraden Linie laufen, während der Array-Index zunimmt, läuft er entlang eines Rings und kehrt automatisch zur Startposition des Arrays zurück, wenn er das Ende des Arrays erreicht.

Aus der obigen Analyse können wir auch erkennen, dass gewöhnliche sequentielle Warteschlangen fehlerhaft sind, sodass wir bei der tatsächlichen Verwendung kreisförmige Warteschlangen verwenden werden. Bei den sequentiellen Warteschlangen, die wir später besprechen werden, handelt es sich hauptsächlich um kreisförmige Warteschlangen. Um sicherzustellen, dass die Warteschlange leer oder voll ist, muss die kreisförmige Warteschlange Speicherplatz opfern.

3.2 Elemente kreisförmiger Warteschlangen

Die kreisförmige Warteschlange qu besteht außerdem aus vier Elementen, nämlich zwei Sonderzuständen: leer und voll ; zwei Operationen: Eintreten und Verlassen der Warteschlange .

​Warteschlange leerer Status : qu.rear == qu.front

​Warteschlangen- Vollstatus : (qu.rear+1)%maxSize == qu.front

​Enqueue- Vorgang :qu.data[qu.rear]=x; qu.rear = (qu.rear+1)%maxSize;

​Dequeue- Vorgang :x = qu.data[qu.front]; qu.front = (qu.front+1)%maxSize;

​ Hinweis: Der obige Code dient dazu, zuerst die Daten zu verarbeiten und den Zeiger beim Betreten und Verlassen der Warteschlange zu bewegen; es kann andere Befehle geben, diese sind jedoch im Wesentlichen gleich.

3.3 Grundlegende Funktionsweise der zirkulären Warteschlange

​Initialisieren Sie die Warteschlange

void initQueue(SqQueue *qu){
    
    
  qu->front = qu->rear = 0;
}

​Stellen Sie fest , ob das Team leer ist

//如果为空,返回1,否则返回0
int isEmpty(SqQueue qu){
    
    
    if(qu.rear == qu.front){
    
    
        return 1;
    }
    return 0;
}

​In den Warteschlangenvorgang

int enQueue(SqQueue *qu, int x){
    
    
    if((qu->rear+1)%maxSize == qu->front){
    
    
        printf("队满,无法入队!");
        return 0;
    }
    qu->data[qu->rear] = x;
    qu->rear = (qu->rear+1) % maxSize;
    return 1;
}

​Dequeue- Vorgang

int deQueue(SqQueue *qu, int *x){
    
    
    if(qu->rear == qu->front){
    
    
        printf("队空,无法出队!");
        return 0;
    }
    *x = qu->data[qu->front];
    qu->front = (qu->front+1) % maxSize;
    return 1;
}

​ In der Prüfung wird das Team im Allgemeinen als Hilfsstruktur zur Lösung anderer Probleme verwendet, sodass die Definition und Funktionsweise des Teams im Allgemeinen sehr einfach geschrieben werden kann, wie zum Beispiel:

//两句话定义一个队
int queue[maxSize];
int front = rear = 0;
//入队
queue[rear] = x;
rear = (rear + 1) % maxSize;

//出队
x = queue[front];
front = (fron + 1) % maxSize;

4. Definition und grundlegende Funktionsweise des Kettenteams

4.1 Elemente des Kettenteams

​ Für das Kettenteam lqu gibt es außerdem vier Elemente, nämlich zwei Sonderzustände: Das Team ist leer und das Team ist voll . Zwei Vorgänge: Betreten des Teams und Verlassen des Teams .

​Leere Warteschlange : lqu->rear == NULL oder lqu->front == NULL, was anzeigt, dass der Stapel leer ist.

​Warteschlange voll : Unter normalen Umständen liegt keine volle Warteschlange vor (es sei denn, der Speicher reicht nicht aus und es können keine neuen Knoten beantragt werden).

Enqueue -Operation : Der Zeiger p zeigt auf den Knoten, auf dem sich das Element befindet, und der Knoten wird mithilfe der Tail-Insert-Methode eingefügt.

//尾插法
lqu->rear->next = p;
lqu->rear = p;

​Dequeue- Vorgang : Das entnommene Element wird in x gespeichert

//p指向出栈结点
p = lqu->front;
x = p->data;
//队首指针指向下一个结点
lqu->front = p->next;
free(p);

​ Das dynamische schematische Diagramm des Einreihungs- und Entnahmevorgangs sieht wie folgt aus:

Ressourcenzuteilungskarte

4.2 Grundlegende Funktionsweise des Kettenteams

​Initialisieren Sie die Warteschlange

void InitLinkedQueue(LiQueue *lqu){
    
    
    lqu = (LiQueue *) malloc(sizeof(LiQueue));
    lqu -> front =NULL;
    lqu -> rear = NULL;
}

​Stellen Sie fest , ob das Team leer ist

int isLinkedEmpty(LiQueue lqu){
    
    
    if(lqu.rear == NULL || lqu.rear == NULL){
    
    
        return 1;
    }
    return 0;
}

​Enqueue- Vorgang

void enLinkedQueue(LiQueue *lqu, int x){
    
    
    //创建一个节点p
    QNode *p = (QNode *) malloc(sizeof(QNode));
    p->data = x;
    p->next = NULL;
    
    //需要判断队列是否为空,如果为空,需要同时修改front指针的值
    if(lqu->rear == NULL){
    
    
        lqu->rear = lqu ->front = p;
    } else{
    
    
        lqu->rear->next = p;
        lqu->rear = p;
    }
}

​Dequeue- Vorgang

int deLinkedQueue(LiQueue *lqu, int *x){
    
    
    if(lqu->rear == NULL){
    
    
        printf("队空,无法出队!");
        return 0;
    }
    QNode *p = lqu->front;
    //如果队中只有一个结点,需要同时修改rear指针的值
    if(lqu->front == lqu->rear){
    
    
        lqu->rear = lqu ->front = NULL;
    } else{
    
    
        lqu->front = p->next;
    }
    *x = p->data;
    free(p);
    return 1;
}

​Hauptfunktionstestcode

int main(int argc, const char * argv[]) {
    
    
    // insert code here...
    LiQueue lqu;
  	int x;
    InitLinkedQueue(&lqu);
    printf("st.top:%d\n", lqu.front);
    printf("Queue is Empty:%d\n", isLinkedEmpty(lqu));
    enLinkedQueue(&lqu, 1);
    enLinkedQueue(&lqu, 2);
    enLinkedQueue(&lqu, 3);
    printf("Queue is Empty:%d\n", isLinkedEmpty(lqu));
    deLinkedQueue(&lqu, &x);
    printf("出队的元素为:%d\n", x);
    deLinkedQueue(&lqu, &x);
    printf("出队的元素为:%d\n", x);
    deLinkedQueue(&lqu, &x);
    printf("出队的元素为:%d\n", x);
}

5. Doppelendige Warteschlange

Eine doppelendige Warteschlange ist eine lineare Liste, in der an beiden Enden Einfügungs- und Löschvorgänge ausgeführt werden können. Eine doppelendige Warteschlange kann man sich als zwei Stapel vorstellen, die am unteren Ende des Stapels miteinander verbunden sind. Im Gegensatz zum gemeinsam genutzten Stapel erstrecken sich die oberen Zeiger der beiden Stapel bis zu beiden Enden. Da die doppelendige Warteschlange das Einfügen und Löschen von Elementen an beiden Enden ermöglicht, müssen zwei Zeiger eingerichtet werden: end1 und end2, die jeweils auf die Elemente an beiden Enden der doppelendigen Warteschlange zeigen.

Ressourcenzuteilungskarte

Eine doppelendige Warteschlange, die das Einfügen und Löschen an einem Ende und nur das Löschen am anderen Ende zulässt, wird als eingabebeschränkte doppelendige Warteschlange bezeichnet, wie auf der linken Seite der Abbildung unten dargestellt; eine doppelendige Warteschlange, die das Einfügen ermöglicht und Löschen an einem Ende und nur Einfügen am anderen Ende. Die Warteschlange wird als ausgangsbegrenzte doppelendige Warteschlange bezeichnet, wie auf der rechten Seite der folgenden Abbildung dargestellt.

Ressourcenzuteilungskarte

​ Die grundlegende Funktionsweise der Double-Ended-Warteschlange kann sich auf die folgenden Fragen beziehen:

Beispiel: Eine Warteschlange erlaubt Enqueue-Operationen an beiden Enden der Warteschlange, erlaubt aber nur Dequeue-Operationen an einem Ende. Wenn die Elemente a, b, c, d, e nacheinander in diese Warteschlange gelangen und dann Dequeue-Operationen ausführen, ist es unmöglich, sie abzurufen Die Dequeue-Sequenz von ist ().
A. b, a, c, d, e B. d, b, a, c, e
C. d, b, c, a, e D. e, c, b, a, d

Antwort: C.

6. Zusammenfassung

Das Konzept und die Funktionsweise des Stapels sind relativ einfach, er erscheint jedoch häufig als Hilfsstruktur bei der Lösung anderer Probleme, z. B. der Ebenendurchquerung des Binärbaums usw.

Und die Warteschlange ist eine sehr weit verbreitete Datenstruktur. In unserer zukünftigen Programmierung ist die Häufigkeit der Verwendung sehr hoch. Stellen Sie sicher, dass Sie mit den Eigenschaften des Teams vertraut sind und diese bei der Lösung spezifischer Probleme sinnvoll nutzen.

Übungsfragen zu Stapeln und Warteschlangen finden Sie in diesem Artikel .

Referenz:

1. Grundlagen der C-Sprachprogrammierung in der Datenstruktur

2. Datenstruktur für die postgraduale Aufnahmeprüfung

3. Highscore-Notizen zur Datenstruktur

4. Königliche Datenstruktur

5. Datenstruktur – C-Sprachversion, Yan Weimin


​ Es liegt wieder unter der Trennlinie und dieser Artikel ist zu Ende. Der Inhalt dieses Artikels wurde vollständig vom Blogger nach seinem eigenen Verständnis und den Materialien für die Postgraduierten-Aufnahmeprüfung zusammengestellt. Er dient nur als Referenz. Wenn Sie Fragen haben, wenden Sie sich bitte an uns. Sie können im Kommentarbereich eine Nachricht hinterlassen. Wenn Sie Fehler haben, kritisieren und korrigieren Sie diese bitte.

​ In dieser Kolumne geht es um Datenstrukturwissen. Wenn es Ihnen gefällt, können Sie weiterhin aufmerksam sein. Wenn dieser Artikel für Sie hilfreich ist, liken Sie ihn bitte auch, kommentieren Sie ihn und achten Sie darauf.

Wenn Sie Fragen haben, können Sie im Kommentarbereich eine Nachricht hinterlassen.

Supongo que te gusta

Origin blog.csdn.net/qq_34666857/article/details/121455479
Recomendado
Clasificación