文章目錄
- 線性表的基本概念
-
- <1>定義
- <2>性質
- 線性表的順序存儲結構
-
- 1.基本概念
- 2.設計與實作
- 3.優點和缺點
線性表的基本概念
<1>定義
線性表是0個或者多個資料元素的集合
線性表中的資料元素之間是有序的
線性表中的資料元素個數是有限的
線性表中的資料元素類型必須相同
<2>性質
a0為線性表的第一個元素,隻有一個後繼
an為線性表的最後一個元素,隻有一個前驅
除這二者外的其他元素ai,既有前驅,又有後繼
線性表能夠逐項和順序存取
線性表的順序存儲結構
1.基本概念
線性表的順序存儲結構,指的是用一段位址連續的存儲單元依次存儲線性表的資料元素
2.設計與實作
在寫程式之前,先說明一下單連結清單的頭插法和尾插法
頭插法:從一個空表開始,重複讀入資料,生成新的結點,将讀入的資料存放到新的結點的資料域中,然後将新結點插入到目前連結清單的表頭結點之後。
尾插法:從一個空表開始,重複讀入資料,生成新的結點,将讀入的資料存放到新的結點的資料域中,然後将新結點插入到目前連結清單的表尾結點之後。
首先先創造一個整體的架構,先自定一個header檔案,然後把想要實作的方法寫入,然後直接在主程式中導入此頭檔案
header.h
#ifndef CPRIMERPLUS_HEADER_H
#define CPRIMERPLUS_HEADER_H
typedef void SeqList;//聲明一下線性表
typedef void SeqListNode;//聲明組成結點的結構體
SeqList *seqList_Create(int capacity);//建立一張線性表
void SeqList_Destroy(SeqList *list);//銷毀一張線性表
void SeqList_Clear(SeqList *list);//清空結點元素
int SeqList_Length(SeqList *list);//傳回線性表的長度
int SeqList_Insert(SeqList *list,SeqListNode *node,int pos);//向SeqList連結清單pos的位置插入一個結點node
SeqListNode *list_Get(SeqList *list , int pos);//擷取pos位置元素
SeqListNode *list_Delete(SeqList *list,int pos);//删除pos位置元素
#endif //CPRIMERPLUS_HEADER_H
頭檔案總體的思路寫好後,下面再把主程式中的使用寫出來
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "header.h"
typedef struct Teacher{
int age;
char *name;
}Teacher;
int main(){
int ret = 0;
SeqList *list = NULL;
Teacher t1,t2,t3,t4,t5;
t1.age = 30;
t2.age = 31;
t3.age = 32;
t4.age = 33;
t5.age = 34;
list = seqList_Create(10);
ret = SeqList_Insert(list, (SeqListNode *) &t1, 0);//頭插法
ret = SeqList_Insert(list, (SeqListNode *) &t2, 0);
ret = SeqList_Insert(list, (SeqListNode *) &t3, 0);
ret = SeqList_Insert(list, (SeqListNode *) &t4, 0);
ret = SeqList_Insert(list, (SeqListNode *) &t5, 0);
//周遊單連結清單,擷取結點
for (int i = 0; i < SeqList_Length(list); ++i) {
Teacher *t = (Teacher *) list_Get(list, i);
if (t == NULL) {
return 0;
}
printf("t->age:%d", t->age);
}
//删除連結清單中的結點
for (int j = 0; j < SeqList_Length(list); ++j) {
list_Delete(list, 0);
}
system("pause");
}
然後最後再把細節寫好,主要采用的還是頭插法插入。
在同一個directory下建立具體方法的實作即可。
思路:
1.先把連結清單的結構寫好,可以用struct,也可以用typedef struct起别名
typedef struct SeqList{
int length;//連結清單實際長度
int capacity;//配置設定最大的容量
unsigned int *node;//所有的結點所形成的數組
// (動态庫内的結點,有多少配置設定多少,是動态的,是以要用指針指向記憶體空間内的結點)
}tSeqList;
2.在連結清單的create方法中,先讓連結清單初始空間為Nul,然後為其動态配置設定存儲空間,因為我們是動态連結清單,然後配置設定的類型和node的類型一緻即可,配置設定完連結清單的空間後,為配置設定好的空間引入memset方法
void *memset(void *s,int c,size_t n)
總的作用:将已開辟記憶體空間s的首n個位元組的值設為值c。
然後根據capacity配置設定node的空間,方法都是一樣的
最後去給容量和結點賦初值,第一個函數也就寫完了
SeqList *seqList_Create(int capacity){
tSeqList *tmp = NULL;//既可以在棧配置設定記憶體空間,也可以在堆配置設定記憶體空間,但是讓初始的連結清單為空
tmp = (tSeqList *) malloc(sizeof(tSeqList));
if(tmp ==NULL) {
printf("func SeqList_Create error:%d",0);
return NULL;
}
memset(tmp, 0, sizeof(tSeqList));//總的作用:将已開辟記憶體空間tmp的首sizeof(tSeqList)個位元組的值設為值0
// 根據capacity配置設定結點空間
tmp->node = (unsigned int *) malloc(sizeof(unsigned int *) * capacity);
if (tmp->node == NULL) {
printf("func SeqList_Create error:%d",0);
return NULL;
}
tmp->capacity = capacity;
tmp->length = 0;
return tmp;
}
3.下面我們開始寫destroy函數,因為我們之前開辟了兩次記憶體空間(seqlist和node),是以也應該是先釋放後開辟的空間
void SeqList_Destroy(SeqList *list){
tSeqList *tList = NULL;
if (list == NULL) {
return;
}
tList = (tSeqList *) list;
if (tList->node != NULL) {
free(tList->node);
}
free(tList);
}
4.然後寫clear清空連結清單函數,但是不是銷毀free掉,而是讓連結清單長度回歸為0
//清空連結清單
void SeqList_Clear(SeqList *list){
tSeqList *tList = NULL;
if (list == NULL) {
return;
}
tList = (tSeqList *) list;
tList->length = 0;
}
5.然後求取連結清單長度
//求連結清單長度
int SeqList_Length(SeqList *list){
tSeqList *tList = NULL;
if (list == NULL) {
return 0;
}
tList = (tSeqList *) list;
return tList->length;
}
6.然後寫元素插入。
思路:
1.判斷線性表是否合法
2.判斷插入位置是否合法
3.把最後一個元素插入進去之後,要把後面的往後挪動一個機關
4.将新元素插入
5.線性表長度+1
元素插入分為兩個階段,第一個階段是元素的後移,第二個階段是給空出的位置進行指派
元素後移:一般的情況下都好說,要是後移之後超過capacity,要判斷length==capacity?或者甚至超過,如果超過立刻return一個提示消息,這是第一種元素後移的bug。第二種元素後移的bug就是,pos的位置,也就是插入位置比length還大,那我們就要進行容錯修正,這時就比較自由了,可以重新定義,或者寫一個容錯修正的算法。
int SeqList_Insert(SeqList *list,SeqListNode *node,int pos){
int ret = 0;
tSeqList *tList = NULL;
if (list == NULL || node == NULL || pos < 0) {
return ret;
}
tList = (tSeqList *) list;
//判斷插入元素是否滿了
if (tList->length == tList->capacity) {
printf("滿了");
}
// 容錯修正,pos>length
if (pos > tList->length) {
pos = tList->length;
}
//1.元素後移
int i = 0;
for (i = (*tList).length; i > pos; --i) {
tList->node[i] = (*tList).node[i - 1];
}
//2.插入元素
tList->node[i] = (unsigned int) node;
tList->length++;
}
7.擷取元素,擷取元素就比插入元素稍微好寫一點,要是也要對插入位置pos進行判斷。
SeqListNode *list_Get(SeqList *list , int pos){
int i = 0, ret = 0;
tSeqList *tList = NULL;
if (list == NULL || pos < 0) {
ret = -1;
return ret;
}
tList = (tSeqList *) list;
return tList->node[pos];
}
8.删除元素
假設我們删除掉第n個結點,首先我們要把這個結點的位置緩存出來,然後把後面的結點依次指派過來。
SeqListNode *list_Delete(SeqList *list,int pos){
SeqListNode *ret = 0;
tSeqList *tList = NULL;
if (list == NULL || pos < 0) {
printf("産生了錯誤");
return NULL;
}
tList = (tSeqList *) list;
ret = (SeqListNode *) tList->node[pos];
for (int i = pos+1; i <tList->length; ++i) {
tList->node[i - 1] = tList->node[i];
}
tList->length--;
return ret;
}
3.優點和缺點
優點:無需為線性表中的邏輯關系增加額外的空間,可以快速的擷取表中合法位置的元素
缺點:插入和删除需要移動大量的結點,當線性表長度較大的時候難以确定存儲空間的容量