第一个一千行总结-数据结构C复习--知识点总结1--一到四章
總結(jié)
第一章:
?
數(shù)據(jù)結(jié)構(gòu)包括:邏輯結(jié)構(gòu),儲(chǔ)存結(jié)構(gòu), 運(yùn)算集合
邏輯結(jié)構(gòu):分為線性(線性表, 棧, 隊(duì)列, 字符串, 數(shù)組, 廣義表)
?? ??? ?非線性:樹,圖,網(wǎng)
儲(chǔ)存結(jié)構(gòu):順序儲(chǔ)存和非順序儲(chǔ)存 線性儲(chǔ)存,散列儲(chǔ)存,鏈?zhǔn)絻?chǔ)存
算法+數(shù)據(jù)結(jié)構(gòu) = 程序
第二章:線性表:
線性表的線性儲(chǔ)存?
邏輯結(jié)構(gòu):?
除了端點(diǎn)以外,所有元素均有一個(gè)前驅(qū)和一個(gè)后繼.具有一對(duì)一的關(guān)系.
存儲(chǔ)結(jié)構(gòu):
一組地址連續(xù)的儲(chǔ)存單元依次存儲(chǔ)
#define MAX 100
typedef struct{
?? ?int elem[MAX];
?? ?int last;
}SeqList;
基本運(yùn)算:
?? ?
查找:?
按照坐標(biāo)查找和按照內(nèi)容查找?
插入:
判插入位置,判滿-->找到位置,移動(dòng)后面的元素-->插入!
刪除:
參數(shù):刪除的位置序號(hào)?
判位置-->將插入元素放到對(duì)應(yīng)變量中-->移動(dòng)元素
雙非遞減有序表合并:
元素比較插入-->單表剩余元素插入
2.3線性表的鏈?zhǔn)酱鎯?chǔ)
單鏈表: 設(shè)頭指針H指向第一個(gè)結(jié)點(diǎn),前驅(qū)結(jié)點(diǎn)指針域存放下一個(gè)結(jié)點(diǎn)的地址
為了方便,在第一個(gè)結(jié)點(diǎn)之前設(shè)立頭結(jié)點(diǎn),頭指針指向頭結(jié)點(diǎn),頭結(jié)點(diǎn)的指針域存儲(chǔ)指向第一個(gè)結(jié)點(diǎn)的指針
typedef struct Node{//Node為結(jié)構(gòu)標(biāo)記?
?? ?char data;
?? ?struct Node *next;
}Node, *LinkList; //Node為類型定義
注意:Node*和LinkList同為結(jié)構(gòu)指針, 兩者等價(jià).后者習(xí)慣指單鏈表頭指針變量,前者定義單鏈表中結(jié)點(diǎn)指針
Attention!!!!!!!
初始化:
InitList(LinkList *L){
?? ?//該處為雙指針, 返回值為空, 靠指針傳出去!!!
?? ?*L = (LinkList)malloc(szieof(Node));
?? ?(*L)->next = NULL;?
}?
//L指向單鏈表頭結(jié)點(diǎn)的指針,*L初始化單鏈表的頭指針變量
建立單鏈表://頭插法?
void CreateFromHead(LinkList L){
?? ?Node *s;
?? ?char c;
?? ?int flag = 1;
?? ?
?? ?while(flag){
?? ??? ?c = getchar();
?? ??? ?if(c != '$'){
?? ??? ??? ?s = (Node *)malloc(sizeof(Node));
?? ??? ??? ?s->data = c;
?? ??? ??? ?s->next = L->next;//L相當(dāng)于頭結(jié)點(diǎn)(表頭指針)
?? ??? ??? ?L->next = s;?
?? ??? ?}?
?? ??? ?else
?? ??? ??? ?flag = 0;
?? ?}
}
//尾插法
void CreateFromTail(LinkList L){
?? ?Node *s, *r;
?? ?char c;
?? ?int flag = 1;
?? ?
?? ?r = L;
?? ?while(flag){
?? ??? ?c = getchar();
?? ??? ?if(c != '$'){
?? ??? ??? ?s = (Node *)malloc(sizeof(Node));
?? ??? ??? ?s->data = c;
?? ??? ??? ?r->next = s;
?? ??? ??? ?r = s;?
?? ??? ?}?
?? ??? ?else{
?? ??? ??? ?flag = 0;
?? ??? ??? ?r->next = NULL;
?? ??? ?}
?? ?}
}
查找:
按照序號(hào)和按照值,和線性表差不多,判空條件改為while(p)
求長(zhǎng)度:...
單鏈表插入:
判斷插入位置合理性-->插入(一般都是頭插,類似語(yǔ)句如下:s->next = pre->next; pre->next = s)
刪除:
關(guān)鍵語(yǔ)句:r = pre->next;//賦值?
?? ??? ?pre->next = r->next;
?? ??? ?*e = r->data;
?? ??? ?free(r);//!!!
合并兩個(gè)有序單鏈表:
思想:不用新分配空間,直接比較數(shù)據(jù)修改指針,把其中的一個(gè)表頭當(dāng)作新表表頭...
LinkList MergeList(LinkList LA, LinkList LB){
?? ?LinkList LC;
?? ?Node *pa, *pb, *r;
?? ?
?? ?LC = LA;
?? ?pa = LA->next;
?? ?pb = LB->next;
?? ?r = LC;
?? ?
?? ?while(pa && pb){
?? ??? ?if(pa->data >= pb->data){
?? ??? ??? ?r->next = pa;
?? ??? ??? ?r = pa;
?? ??? ??? ?pa = pa->next;
?? ??? ?}
?? ??? ?else{
?? ??? ??? ?r->next = pb;
?? ??? ??? ?r = pb;
?? ??? ??? ?pb = pb->next;
?? ??? ?}
?? ?}
?? ?if(pa)
?? ??? ?r->next = pa;
?? ?else
?? ??? ?r->next = pb;
?? ?
?? ?r->next = NULL;
?? ?free(r);
?? ?free(LB);
?? ?return(LC); //return LC;
}?
循環(huán)鏈表:將單鏈表最后一個(gè)結(jié)點(diǎn)指針域NULL改為指向表頭結(jié)點(diǎn)
單循環(huán)鏈表判斷條件: p != L或 p->next != NULL;
初始化循環(huán)單鏈表:
InitCLinkList(LinkList *CL){
?? ?*CL = (LinkList)malloc(sizeof(Node));
?? ?(*CL)->next = *CL;//注意CL是指針(地址), *CL為結(jié)點(diǎn),(或者說(shuō)結(jié)點(diǎn)指針, 就是一般的結(jié)點(diǎn))!!!!!!!!!!!!?
}?
Attention!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
建立循環(huán)單鏈表:易錯(cuò)?
void CreateCLinkList(LinkList CL){
?? ?//尾插法
?? ?Node *rear, *s;
?? ?char c;
?? ?
?? ?rear = CL; //典型步驟
?? ?c = getchar();
?? ?
?? ?while(c != '$'){
?? ??? ?s = (Node *)malloc(sizeof(Node));
?? ??? ?s->data = c;
?? ??? ?rear->next = s;
?? ??? ?rear = s;//典型
?? ??? ?c = getchar();//!!別忘記了?
?? ?}?
?? ?rear->next = CL;//?
}?
循環(huán)單鏈表合并:
LinkList Merge(LinkList LA, LinkList LB){
?? ?Node *p, *q;//帶頭結(jié)點(diǎn)
?? ?
?? ?p = LA;
?? ?q = LB;
?? ?
?? ?while(p->next != LA) p = p->next;
?? ?while(q->next != LB) q = q->next;
?? ?
?? ?p->next = LB->next;
?? ?q->next = LA;
?? ?
?? ?free(LB);
?? ?return LA;?
}
//稍難,帶尾指針的帶頭結(jié)點(diǎn)循環(huán)內(nèi)單鏈表合并算法
LinkList Merge_2(LinkList LA, LinkList LB){
?? ?//LA LB為尾指針,所以LA->next and LB->next 為頭結(jié)點(diǎn)
?? ?Node *p;
?? ?
?? ?p = LA->next;//p暫時(shí)保存LA頭結(jié)點(diǎn)地址
?? ?LA->next = LB->next->next;//指向LB第一個(gè)結(jié)點(diǎn)
?? ?free(LB->next);
?? ?LB->next = p;
?? ?
?? ?return LB;//返回新的循環(huán)鏈表的尾指針?
}?
LinkList Merge_2(LinkList A, LinkList B){
?? ?Node *q;
?? ?
?? ?q = B->next;
?? ?B->next = A->next->next;
?? ?free(A->next);
?? ?A->next = q;
?? ?
?? ?return A;?
}?
雙向鏈表:
typedef struct DNode{
?? ?int data;
?? ?struct DNode *prior, *next;
}DNode, *DoubleList;
插入:
//需要改變四個(gè)指針
int DLinkInsert(DoubleList L, int i, int e){
?? ?
?? ?DNode *s, *p;
?? ?
?? ?//判斷插入位置是否合法
?? ?p = L;
?? ?for(; i > 0 && p; i--)
?? ??? ?p = p->next;
?? ?//p最終指向待插入位置
?? ?if(!p) return FALSE;
?? ??
?? ?s = (DNode *)malloc(sizeof(DNode));
?? ?s->data = e;
?? ?
?? ?s->prior = p->prior;
?? ?p->prior->next = s;
?? ?s->next = p;
?? ?p->prior = s;
?? ?
?? ?return OK;?
}?
刪除相似:
判斷插入位置-->找到刪除節(jié)點(diǎn)->刪除數(shù)據(jù)存入指針變量->改變指針->返回TRUE
關(guān)鍵步驟:
*e = p->data;
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
靜態(tài)鏈表:相比于動(dòng)態(tài)鏈表(借助函數(shù)malloc和free),定義較大的結(jié)構(gòu)數(shù)組,存放data和游標(biāo)cursor
多次插入和刪除造成鏈表假滿,原因是未對(duì)刪除元素空間進(jìn)行回收.將所有刪除和未分配的結(jié)點(diǎn)空間
通過(guò)游標(biāo)鏈形成空閑結(jié)點(diǎn)鏈表...
線性表的應(yīng)用:
?? ?
一元多項(xiàng)式的表示及相加
typedef struct Polynode{
?? ?int coef;//系數(shù)
?? ?int exp;//指數(shù)
?? ?struct Polynode *next;?
}Polynode, *Polylist;?
尾插法建立:...
相加運(yùn)算:
void Polyadd(Polylist polya, Polylist polyb){
?? ?Polynode *p, *q, *tail, *temp;
?? ?int sum;
?? ?
?? ?p = polya->next;
?? ?q = polyb->next;//p,q分別指向第一個(gè)結(jié)點(diǎn);
?? ?tail = p;
?? ?
?? ?while(p && q){
?? ??? ?if(p->exp < q->exp){
?? ??? ??? ?//尾插
?? ??? ??? ?tail->next = p;
?? ??? ??? ?tail = p;
?? ??? ??? ?p = p->next;?
?? ??? ?}
?? ??? ?else if(p->exp > q->exp){
?? ??? ??? ?tail->next = q;
?? ??? ??? ?tail = q;
?? ??? ??? ?q = q->next;
?? ??? ?}
?? ??? ?else{
?? ??? ??? ?//指數(shù)相等,判斷系數(shù)之和是否為零
?? ??? ??? ?//為零,分別走下一個(gè)結(jié)點(diǎn),同時(shí)釋放p,q;不為零, ....
?? ??? ??? ?sum = p->coef + q->coef;
?? ??? ??? ?if(sum){
?? ??? ??? ??? ?p->sum = sum;
?? ??? ??? ??? ?tail->next = p;
?? ??? ??? ??? ?tail = p;
?? ??? ??? ??? ?p = p->next;
?? ??? ??? ??? ??
?? ??? ??? ??? ?temp = q;
?? ??? ??? ??? ?q = q->next;
?? ??? ??? ??? ?free(temp);
?? ??? ??? ?}?
?? ??? ??? ?else{
?? ??? ??? ??? ?temp = p;
?? ??? ??? ??? ?p = p->next;
?? ??? ??? ??? ?free(temp);
?? ??? ??? ??? ?
?? ??? ??? ??? ?temp = q;
?? ??? ??? ??? ?q = q->next;
?? ??? ??? ??? ?free(q);
?? ??? ??? ?}
?? ??? ?}
?? ?}?
?? ?//值得注意的是,也許其中一個(gè)鏈表數(shù)據(jù)并沒(méi)有走完
?? ?if(p)
?? ??? ?tail->next = p;
?? ?else
?? ??? ?tail->next = q;?
}?
經(jīng)典算法:
?? ?
刪除順序表中所有值為x的元素,時(shí)間復(fù)雜度盡可能小
思想:避免直接掃描-->刪除-->移動(dòng)...
在原來(lái)表的基礎(chǔ)上構(gòu)造新表,方法:若是不等于x,那么直接復(fù)制到新表;等于就跳過(guò).注意的是新表不用另外聲明.?
單鏈表第一個(gè)存儲(chǔ)元素的值劃分單鏈表為兩半, 小于放該元素前面,大于相反
//默認(rèn)有頭結(jié)點(diǎn)?
void divide_2(LinkList L){
?? ?if(!L->next) return;
?? ?
?? ?Node *p, *q, *pre, *s;
?? ?
?? ?s = L->next;//r指向劃分結(jié)點(diǎn)
?? ?pre = s;
?? ?p = s->next;
?? ?
?? ?while(p){
?? ?//p!=NULL
?? ?q = p->next;//指針跟蹤技術(shù)
?? ?if(p->data < s->data){
?? ??? ?//頭插,利用pre的指針跟蹤
?? ??? ?pre->next = p->next;//pre后繼連接到q
?? ??? ?//頭插?
?? ??? ?p->next = L->next;
?? ??? ?L->next = p;
?? ??? ?
?? ??? ?p = q;?
?? ?}?
}?
第二章總結(jié):
存儲(chǔ)密度:順序表為百分百,鏈表會(huì)低很多
優(yōu)缺點(diǎn):順序表為隨機(jī)存儲(chǔ),單鏈表需要從頭查找.插入刪除少就順序表
線性鏈表分為:
?? ?帶頭結(jié)點(diǎn)的單鏈表!!!很重要!:特點(diǎn)只能從前往往后尋找
?? ?帶頭結(jié)點(diǎn)的循環(huán)單鏈表:尋找一個(gè)結(jié)點(diǎn)的前驅(qū)時(shí)間耗費(fèi)O(n);
?? ?帶尾指針的循環(huán)單鏈表:尋找尾結(jié)點(diǎn)和頭結(jié)點(diǎn)方便
?? ?帶頭結(jié)點(diǎn)的雙向循環(huán)鏈表:前驅(qū)和后繼都好找但是儲(chǔ)存密度相對(duì)較低.?
?? ?
第三章 限定性線性表--棧和隊(duì)列!必考!!!
?
棧:單向插入和刪除,叫做入棧和出棧 ?后進(jìn)先出的特點(diǎn)
定義;
typedef struct {
?? ?int elem[MAX];
?? ?int top;//空為-1?
}SeqStack;//順序棧
初始化:棧頂置為-1
進(jìn)棧:判滿-->棧頂++ ->進(jìn)棧
出棧:判空-->棧底-- ->出棧?
!!
//判空
bool IsEmpty(SeqStack *S){
?? ?if(S->top == -1)
?? ??? ?return true;
?? ?else
?? ??? ?return false;
}?
//出棧
int Pop(SeqStack *S, int *e){
?? ?if(IsEmpty(S))
?? ??? ?return -1;
?? ?
?? ?*e = S->elem[S->top];
?? ?S->top--;
?? ?return 1;
}?
多棧共享技術(shù):雙端棧,棧底分別為兩端,判滿:S->top[0] + 1 == S->top[1];判空: S->top[0] == 0,S->top[1] == MAX-1;
鏈棧:
定義:
typedef struct node{
?? ?int data;
?? ?struct node *next;
}LinkStackNode;
typedef LinkStackNode* LinkStack
//進(jìn)棧:top為頭結(jié)點(diǎn)?
int Push(LinkStack top, int x){
?? ?LinkStackNode *temp;
?? ?temp = (LinkStackNode *)malloc(sizeof(LinkStackNode));
?? ?if(temp == NULL){
?? ??? ?printf("申請(qǐng)空間失敗\n");
?? ??? ?return FALSE;
?? ?}
?? ?temp->next = x;
?? ?temp->next = top->next;
?? ?top->next = temp;
?? ?return TRUE;
}?
//出棧
int Pop(LinkStack top,int *x){
?? ?LinkStackNode *temp;
?? ?temp = top->next;
?? ?if(temp == NULL){
?? ??? ?return FALSE;
?? ?}
?? ?top->next = temp->next;
?? ?*x = temp->data;
?? ?free(temp);
?? ?return TRUE;
}?
//多棧運(yùn)算 略?
#define N 10
typedef struct node{
?? ?int data;
?? ?struct node *next;
}LinkStackNode, *LinkStack;?
LinkStack top[N];
//top[i]分別是十個(gè)棧中每個(gè)棧的棧頂 ?
//括號(hào)匹配?
void BracketMatch(char *str){
?? ?Stack S;
?? ?int i;
?? ?char ch;
?? ?//初始化
?? ?InitStack(&S);
?? ?for(i = 0; str[i] != '\0'; i++){
?? ??? ?switch(str[i]){
?? ??? ??? ?case '[':
?? ??? ??? ?case '{':
?? ??? ??? ?case '(':
?? ??? ??? ??? ?Push(&S, str[i]);
?? ??? ??? ??? ?break;
?? ??? ??? ?case ')':
?? ??? ??? ?case ']':
?? ??? ??? ?case '}':
?? ??? ??? ??? ?if(IsEmpty(&S)){
?? ??? ??? ??? ??? ?printf("右括號(hào)多余!\n");
?? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ?}?? ?
?? ??? ??? ??? ?else{
?? ??? ??? ??? ??? ?GetTop(&S, &ch);
?? ??? ??? ??? ??? ?if(Match(ch, str[i])){
?? ??? ??? ??? ??? ??? ?Pop(&S, &ch);
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?else{
?? ??? ??? ??? ??? ??? ?printf("括號(hào)不匹配\n");
?? ??? ??? ??? ??? ??? ?return;
?? ??? ??? ??? ??? ?}
?? ??? ?}
?? ??? ?}
?? ?}?
?? ?if(IsEmpty(&S)){
?? ??? ?printf("括號(hào)匹配成功!\n");
?? ??? ?return;
?? ?}
?? ?else
?? ??? ?printf("左括號(hào)多余\n");
}?
//表達(dá)式求值 略?
int ExpEvaluation(){
?? ?InitStack(&OPTR);//運(yùn)算符棧?
?? ?InitStack(&OVS);//運(yùn)算數(shù)棧?
?? ?Push(&OPTR, '#');
?? ?printf("\n\nPlease enter an expression(End with '#'):");
?? ?ch = getchar();
?? ?
?? ?while(ch == '#' || GetTop(OPTR)!='#'){
?? ??? ?if(!In(ch, OPSet)){
?? ??? ??? ?n = GetNumber(ch);
?? ??? ??? ?Push(&OVS, n);
?? ??? ??? ?ch = getchar();
?? ??? ?}
?? ??? ?else{
?? ??? ??? ?switch(Compare(ch, GetTop(OTPR))){
?? ??? ??? ??? ?case '>':Push(&OPTR, ch);
?? ??? ??? ??? ??? ?ch = getchar();
?? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ?case '=':
?? ??? ??? ??? ?case '<':
?? ??? ??? ??? ??? ?Pop(&OPTR, &op);
?? ??? ??? ??? ??? ?Pop(&OVS, &a);
?? ??? ??? ??? ??? ?Pop(&OVS, &b);
?? ??? ??? ??? ??? ?v = Execute(a, op, b);
?? ??? ??? ??? ??? ?Push(&OVS, v);
?? ??? ??? ??? ??? ?break;
?? ??? ??? ?}
?? ??? ?}
?? ?}
?? ?v = GetTop(OVS);
?? ?return (v);
}?
棧與遞歸:
常見:斐波那契數(shù)列, 漢諾塔問(wèn)題, 階乘...
階乘遞歸:
int f(int n){
?? ?if(n == 0)?
?? ??? ?return 1;
?? ?else
?? ??? ?return n * f(n-1);
}?
斐波那契:
Fib(int n){
?? ?if(n == 0 || n == 1)
?? ??? ?return n;
?? ?else
?? ??? ?return Fib(n-1) + Fib(n-2);
}?
隊(duì)列:一端進(jìn)去,另一端出來(lái) 先進(jìn)先出.
!!!插入一端為隊(duì)尾, 出去一端為隊(duì)頭,所以插入用尾插!!!!!!!!!!!!!!!!!!!!!!!!!!
鏈隊(duì)列:
定義:
typedef struct Node{
?? ?int data;
?? ?struct Node *next;
}LQNode;
typedef struct{
?? ?LQNode *front;
?? ?LQNode *rear;
}LQ;//LinkQueue
初始化:
int InitQueue(LQ *Q){
?? ?Q->front = (LQNode *)malloc(sizeof(Node));
?? ?
?? ?if(Q->front){
?? ??? ?Q->rear = Q->front;
?? ??? ?Q->front->next = NULL;
?? ??? ?return 1;?
?? ?}
?? ?return -1;
}?
入隊(duì)://這個(gè)不太好理解,需要畫圖?
int EnterQueue(LQ *Q, int x){
?? ?LQNode *new_node;
?? ?
?? ?new_node = (LQNode *)malloc(sizeof(LQNode));
?? ?if(!new_node) return -1;
?? ?
?? ?new_node->data = x;
?? ?new_node->next = NULL;
?? ?Q->rear->next = new_node;//尾插?
?? ?Q->rear = new_node;
?? ?
?? ?return 1;?
}?
循環(huán)隊(duì)列:....
//輾轉(zhuǎn)相除法和排隊(duì)等待問(wèn)題?
int fun(int m, int n){
?? ?int r;
?? ?if(n > m){
?? ??? ?return fun(n, m);
?? ??? ?//相與交換位置?
?? ??? ?//多次輾轉(zhuǎn)相除找出最大公約數(shù)?
?? ?}
?? ?else if(n == 0){
?? ??? ?return m;
?? ?}
?? ?else{
?? ??? ?r = m % n;
?? ??? ?return (fun(n, r));
?? ?}
}
int fun(int m, int n){
?? ?int r;
?? ?
?? ?do{
?? ??? ?r = m % n//分母較大就相當(dāng)于執(zhí)行交換值的操作;
?? ??? ?m = n;
?? ??? ?n = r;
?? ?}while(r != 0);
?? ?return m;
}
void seedoctor(){
?? ?InitQueue(&Q);
?? ?flag = 1;
?? ?while(flag){
?? ??? ?printf("Please enter the code:");
?? ??? ?ch = getch();
?? ??? ?switch(ch){
?? ??? ??? ?case 'a':
?? ??? ??? ??? ?printf("\n病歷號(hào):");
?? ??? ??? ??? ?scanf("%d", &n);
?? ??? ??? ??? ?EnterQueue(&Q, n);
?? ??? ??? ??? ?break;
?? ??? ??? ?case 'n':
?? ??? ??? ??? ?if(IsEmpty){
?? ??? ??? ??? ??? ?DeleteQueue(&Q, &n);
?? ??? ??? ??? ??? ?printf("病歷號(hào)為%d號(hào)的就診\n", n);
?? ??? ??? ??? ?}?
?? ??? ??? ??? ?else?
?? ??? ??? ??? ??? ?printf("無(wú)病人等待");?
?? ??? ??? ??? ?break
?? ??? ??? ?case 'q':
?? ??? ??? ??? ?printf("今天停止掛號(hào), 以下病人依次就診.");
?? ??? ??? ??? ?while(!IsEmpty){
?? ??? ??? ??? ??? ?DeleteQueue(&Q, &n);
?? ??? ??? ??? ??? ?printf("%d ? ?\n", n);
?? ??? ??? ??? ?}
?? ??? ??? ??? ?flag = 0;
?? ??? ??? ??? ?break;
?? ??? ??? ?default:
?? ??? ??? ??? ?printf("輸入錯(cuò)誤.\n");?
?? ??? ?}
?? ?}
} ?
第三章總結(jié):
棧:先進(jìn)后出; 順序棧可能產(chǎn)生上溢,鏈棧不會(huì).?
隊(duì)列:先進(jìn)先出; 鏈隊(duì)列設(shè)頭指針和尾指針,封裝在一個(gè)結(jié)構(gòu)體里面.
第四章:串
字符串:雙引號(hào)括起來(lái).....空串:就是一對(duì)引號(hào)
定長(zhǎng)順序串:靜態(tài)結(jié)構(gòu), 地址連續(xù)存儲(chǔ)單元存儲(chǔ)字符串序列
定義:
typedef struct{
?? ?char ch[MAX];
?? ?int len;
}SString;
插入:插入位置position會(huì)將已經(jīng)有的串L分為兩個(gè)部分i,j,新插入的串s會(huì)導(dǎo)致以下三種情況
1. 插入后仍然長(zhǎng)度小于MAX
2. 插入后j串溢出一部分
3. 插入后j串全部溢出, s溢出一部分
int SStringInsert(SString *s, int pos, SString t){
?? ?int i;
?? ?//判插入位置合理性?
?? ?if(pos < 0 || pos > s->len) return -1;
?? ?
?? ?//第一種情況, 先將后串后移,再插入
?? ?if(s->len + t.len <= MAX){//注意的是一個(gè)是類似字符串指針, 一個(gè)用點(diǎn)運(yùn)算符
?? ??? ?//后移
?? ??? ?for(i = pos + t.len; i < t.len + s->len; i++)
?? ??? ??? ?s[i] = s[i-t.len];
?? ??? ?//復(fù)制?
?? ??? ?for(i = pos; i < pos + t.len; i++)
?? ??? ??? ?s[i] = t.ch[i-pos];
?? ??? ?s->len += t.len;?
?? ?}
?? ?else if(pos + t.len <= MAX){
?? ??? ?for(i = MAX - 1; i > pos; i--)
?? ??? ??? ?s[i] = s[i - t.len];
?? ??? ?
?? ??? ?for(i = pos; i < pos + t.len; i++)
?? ??? ??? ?s[i] = t.ch[i-pos];
?? ??? ?s->len = MAX - 1;
?? ?}?
?? ?else{
?? ??? ?for(i = pos; i < MAX; i++)
?? ??? ??? ?s[i] = t.ch[i-pos];
?? ??? ?s->len = MAX - 1;?
?? ?}
?? ?return 1;//#define OK 1; return OK;
}?
//Delete
int StrDelete(SString *s, int pos, int len){
?? ?//從串中刪除從pos位置起的len長(zhǎng)度的字符
?? ?int i;
?? ?
?? ?if(pos < 0 ||pos > (s->len-len)) return 0;
?? ?
?? ?for(i = pos + len; i < s->len; i++)
?? ??? ?s->ch[i-len] = s->ch[i];
?? ??? ?
?? ?s->len -= len;
?? ?
?? ?return 1;?
}
串比較?
//Compare
int StrCompare(SString s, SString t){
?? ?int i=0;
?? ?for(i = 0; i< s.len && i < t.len; i++)
?? ??? ?if(s.ch[i] != t.ch[i])
?? ??? ??? ?return (s.ch[i] - t.ch[i]);
?? ?return s->len-t.len;//注意返回值
?? ?//如果前者大于后者, 第一個(gè)return返回正;后者大, 返回負(fù)數(shù)
?? ?//前面能夠完全匹配, 那么第二個(gè)return比較字符串長(zhǎng)度?
}?
最基礎(chǔ)的BF算法?
//定位函數(shù)(布魯特-福斯算法)
int StrIndex(SString s,int pos, SString t){
?? ?int i, j ,start;
?? ?//對(duì)s字符串一輪一輪的從pos字符開始和t字符串比較, 比較不成功則start向后移
?? ?start = pos;
?? ?i = start;
?? ?j = 0;
?? ?while(i < s.len && j <t.len){
?? ??? ?if(s.ch[i] == t.ch[j]){
?? ??? ??? ?i++;
?? ??? ??? ?j++;
?? ??? ?}
?? ??? ?else{
?? ??? ??? ?start++;
?? ??? ??? ?i = start;
?? ??? ??? ?j = 0;?
?? ??? ?}
?? ?}
?? ?if(j >= t.len) return start;
?? ?else return -1;?
}?
堆串:
定義:?
typedef struct{
?? ?char *ch;
?? ?int len;
}HString;
存儲(chǔ)方式有效率, 但是程序執(zhí)行過(guò)程中會(huì)不斷的銷毀和生成新串!!!
//插入?
int StrInsert(HString *s, int pos, HString *t){
?? ?int i;
?? ?char *p;
?? ?
?? ?if(pos < 0 || pos > s->len || s->len == 0) return 0;
?? ?//為新串分配空間?
?? ?p = (char *)malloc(sizeof(s->len + t->len));
?? ?if(!p) return 0;
?? ?//舊的前部分復(fù)制到新?
?? ?for(i = 0; i < pos; i++)
?? ??? ?p[i] = s->ch[i];
?? ?//復(fù)制t?
?? ?for(i = pos; i< pos +t->len; i++)
?? ??? ?p[i] = t->ch[i-pos];
?? ?//復(fù)制舊的串后部分?
?? ?for(i = pos; i<s->len;i++ )
?? ??? ?p[i+s->len] = s->ch[i];
?? ??? ?
?? ?s->len += t->len;
?? ?
?? ?!!!!!!!!!!!!!!!!!!!!!!!!!下一步!!!!!!!!!!!!!!!!!!!!
?? ?字符串指針直接復(fù)制, 不是普通數(shù)組不用strcpy()?
?? ?s->ch = p;
?? ?
?? ?return 1;
}
//賦值
int StrAssign(HString *s, char *tval){
?? ?int len, i = 0;
?? ?if(s->len == 0)return 0;
?? ?while(tval[i] != '\0') i++;
?? ?//得到tval字符串的長(zhǎng)度
?? ?len = i;
?? ?if(len){
?? ??? ?s->ch = (char *)malloc(sizeof(len));
?? ??? ?if(!s->ch) return 0;
?? ??? ?for(i = 0; i< len; i++)
?? ??? ??? ?s->ch[i] = tval[i];
?? ??? ?s->len = len;
?? ??? ?return 1;
?? ?}?
?? ?else
?? ??? ?s->ch = NULL;
?? ??? ?return 1;
}?
//塊鏈串
#define MAX 4
typedef struct Block{
?? ?char ch[MAX];//data域, 結(jié)點(diǎn)大小, 指的是存放字符的個(gè)數(shù)?
?? ?struct Block *next;//鏈域, 指的是link域占用字符個(gè)數(shù)?
}Block;?
//儲(chǔ)存密度 data占用存儲(chǔ)位/實(shí)際為串分配存儲(chǔ)位 存儲(chǔ)密度越小運(yùn)算處理越方便
//MAX == 1時(shí), 就是一個(gè)普通的線性鏈表?
typedef struct{
?? ?Block *head;
?? ?Block *tail;
?? ?int len;
}BLString;
icoding例題改編測(cè)試!!!!
#include <stdlib.h>
#include <stdio.h>
#define BLOCK_SIZE 4 ? ?
#define BLS_BLANK '#' ? // 用于空白處的補(bǔ)齊字符!!!!!!!
typedef struct _block {
? ? char ch[BLOCK_SIZE]; ? ?//塊的數(shù)據(jù)域
? ? struct _block *next; ? ?//塊的指針域
} Block;
typedef struct {
? ? Block *head; ? ? ? ?// 串的頭指針
? ? Block *tail; ? ? ? ?// 串的尾指針
? ? int len; ? ? ? ? ? ?// 串的當(dāng)前長(zhǎng)度
} BLString;
//字符串初始化函數(shù):
void blstr_init(BLString *T) {
? ? T->len = 0;
? ? T->head = NULL;
? ? T->tail = NULL;
}
//這些定義已包含在頭文件 dsstring.h 中,請(qǐng)實(shí)現(xiàn)塊鏈串的子串查找操作:
//
//bool blstr_substr(BLString src, int pos, int len, BLString *sub);
//src為要查找的字符串
//pos為子串開始的下標(biāo)
//len為子串的長(zhǎng)度
//sub在函數(shù)調(diào)用運(yùn)行前指向一個(gè)已經(jīng)初始化好的空串,在函數(shù)返回時(shí),sub指向串src從第pos個(gè)字符起長(zhǎng)度為len的子串
//函數(shù)查找成功返回true,參數(shù)不正確返回 false
#include "dsstring.h"
#include <stdio.h>
#include <stdlib.h>
//函數(shù)聲明:長(zhǎng)度判斷很多寫法,大多數(shù)不同的編譯器都會(huì)各種報(bào)錯(cuò),這種不是最簡(jiǎn)便的但是一般不會(huì)報(bào)錯(cuò)?
int len(const char* s)
{
? ? int q = 0;
? ? while (*s != '\0') {//while(*s)
? ? ? ? q++;
? ? ? ? s++;
? ? }
? ? return q;
}
int StrAssign(BLString* S, const char* cstr)
{
?? ?//將串cstr存入S中去, S是塊鏈串?
? ? int i, j, k, len;
? ? Block *p, *q;
? ??
? ? len = strlen(cstr); /*len為鏈串的長(zhǎng)度 */
? ? if (len == 0)
? ? ? ? return 0;
? ? ? ??
? ? S->len = len;
? ? //整除哈!! ?8 / 5 = 1
? ? j = len / BLOCK_SIZE; /*j為鏈串的結(jié)點(diǎn)數(shù) */
? ? if (len % BLOCK_SIZE)
? ? ? ? j++;
? ? ? ??
? ? for (i = 0; i < j; i++) {
? ? ? ? p = (Block*)malloc(sizeof(Block)); /*動(dòng)態(tài)生成一個(gè)結(jié)點(diǎn)*/
? ? ? ? if (!p)
? ? ? ? ? ? return 0;
? ? ? ? ? ??
? ? ? ? //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!字符串重點(diǎn)?
? ? ? ? for (k = 0; k < BLOCK_SIZE && *cstr; k++) /*將字符串ctrs中的字符賦值給鏈串的數(shù)據(jù)域*/
? ? ? ? ? ? *(p->ch + k) = *cstr++;//p->ch[k] = cstr[xxx]?
? ? ? ??
? ? ? ? //指針跟蹤?
? ? ? ? if (i == 0) /*如果是第一個(gè)結(jié)點(diǎn)*/
? ? ? ? ? ? S->head = q = p; /*頭指針指向第一個(gè)結(jié)點(diǎn)*/
? ? ? ? else {//尾插,q為尾結(jié)點(diǎn)?
? ? ? ? ? ? q->next = p;
? ? ? ? ? ? q = p;
? ? ? ? }
? ? ? ? if (!*cstr) /*如果是最后一個(gè)鏈結(jié)點(diǎn)*/
? ? ? ? {
? ? ? ? ? ? S->tail = q; /*將尾指針指向最后一個(gè)結(jié)點(diǎn)*/
? ? ? ? ? ? q->next = NULL; /*將尾指針的指針域置為空*/
? ? ? ? ? ? for (; k < BLOCK_SIZE; k++) /*將最后一個(gè)結(jié)點(diǎn)用'#'填充*/
? ? ? ? ? ? ? ? *(q->ch + k) = BLS_BLANK;
? ? ? ? }
? ? }
? ? return 1;
}
bool blstr_substr(BLString src, int pos, int len, BLString* sub)
{
? ? char* t;
? ? if (pos < 0 || pos >= src.len || len < 1)
? ? ? ? return false;
? ? int n = pos / BLOCK_SIZE, h = pos % BLOCK_SIZE;
? ? Block* temp = src.head;
? ? for (int i = 0; i < n; i++) //假裝到初始節(jié)點(diǎn)
? ? {
? ? ? ? temp = temp->next;
? ? }
? ? char str[100];
? ? int i = 0;
? ? while (i < len) {
? ? ? ? if (h >= BLOCK_SIZE) {
? ? ? ? ? ? temp = temp->next;
? ? ? ? ? ? h = 0;
? ? ? ? } else {
? ? ? ? ? ? if (!temp || temp->ch[h] == BLS_BLANK)
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? str[i++] = temp->ch[h++];
? ? ? ? }
? ? }
? ? str[i] = '\0';
? ? StrAssign(sub, str);
? ? return true;
}
//算法BF and KMP?
略過(guò)........?
//BF 回溯算法
int StrIndex(SString s, int pos, SString t){
?? ?int i, j;
?? ?if(t.len == 0)
?? ??? ?return (0);//空串任意串的字串
?? ??? ?
?? ?i = pos;
?? ?j = 0;
?? ?
?? ?while(i < s.len && j < t.len){
?? ??? ?if(s[i] == t[j]){
?? ??? ??? ?i++; j++;
?? ??? ?}
?? ??? ?else{
?? ??? ??? ?i = i-j+1; //關(guān)鍵?
?? ??? ??? ?j = 0;
?? ??? ?}
?? ?}
?? ?if(j >= t.len)
?? ??? ?return (i-j);
?? ?else
?? ??? ?return -1;?
}
//KMP
//next
void GetNext(SString t, int next[]){
?? ?int j, k;
?? ?j = 0;
?? ?k = -1;
?? ?next[0] = -1;
?? ?while(j < t.len-1){
?? ??? ?if(k == -1|| t.data[j] == t.data[k]){
?? ??? ??? ?j++;k++; next[j] = k;
?? ??? ?}
?? ??? ?else{
?? ??? ??? ?k = next[k];
?? ??? ?}
?? ?}
}
//KMP
int StrIndex_KMP(SString s, int pos, SString t, int next[]){
?? ?int i, j;
?? ?if(t.len == 0) return 0;
?? ?i = pos;
?? ?j = 0;
?? ?while(i<s.len && j<t.len){
?? ??? ?if(j == -1 || t.data[i] == s.data[j]){
?? ??? ??? ?i++;j++;
?? ??? ?}
?? ??? ?else
?? ??? ??? ? j = next[j];
?? ??? ?
?? ?}
?? ?if(j>=t.len)
?? ??? ?return i-t.len;
?? ?else
?? ??? ?return -1;?
}
第四章總結(jié):
字符串是特殊的線性表, 元素為字符.
區(qū)分:定長(zhǎng)順序串(靜態(tài)儲(chǔ)存),堆串(多次分配銷毀),塊鏈串(鏈表)
?
總結(jié)
以上是生活随笔為你收集整理的第一个一千行总结-数据结构C复习--知识点总结1--一到四章的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 什么是人造肛门
- 下一篇: 数组合并假设有 n 个长度为 k 的已排